diff --git a/modules/flowable-http-common/src/main/java/org/flowable/http/common/api/HttpResponseVariableType.java b/modules/flowable-http-common/src/main/java/org/flowable/http/common/api/HttpResponseVariableType.java new file mode 100644 index 00000000000..df2c1aaa89a --- /dev/null +++ b/modules/flowable-http-common/src/main/java/org/flowable/http/common/api/HttpResponseVariableType.java @@ -0,0 +1,22 @@ +/* Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.flowable.http.common.api; + +public enum HttpResponseVariableType { + + AUTO, + STRING, + JSON, + BASE64, + BYTES +} diff --git a/modules/flowable-http-common/src/main/java/org/flowable/http/common/impl/BaseHttpActivityDelegate.java b/modules/flowable-http-common/src/main/java/org/flowable/http/common/impl/BaseHttpActivityDelegate.java index f05b349d214..da7fc7f7863 100644 --- a/modules/flowable-http-common/src/main/java/org/flowable/http/common/impl/BaseHttpActivityDelegate.java +++ b/modules/flowable-http-common/src/main/java/org/flowable/http/common/impl/BaseHttpActivityDelegate.java @@ -13,6 +13,9 @@ package org.flowable.http.common.impl; import java.io.IOException; +import java.util.Base64; +import java.util.List; +import java.util.Locale; import java.util.Set; import java.util.concurrent.CompletableFuture; @@ -25,12 +28,15 @@ import org.flowable.http.common.api.HttpHeaders; import org.flowable.http.common.api.HttpRequest; import org.flowable.http.common.api.HttpResponse; +import org.flowable.http.common.api.HttpResponseVariableType; import org.flowable.http.common.api.client.AsyncExecutableHttpRequest; import org.flowable.http.common.api.client.ExecutableHttpRequest; import org.flowable.http.common.api.client.FlowableHttpClient; +import com.fasterxml.jackson.core.JsonProcessingException; import com.fasterxml.jackson.databind.ObjectMapper; import com.fasterxml.jackson.databind.node.MissingNode; +import com.fasterxml.jackson.databind.node.NullNode; /** * @author Filip Hrisafov @@ -72,8 +78,14 @@ public abstract class BaseHttpActivityDelegate { protected Expression responseVariableName; // Flag to save the response variables as a transient variable. Default is false (Optional). protected Expression saveResponseParametersTransient; + /** + * @deprecated use {@link #responseVariableType} instead + */ // Flag to save the response variable as an ObjectNode instead of a String + @Deprecated protected Expression saveResponseVariableAsJson; + + protected Expression responseVariableType; // Prefix for the execution variable names (Optional) protected Expression resultVariablePrefix; @@ -105,7 +117,7 @@ protected RequestData createRequest(VariableContainer variableContainer, String requestData.setSaveRequest(ExpressionUtils.getBooleanFromField(saveRequestVariables, variableContainer)); requestData.setSaveResponse(ExpressionUtils.getBooleanFromField(saveResponseParameters, variableContainer)); requestData.setSaveResponseTransient(ExpressionUtils.getBooleanFromField(saveResponseParametersTransient, variableContainer)); - requestData.setSaveResponseAsJson(ExpressionUtils.getBooleanFromField(saveResponseVariableAsJson, variableContainer)); + requestData.setResponseVariableType(determineResponseVariableType(variableContainer)); requestData.setPrefix(ExpressionUtils.getStringFromField(resultVariablePrefix, variableContainer)); String failCodes = ExpressionUtils.getStringFromField(failStatusCodes, variableContainer); @@ -163,10 +175,8 @@ protected void saveResponseFields(VariableContainer variableContainer, RequestDa if (!response.isBodyResponseHandled()) { String responseVariableName = ExpressionUtils.getStringFromField(this.responseVariableName, variableContainer); String varName = StringUtils.isNotEmpty(responseVariableName) ? responseVariableName : request.getPrefix() + "ResponseBody"; - Object varValue = request.isSaveResponseAsJson() && response.getBody() != null ? objectMapper.readTree(response.getBody()) : response.getBody(); - if (varValue instanceof MissingNode) { - varValue = null; - } + Object varValue = determineResponseVariableValue(request, response, objectMapper); + if (request.isSaveResponseTransient()) { variableContainer.setTransientVariable(varName, varValue); } else { @@ -205,6 +215,101 @@ protected void saveResponseFields(VariableContainer variableContainer, RequestDa } } + protected Object determineResponseVariableValue(RequestData request, HttpResponse response, ObjectMapper objectMapper) throws IOException { + HttpResponseVariableType responseVariableType = request.getResponseVariableType(); + String contentType = getContentTypeWithoutCharset(response); + switch (responseVariableType) { + case AUTO: + if (isTextContentType(contentType)) { + return response.getBody(); + } else if (isJsonContentType(contentType)) { + return readJsonTree(response, objectMapper); + } else { + return response.getBodyBytes(); + } + case STRING: { + return response.getBody(); + } + case JSON: { + return readJsonTree(response, objectMapper); + } + case BYTES: { + return response.getBodyBytes(); + } + case BASE64: { + byte[] bodyBytes = response.getBodyBytes(); + return Base64.getEncoder().encodeToString(bodyBytes); + } + default: { + throw new FlowableException("Unsupported response variable type: " + responseVariableType); + } + } + } + + protected Object readJsonTree(HttpResponse response, ObjectMapper objectMapper) throws JsonProcessingException { + Object varValue; + if (response.getBody() != null) { + varValue = objectMapper.readTree(response.getBody()); + } else { + varValue = response.getBody(); + } + if (varValue instanceof MissingNode || varValue instanceof NullNode) { + varValue = null; + } + return varValue; + } + + protected boolean isJsonContentType(String contentType) { + if (contentType != null) { + return contentType != null && contentType.endsWith("/json") || contentType.endsWith("+json"); + } + return false; + } + + protected boolean isTextContentType(String contentType) { + if (contentType != null) { + return contentType.startsWith("text/") || contentType.endsWith("/xml") || contentType.endsWith("+xml"); + } + return false; + } + + protected String getContentTypeWithoutCharset(HttpResponse response) { + List contentTypeHeader = response.getHttpHeaders().get("Content-Type"); + if (contentTypeHeader != null && !contentTypeHeader.isEmpty()) { + String contentType = contentTypeHeader.get(0); + if (contentType.indexOf(';') >= 0) { + contentType = contentType.split(";")[0]; // remove charset if present + } + return contentType; + } + return null; + } + + protected HttpResponseVariableType determineResponseVariableType(VariableContainer variableContainer) { + // We use string as default, when neither is set, for backwards compatibility reasons. + HttpResponseVariableType effectiveResponseVariableType = HttpResponseVariableType.STRING; + if (responseVariableType != null && saveResponseVariableAsJson != null) { + throw new FlowableException( + "Only one of responseVariableType or saveResponseVariableAsJson can be set, not both. saveResponseVariableAsJson is deprecated, please use responseVariableType instead."); + } + if (responseVariableType != null) { + String responseVariableTypeString = ExpressionUtils.getStringFromField(responseVariableType, variableContainer).toUpperCase(Locale.ROOT); + if (responseVariableTypeString == null) { + effectiveResponseVariableType = HttpResponseVariableType.AUTO; + } else if (responseVariableTypeString.equalsIgnoreCase("true")) { + // Backwards compatibility - if the responseVariableType is set to true, then we assume it's JSON + effectiveResponseVariableType = HttpResponseVariableType.JSON; + } else { + effectiveResponseVariableType = HttpResponseVariableType.valueOf(responseVariableTypeString.toUpperCase(Locale.ROOT)); + } + } else if (saveResponseVariableAsJson != null) { + // Backwards compatibility - if the saveResponseVariableAsJson is set, then we assume it's JSON otherwise it's a string (old default). + boolean saveResponseAsJson = ExpressionUtils.getBooleanFromField(saveResponseVariableAsJson, variableContainer); + effectiveResponseVariableType = saveResponseAsJson ? HttpResponseVariableType.JSON : HttpResponseVariableType.STRING; + } + return effectiveResponseVariableType; + } + protected CompletableFuture prepareAndExecuteRequest(RequestData request, boolean parallelInSameTransaction, AsyncTaskInvoker taskInvoker) { ExecutableHttpRequest httpRequest = httpClient.prepareRequest(request.getHttpRequest()); @@ -303,7 +408,8 @@ public static class RequestData { protected boolean saveRequest; protected boolean saveResponse; protected boolean saveResponseTransient; - protected boolean saveResponseAsJson; + + protected HttpResponseVariableType responseVariableType; protected String prefix; public HttpRequest getHttpRequest() { @@ -362,12 +468,12 @@ public void setSaveResponseTransient(boolean saveResponseTransient) { this.saveResponseTransient = saveResponseTransient; } - public boolean isSaveResponseAsJson() { - return saveResponseAsJson; + public HttpResponseVariableType getResponseVariableType() { + return responseVariableType; } - public void setSaveResponseAsJson(boolean saveResponseAsJson) { - this.saveResponseAsJson = saveResponseAsJson; + public void setResponseVariableType(HttpResponseVariableType responseVariableType) { + this.responseVariableType = responseVariableType; } public String getPrefix() { diff --git a/modules/flowable-http/src/test/java/org/flowable/http/bpmn/HttpServiceTaskTest.java b/modules/flowable-http/src/test/java/org/flowable/http/bpmn/HttpServiceTaskTest.java index 69911ff0bb3..b0a6d768f3d 100644 --- a/modules/flowable-http/src/test/java/org/flowable/http/bpmn/HttpServiceTaskTest.java +++ b/modules/flowable-http/src/test/java/org/flowable/http/bpmn/HttpServiceTaskTest.java @@ -21,6 +21,7 @@ import java.io.IOException; import java.net.SocketException; import java.net.SocketTimeoutException; +import java.nio.charset.StandardCharsets; import java.util.HashMap; import java.util.List; import java.util.Map; @@ -51,6 +52,7 @@ import com.fasterxml.jackson.databind.JsonNode; import com.fasterxml.jackson.databind.ObjectMapper; +import com.fasterxml.jackson.databind.node.ObjectNode; import net.javacrumbs.jsonunit.core.Option; @@ -675,6 +677,136 @@ public void testGetWithVariableParameters(String requestParam, String expectedRe assertProcessEnded(procId); } + @Test + @Deployment(resources = "org/flowable/http/bpmn/HttpServiceTaskTest.testGetWithSaveResponseVariableAndVariableType.bpmn20.xml") + public void testGetWithSaveResponseVariablePdfIsPutAsByteArrayForAutoType() { + String procId = runtimeService.createProcessInstanceBuilder() + .processDefinitionKey("simpleGetOnly") + .transientVariable("requestUrl","http://localhost:9798/binary/pdf") + .transientVariable("responseVariableType","auto") + .start() + .getId(); + List variables = historyService.createHistoricVariableInstanceQuery().processInstanceId(procId).list(); + assertThat(variables) + .extracting(HistoricVariableInstance::getVariableName) + .containsExactly("responseVariable"); + assertThat(variables.get(0).getValue()).isInstanceOfSatisfying(byte[].class, value -> assertThat(value).isNotEmpty()); + assertProcessEnded(procId); + + + // request byte array + procId = runtimeService.createProcessInstanceBuilder() + .processDefinitionKey("simpleGetOnly") + .transientVariable("requestUrl","http://localhost:9798/binary/pdf") + .transientVariable("responseVariableType","bytes") + .start() + .getId(); + variables = historyService.createHistoricVariableInstanceQuery().processInstanceId(procId).list(); + assertThat(variables) + .extracting(HistoricVariableInstance::getVariableName) + .containsExactly("responseVariable"); + assertThat(variables.get(0).getValue()).isInstanceOfSatisfying(byte[].class, value -> assertThat(value).isNotEmpty()); + assertProcessEnded(procId); + } + + @Test + @Deployment(resources = "org/flowable/http/bpmn/HttpServiceTaskTest.testGetWithSaveResponseVariableAndVariableType.bpmn20.xml") + public void testGetWithSaveResponseVariableAndVariableTypeStringOctetStream() { + String procId = runtimeService.createProcessInstanceBuilder() + .processDefinitionKey("simpleGetOnly") + .transientVariable("requestUrl","http://localhost:9798/binary/octet-stream-string") + .transientVariable("responseVariableType","string") + .start() + .getId(); + List variables = historyService.createHistoricVariableInstanceQuery().processInstanceId(procId).list(); + assertThat(variables) + .extracting(HistoricVariableInstance::getVariableName) + .containsExactly("responseVariable"); + assertThat(variables.get(0).getValue()).isInstanceOfSatisfying(String.class, + value -> assertThat(value).isEqualTo("Content-Type is octet-stream, but still a string")); + assertProcessEnded(procId); + } + + @Test + @Deployment(resources = "org/flowable/http/bpmn/HttpServiceTaskTest.testGetWithSaveResponseVariableAndVariableType.bpmn20.xml") + public void testGetWithSaveResponseVariableAndVariableTypeJsonContent() { + // AUTO + String procId = runtimeService.createProcessInstanceBuilder() + .processDefinitionKey("simpleGetOnly") + .transientVariable("requestUrl","http://localhost:9798/test") + .transientVariable("responseVariableType","auto") + .start() + .getId(); + List variables = historyService.createHistoricVariableInstanceQuery().processInstanceId(procId).list(); + assertThat(variables) + .extracting(HistoricVariableInstance::getVariableName) + .containsExactly("responseVariable"); + assertThat(variables.get(0).getValue()).isInstanceOfSatisfying(ObjectNode.class, + value -> assertThatJson(value).isEqualTo("{name:{firstName:'John', lastName:'Doe'}}")); + assertProcessEnded(procId); + + // BASE64 + procId = runtimeService.createProcessInstanceBuilder() + .processDefinitionKey("simpleGetOnly") + .transientVariable("requestUrl","http://localhost:9798/test") + .transientVariable("responseVariableType","base64") + .start() + .getId(); + variables = historyService.createHistoricVariableInstanceQuery().processInstanceId(procId).list(); + assertThat(variables) + .extracting(HistoricVariableInstance::getVariableName) + .containsExactly("responseVariable"); + assertThat(variables.get(0).getValue()).isInstanceOfSatisfying(String.class, + value -> assertThat(value).isEqualTo("eyJuYW1lIjp7ImZpcnN0TmFtZSI6IkpvaG4iLCJsYXN0TmFtZSI6IkRvZSJ9fQo=")); + assertProcessEnded(procId); + + // BYTES + procId = runtimeService.createProcessInstanceBuilder() + .processDefinitionKey("simpleGetOnly") + .transientVariable("requestUrl","http://localhost:9798/test") + .transientVariable("responseVariableType","bytes") + .start() + .getId(); + variables = historyService.createHistoricVariableInstanceQuery().processInstanceId(procId).list(); + assertThat(variables) + .extracting(HistoricVariableInstance::getVariableName) + .containsExactly("responseVariable"); + assertThat(variables.get(0).getValue()).isInstanceOfSatisfying(byte[].class, + value -> assertThat(value).asString(StandardCharsets.UTF_8).isEqualToIgnoringWhitespace("{\"name\":{\"firstName\":\"John\",\"lastName\":\"Doe\"}}")); + assertProcessEnded(procId); + + // STRING + procId = runtimeService.createProcessInstanceBuilder() + .processDefinitionKey("simpleGetOnly") + .transientVariable("requestUrl","http://localhost:9798/test") + .transientVariable("responseVariableType","string") + .start() + .getId(); + variables = historyService.createHistoricVariableInstanceQuery().processInstanceId(procId).list(); + assertThat(variables) + .extracting(HistoricVariableInstance::getVariableName) + .containsExactly("responseVariable"); + assertThat(variables.get(0).getValue()).isInstanceOfSatisfying(String.class, + value -> assertThat(value).isEqualToIgnoringWhitespace("{\"name\":{\"firstName\":\"John\",\"lastName\":\"Doe\"}}")); + assertProcessEnded(procId); + + // JSON + procId = runtimeService.createProcessInstanceBuilder() + .processDefinitionKey("simpleGetOnly") + .transientVariable("requestUrl","http://localhost:9798/test") + .transientVariable("responseVariableType","json") + .start() + .getId(); + variables = historyService.createHistoricVariableInstanceQuery().processInstanceId(procId).list(); + assertThat(variables) + .extracting(HistoricVariableInstance::getVariableName) + .containsExactly("responseVariable"); + assertThat(variables.get(0).getValue()).isInstanceOfSatisfying(ObjectNode.class, + value -> assertThatJson(value).isEqualTo("{name:{firstName:'John',lastName:'Doe'}}")); + assertProcessEnded(procId); + } + + static Stream parametersForGetWithVariableParameters() { return Stream.of( Arguments.arguments("Test+ Plus", "Test+ Plus"), diff --git a/modules/flowable-http/src/test/java/org/flowable/http/bpmn/HttpServiceTaskTestServer.java b/modules/flowable-http/src/test/java/org/flowable/http/bpmn/HttpServiceTaskTestServer.java index b6ad6b356fc..f0b8090d08a 100644 --- a/modules/flowable-http/src/test/java/org/flowable/http/bpmn/HttpServiceTaskTestServer.java +++ b/modules/flowable-http/src/test/java/org/flowable/http/bpmn/HttpServiceTaskTestServer.java @@ -102,6 +102,8 @@ public class HttpServiceTaskTestServer { httpServiceTaskServletHolder.getRegistration().setMultipartConfig(multipartConfig); contextHandler.addServlet(httpServiceTaskServletHolder, "/api/*"); contextHandler.addServlet(new ServletHolder(new SimpleHttpServiceTaskTestServlet()), "/test"); + contextHandler.addServlet(new ServletHolder(new SimpleHttpServiceTaskBinaryContentTestServlet()), "/binary/pdf"); + contextHandler.addServlet(new ServletHolder(new OctetStreamStringTestServlet()), "/binary/octet-stream-string"); contextHandler.addServlet(new ServletHolder(new HelloServlet()), "/hello"); contextHandler.addServlet(new ServletHolder(new ArrayResponseServlet()), "/array-response"); contextHandler.addServlet(new ServletHolder(new DeleteResponseServlet()), "/delete"); @@ -293,6 +295,31 @@ protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws Se resp.getWriter().println(responseNode); } } + + private static class OctetStreamStringTestServlet extends HttpServlet { + + private static final long serialVersionUID = 1L; + + @Override + protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws IOException { + resp.setStatus(200); + resp.setContentType("application/octet-stream"); + resp.getWriter().write("Content-Type is octet-stream, but still a string"); + } + } + + private static class SimpleHttpServiceTaskBinaryContentTestServlet extends HttpServlet { + + private static final long serialVersionUID = 1L; + + @Override + protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws IOException { + resp.setStatus(200); + resp.setContentType("application/pdf"); + InputStream byteArrayInputStream = getClass().getClassLoader().getResourceAsStream("org/flowable/http/content/sample.pdf"); + IOUtils.copy(byteArrayInputStream, resp.getOutputStream()); + } + } private static class HelloServlet extends HttpServlet { diff --git a/modules/flowable-http/src/test/java/org/flowable/http/cmmn/CmmnHttpTaskTest.java b/modules/flowable-http/src/test/java/org/flowable/http/cmmn/CmmnHttpTaskTest.java index b2fecb2d0b9..8a98d4493b7 100644 --- a/modules/flowable-http/src/test/java/org/flowable/http/cmmn/CmmnHttpTaskTest.java +++ b/modules/flowable-http/src/test/java/org/flowable/http/cmmn/CmmnHttpTaskTest.java @@ -12,11 +12,13 @@ */ package org.flowable.http.cmmn; +import static net.javacrumbs.jsonunit.assertj.JsonAssertions.assertThatJson; import static org.assertj.core.api.Assertions.assertThat; import static org.assertj.core.api.Assertions.assertThatThrownBy; import static org.assertj.core.api.Assertions.entry; import java.net.SocketTimeoutException; +import java.nio.charset.StandardCharsets; import java.util.HashMap; import java.util.Map; @@ -29,6 +31,8 @@ import org.junit.Rule; import org.junit.Test; +import com.fasterxml.jackson.databind.node.ObjectNode; + /** * @author martin.grofcik */ @@ -319,6 +323,104 @@ public void testExpressions() throws Exception { ); } + @Test + @CmmnDeployment(resources = "org/flowable/http/cmmn/CmmnHttpTaskTest.testGetWithResponseVariableAndVariableType.cmmn") + public void testGetWithSaveResponseVariablePdfIsPutAsByteArrayByDefault() { + // default + CaseInstance caseInstance = cmmnRule.getCmmnRuntimeService().createCaseInstanceBuilder() + .caseDefinitionKey("myCase") + .transientVariable("responseVariableType","auto") + .transientVariable("requestUrl","http://localhost:9798/binary/pdf") + .start(); + + Map variables = caseInstance.getCaseVariables(); + assertThat(variables.get("responseVariable")).isInstanceOfSatisfying(byte[].class, value -> assertThat(value).isNotEmpty()); + + // request byte array + caseInstance = cmmnRule.getCmmnRuntimeService().createCaseInstanceBuilder() + .caseDefinitionKey("myCase") + .transientVariable("responseVariableType","bytes") + .transientVariable("requestUrl","http://localhost:9798/binary/pdf") + .start(); + + variables = caseInstance.getCaseVariables(); + assertThat(variables.get("responseVariable")).isInstanceOfSatisfying(byte[].class, value -> assertThat(value).isNotEmpty()); + } + + @Test + @CmmnDeployment(resources = "org/flowable/http/cmmn/CmmnHttpTaskTest.testGetWithResponseVariableAndVariableType.cmmn") + public void testGetWithSaveResponseVariableAndVariableTypeStringOctetStream() { + CaseInstance caseInstance = cmmnRule.getCmmnRuntimeService().createCaseInstanceBuilder() + .caseDefinitionKey("myCase") + .transientVariable("responseVariableType","string") + .transientVariable("requestUrl","http://localhost:9798/binary/octet-stream-string") + .start(); + + Map variables = caseInstance.getCaseVariables(); + assertThat(variables.get("responseVariable")).isInstanceOfSatisfying(String.class, + value -> assertThat(value).isEqualTo("Content-Type is octet-stream, but still a string")); + } + + @Test + @CmmnDeployment(resources = "org/flowable/http/cmmn/CmmnHttpTaskTest.testGetWithResponseVariableAndVariableType.cmmn") + public void testGetWithSaveResponseVariableAndVariableTypeJsonContent() { + // DEFAULT + CaseInstance caseInstance = cmmnRule.getCmmnRuntimeService().createCaseInstanceBuilder() + .caseDefinitionKey("myCase") + .transientVariable("responseVariableType", "auto") + .transientVariable("requestUrl", "http://localhost:9798/test") + .start(); + + Map variables = caseInstance.getCaseVariables(); + assertThat(variables.get("responseVariable")).isInstanceOfSatisfying(ObjectNode.class, + value -> assertThatJson(value).isEqualTo("{name:{firstName:'John', lastName:'Doe'}}")); + + // BASE64 + caseInstance = cmmnRule.getCmmnRuntimeService().createCaseInstanceBuilder() + .caseDefinitionKey("myCase") + .transientVariable("responseVariableType", "base64") + .transientVariable("requestUrl", "http://localhost:9798/test") + .start(); + + variables = caseInstance.getCaseVariables(); + assertThat(variables.get("responseVariable")).isInstanceOfSatisfying(String.class, + value -> assertThat(value).isEqualTo("eyJuYW1lIjp7ImZpcnN0TmFtZSI6IkpvaG4iLCJsYXN0TmFtZSI6IkRvZSJ9fQo=")); + + // BYTES + caseInstance = cmmnRule.getCmmnRuntimeService().createCaseInstanceBuilder() + .caseDefinitionKey("myCase") + .transientVariable("responseVariableType", "bytes") + .transientVariable("requestUrl", "http://localhost:9798/test") + .start(); + + variables = caseInstance.getCaseVariables(); + assertThat(variables.get("responseVariable")).isInstanceOfSatisfying(byte[].class, + value -> assertThat(value).asString(StandardCharsets.UTF_8) + .isEqualToIgnoringWhitespace("{\"name\":{\"firstName\":\"John\",\"lastName\":\"Doe\"}}")); + + // STRING + caseInstance = cmmnRule.getCmmnRuntimeService().createCaseInstanceBuilder() + .caseDefinitionKey("myCase") + .transientVariable("responseVariableType", "string") + .transientVariable("requestUrl", "http://localhost:9798/test") + .start(); + + variables = caseInstance.getCaseVariables(); + assertThat(variables.get("responseVariable")).isInstanceOfSatisfying(String.class, + value -> assertThatJson(value).isEqualTo("{\"name\":{\"firstName\":\"John\",\"lastName\":\"Doe\"}}")); + } + + @Test + @CmmnDeployment(resources = "org/flowable/http/cmmn/CmmnHttpTaskTest.testGetWithSaveResponseVariableAndVariableType.cmmn") + public void testGetWithInvalidConfigJsonAndVariableResponseType() { + assertThatThrownBy(() -> cmmnRule.getCmmnRuntimeService().createCaseInstanceBuilder() + .caseDefinitionKey("myCase") + .transientVariable("requestUrl", "http://localhost:9798/binary/pdf") + .start()).isInstanceOf(FlowableException.class) + .hasMessage("Only one of responseVariableType or saveResponseVariableAsJson can be set, not both. " + + "saveResponseVariableAsJson is deprecated, please use responseVariableType instead."); + } + protected CaseInstance createCaseInstance() { return cmmnRule.getCmmnRuntimeService().createCaseInstanceBuilder() .caseDefinitionKey("myCase") diff --git a/modules/flowable-http/src/test/resources/org/flowable/http/bpmn/HttpServiceTaskTest.testGetWithSaveResponseVariableAndVariableType.bpmn20.xml b/modules/flowable-http/src/test/resources/org/flowable/http/bpmn/HttpServiceTaskTest.testGetWithSaveResponseVariableAndVariableType.bpmn20.xml new file mode 100644 index 00000000000..9f103d4c667 --- /dev/null +++ b/modules/flowable-http/src/test/resources/org/flowable/http/bpmn/HttpServiceTaskTest.testGetWithSaveResponseVariableAndVariableType.bpmn20.xml @@ -0,0 +1,30 @@ + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/modules/flowable-http/src/test/resources/org/flowable/http/cmmn/CmmnHttpTaskTest.testGetWithResponseVariableAndVariableType.cmmn b/modules/flowable-http/src/test/resources/org/flowable/http/cmmn/CmmnHttpTaskTest.testGetWithResponseVariableAndVariableType.cmmn new file mode 100644 index 00000000000..1c5e7debc4c --- /dev/null +++ b/modules/flowable-http/src/test/resources/org/flowable/http/cmmn/CmmnHttpTaskTest.testGetWithResponseVariableAndVariableType.cmmn @@ -0,0 +1,45 @@ + + + + + + + + + + + + + + complete + + + + + + + + + + + + + + + + + + + false + + + + + + + + + + diff --git a/modules/flowable-http/src/test/resources/org/flowable/http/cmmn/CmmnHttpTaskTest.testGetWithSaveResponseVariableAndVariableType.cmmn b/modules/flowable-http/src/test/resources/org/flowable/http/cmmn/CmmnHttpTaskTest.testGetWithSaveResponseVariableAndVariableType.cmmn new file mode 100644 index 00000000000..5d34725daa7 --- /dev/null +++ b/modules/flowable-http/src/test/resources/org/flowable/http/cmmn/CmmnHttpTaskTest.testGetWithSaveResponseVariableAndVariableType.cmmn @@ -0,0 +1,45 @@ + + + + + + + + + + + + + + complete + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/modules/flowable-http/src/test/resources/org/flowable/http/content/sample.pdf b/modules/flowable-http/src/test/resources/org/flowable/http/content/sample.pdf new file mode 100644 index 00000000000..774c2ea70c5 Binary files /dev/null and b/modules/flowable-http/src/test/resources/org/flowable/http/content/sample.pdf differ