From d2e69c0d689596033a9c35aa98d37a44e2cc88cb Mon Sep 17 00:00:00 2001 From: Rob Daugherty Date: Tue, 15 May 2018 13:23:01 -0400 Subject: WorkflowResponse json issues This commit adds some robustness to the interface between the API-H and BPMN, specifically, in how the response is handled. I don't have proof, but there appears to be some randomness to the json provider behavior when used with the jax-rs. Sometimes, the serializer is adding the root element, and sometimes it is not. Maybe there's something wrong with the configuration. Maybe we have competing json providers. I couldn't pin this down. I'm almost certain it is the presence of the root element in the content that causes the API-H code to fail parsing of the BPMN response. This doesn't kill the request, as you might expect, but rather, the API-H passes the BPMN response through to the client (VID, or policy, or whatever). The original problem (SO-586) was "fixed" by "removing the wrapper". This "wrapper" is a needed feature of the interface between BPMN and the API-H. We shouldn't have removed it. The fact that the "fix" appeared to work is due to the behavior I described in the previous paragraph. The API-H chokes on the message, and it passes it through unchanged. Not really what we want. So, I don't know why the jackson/json behavior is flaky and different now, but I can (and did) modify the API-H so it can parse a json message whether or not it has a root element. Note that WorkflowResponse.java (in BPMN) and CamundaResponse.java (in the API-H) are basically the same bean representing the message format. Seems less than ideal to have two different classes. Also note that I changed the name of the "response" attribute of the WorkflowResponse and CamundaResponse classes to "content". Got tired of seeing this nonsense everywhere in the code: response.getResponse() Change-Id: Icaf70f8457de99e493cf882170fe778c620308c9 Issue-ID: SO-586 Issue-ID: SO-618 Signed-off-by: Rob Daugherty --- .../apihandler/camundabeans/CamundaResponse.java | 83 ++++++++++++---------- .../mso/apihandler/common/ResponseHandler.java | 78 ++++++++++---------- .../mso/camunda/tests/CamundaResponseTest.java | 55 +++++++++----- .../mso/camunda/tests/ResponseHandlerTest.java | 26 ++++--- 4 files changed, 137 insertions(+), 105 deletions(-) (limited to 'mso-api-handlers/mso-api-handler-common') diff --git a/mso-api-handlers/mso-api-handler-common/src/main/java/org/openecomp/mso/apihandler/camundabeans/CamundaResponse.java b/mso-api-handlers/mso-api-handler-common/src/main/java/org/openecomp/mso/apihandler/camundabeans/CamundaResponse.java index 3c5c5ecb1d..64b7d86b59 100644 --- a/mso-api-handlers/mso-api-handler-common/src/main/java/org/openecomp/mso/apihandler/camundabeans/CamundaResponse.java +++ b/mso-api-handlers/mso-api-handler-common/src/main/java/org/openecomp/mso/apihandler/camundabeans/CamundaResponse.java @@ -20,53 +20,41 @@ package org.openecomp.mso.apihandler.camundabeans; +import java.util.Map; import com.fasterxml.jackson.annotation.JsonProperty; +import com.fasterxml.jackson.annotation.JsonRootName; + +// This class must be 100% JSON-compatible with the BPMN WorkflowResponse class. +// TODO: BPMN and the API-H should use a common class. /** - * JavaBean JSON class for a "variables" which contains the xml payload that - * will be passed to the Camunda process - * + * A synchronous response from a workflow. */ - +@JsonRootName(value = "WorkflowResponse") public class CamundaResponse { - - @JsonProperty("response") - private String response; + + @JsonProperty("processInstanceId") + private String processInstanceId; + @JsonProperty("messageCode") private int messageCode; + @JsonProperty("message") private String message; - @JsonProperty("processInstanceID") - private String processInstanceID; - @JsonProperty("variables") - private String variables; - public String getProcessInstanceID() { - return processInstanceID; - } - - public void setProcessInstanceID(String processInstanceID) { - this.processInstanceID = processInstanceID; - } - - public String getVariables() { - return variables; - } - - public void setVariables(String variables) { - this.variables = variables; - } + @JsonProperty("variables") + private Map variables; - public CamundaResponse() { - } + @JsonProperty("content") + private String content; - public String getResponse() { - return response; + public String getProcessInstanceId() { + return processInstanceId; } - public void setResponse(String response) { - this.response = response; + public void setProcessInstanceId(String processInstanceId) { + this.processInstanceId = processInstanceId; } public int getMessageCode() { @@ -85,13 +73,30 @@ public class CamundaResponse { this.message = message; } + public Map getVariables() { + return variables; + } + + public void setVariables(Map variables) { + this.variables = variables; + } + + public String getContent() { + return content; + } + + public void setContent(String content) { + this.content = content; + } + @Override public String toString() { - return "CamundaResponse [response=" + response + ", messageCode=" - + messageCode + ", message=" + message + "]"; + return getClass().getSimpleName() + "[" + + "processInstanceId=" + processInstanceId + + ",messageCode=" + messageCode + + ",message=" + message + + ",variables=" + variables + + ",content=" + content + + "]"; } - - - - -} +} \ No newline at end of file diff --git a/mso-api-handlers/mso-api-handler-common/src/main/java/org/openecomp/mso/apihandler/common/ResponseHandler.java b/mso-api-handlers/mso-api-handler-common/src/main/java/org/openecomp/mso/apihandler/common/ResponseHandler.java index 732b7786b2..a8b8984343 100644 --- a/mso-api-handlers/mso-api-handler-common/src/main/java/org/openecomp/mso/apihandler/common/ResponseHandler.java +++ b/mso-api-handlers/mso-api-handler-common/src/main/java/org/openecomp/mso/apihandler/common/ResponseHandler.java @@ -27,21 +27,22 @@ import org.apache.http.HttpEntity; import org.apache.http.HttpResponse; import org.apache.http.HttpStatus; import org.apache.http.util.EntityUtils; -import com.fasterxml.jackson.databind.ObjectMapper; - import org.openecomp.mso.apihandler.camundabeans.CamundaResponse; -import org.openecomp.mso.logger.MsoLogger; import org.openecomp.mso.logger.MessageEnum; +import org.openecomp.mso.logger.MsoLogger; +import org.openecomp.mso.utils.RootIgnoringObjectMapper; + +import com.fasterxml.jackson.databind.ObjectMapper; public class ResponseHandler { private CamundaResponse response; private int status; - private String responseBody=""; + private String content = ""; private HttpResponse httpResponse; private int type; private static MsoLogger msoLogger = MsoLogger.getMsoLogger(MsoLogger.Catalog.APIH); - private static final String RESPONSE_BODY_MSG = "response body is: "; + private static final String RESPONSE_CONTENT_MSG = "response content is: "; public ResponseHandler(HttpResponse httpResponse, int type) { this.httpResponse = httpResponse; @@ -67,29 +68,31 @@ public class ResponseHandler { + @SuppressWarnings("unchecked") private void parseCamunda(){ try{ - HttpEntity entity = httpResponse.getEntity(); - responseBody = EntityUtils.toString(entity); - } catch (IOException e) { - msoLogger.debug("IOException getting Camunda response body", e); - } - - ObjectMapper mapper = new ObjectMapper(); - try { - response = mapper.readValue(responseBody, CamundaResponse.class); - } catch (IOException e) { - msoLogger.debug("IOException getting Camunda response body", e); - } - msoLogger.debug("json response is: " + responseBody); - if(response!=null){ - responseBody = response.getResponse(); - } - msoLogger.debug(RESPONSE_BODY_MSG + responseBody); - - + HttpEntity entity = httpResponse.getEntity(); + content = EntityUtils.toString(entity); + } catch (IOException e) { + msoLogger.debug("IOException getting Camunda response content", e); + } + + ObjectMapper mapper = new RootIgnoringObjectMapper(CamundaResponse.class); + + try { + response = mapper.readValue(content, CamundaResponse.class); + } catch (IOException e) { + msoLogger.debug("IOException getting Camunda response content", e); + } + msoLogger.debug("json response is: " + content); + if(response!=null){ + content = response.getContent(); + } + msoLogger.debug(RESPONSE_CONTENT_MSG + content); + + if(status!=HttpStatus.SC_ACCEPTED){ - msoLogger.error(MessageEnum.APIH_ERROR_FROM_BPEL_SERVER, "Camunda", String.valueOf(status), responseBody, "Camunda", "parseCamunda", MsoLogger.ErrorCode.BusinessProcesssError, "Error in APIH from Camunda"); + msoLogger.error(MessageEnum.APIH_ERROR_FROM_BPEL_SERVER, "Camunda", String.valueOf(status), content, "Camunda", "parseCamunda", MsoLogger.ErrorCode.BusinessProcesssError, "Error in APIH from Camunda"); } } @@ -99,16 +102,16 @@ public class ResponseHandler { try { if (bpelEntity!=null) { - responseBody = EntityUtils.toString(bpelEntity); - msoLogger.debug(RESPONSE_BODY_MSG + responseBody); + content = EntityUtils.toString(bpelEntity); + msoLogger.debug(RESPONSE_CONTENT_MSG + content); } if(status!=HttpStatus.SC_ACCEPTED){ - msoLogger.error(MessageEnum.APIH_ERROR_FROM_BPEL_SERVER, "BPEL", String.valueOf(status), responseBody, "BPEL", "parseBpel", MsoLogger.ErrorCode.BusinessProcesssError, "Error in APIH from BPEL"); + msoLogger.error(MessageEnum.APIH_ERROR_FROM_BPEL_SERVER, "BPEL", String.valueOf(status), content, "BPEL", "parseBpel", MsoLogger.ErrorCode.BusinessProcesssError, "Error in APIH from BPEL"); } } catch (IOException e) { - msoLogger.debug("IOException getting BPEL response body", e); + msoLogger.debug("IOException getting BPEL response content", e); } } @@ -118,16 +121,16 @@ public class ResponseHandler { try { if (camundataskEntity!=null) { - responseBody = EntityUtils.toString(camundataskEntity); - msoLogger.debug(RESPONSE_BODY_MSG + responseBody); + content = EntityUtils.toString(camundataskEntity); + msoLogger.debug(RESPONSE_CONTENT_MSG + content); } if(status!=HttpStatus.SC_NO_CONTENT && status != HttpStatus.SC_ACCEPTED){ - msoLogger.error(MessageEnum.APIH_ERROR_FROM_BPEL_SERVER, "CAMUNDATASK", String.valueOf(status), responseBody, "CAMUNDATASK", "parseCamundaTask", MsoLogger.ErrorCode.BusinessProcesssError, "Error in APIH from Camunda Task"); + msoLogger.error(MessageEnum.APIH_ERROR_FROM_BPEL_SERVER, "CAMUNDATASK", String.valueOf(status), content, "CAMUNDATASK", "parseCamundaTask", MsoLogger.ErrorCode.BusinessProcesssError, "Error in APIH from Camunda Task"); } } catch (IOException e) { - msoLogger.debug("IOException getting Camunda Task response body", e); + msoLogger.debug("IOException getting Camunda Task response content", e); } } @@ -175,18 +178,17 @@ public class ResponseHandler { } - public String getResponseBody() { - return responseBody; + public String getContent() { + return content; } - public void setResponseBody(String responseBody) { - this.responseBody = responseBody; + public void setContent(String content) { + this.content = content; } public int getStatus() { return status; } - } diff --git a/mso-api-handlers/mso-api-handler-common/src/test/java/org/openecomp/mso/camunda/tests/CamundaResponseTest.java b/mso-api-handlers/mso-api-handler-common/src/test/java/org/openecomp/mso/camunda/tests/CamundaResponseTest.java index 9b36a984b1..7fc2815b4b 100644 --- a/mso-api-handlers/mso-api-handler-common/src/test/java/org/openecomp/mso/camunda/tests/CamundaResponseTest.java +++ b/mso-api-handlers/mso-api-handler-common/src/test/java/org/openecomp/mso/camunda/tests/CamundaResponseTest.java @@ -23,14 +23,10 @@ package org.openecomp.mso.camunda.tests; import static org.junit.Assert.assertEquals; -import java.io.IOException; - import org.junit.Test; import org.openecomp.mso.apihandler.camundabeans.CamundaResponse; +import org.openecomp.mso.utils.RootIgnoringObjectMapper; -import com.fasterxml.jackson.core.JsonGenerationException; -import com.fasterxml.jackson.databind.DeserializationFeature; -import com.fasterxml.jackson.databind.JsonMappingException; import com.fasterxml.jackson.databind.ObjectMapper; /** @@ -41,19 +37,42 @@ import com.fasterxml.jackson.databind.ObjectMapper; public class CamundaResponseTest { @Test - public final void testDeserialization() throws JsonGenerationException, - JsonMappingException, IOException { - ObjectMapper mapper = new ObjectMapper(); // can reuse, share globally - mapper.enable(DeserializationFeature.ACCEPT_SINGLE_VALUE_AS_ARRAY); - - String responseBody = "{ \"response\": \"xml\","+ - "\"messageCode\": 200,"+ - "\"message\": \"Successfully started the process\"," + - "\"processInstanceID\":null,\"variables\":null}"; - - CamundaResponse response = mapper.readValue(responseBody, CamundaResponse.class); - assertEquals(response.toString(), "CamundaResponse [response=xml, messageCode=200, message=Successfully started the process]"); + public final void testDeserializationWithoutRootElement() throws Exception { + + ObjectMapper mapper = new RootIgnoringObjectMapper(CamundaResponse.class); + + String content = "{" + + "\"messageCode\":202" + + ",\"message\":\"Successfully started the process\"" + + ",\"content\":\"xml\"" + + ",\"processInstanceId\":\"4d3b3201a7ce\"" + + ",\"variables\":null" + + "}"; + CamundaResponse response = mapper.readValue(content, CamundaResponse.class); + + assertEquals( + "CamundaResponse[processInstanceId=4d3b3201a7ce,messageCode=202,message=Successfully started the process,variables=null,content=xml]", + response.toString()); } -} + @Test + public final void testDeserializationWithRootElement() throws Exception { + + ObjectMapper mapper = new RootIgnoringObjectMapper(CamundaResponse.class); + + String content = "{\"WorkflowResponse\":{" + + "\"messageCode\":202" + + ",\"message\":\"Successfully started the process\"" + + ",\"content\":\"xml\"" + + ",\"processInstanceId\":\"4d3b3201a7ce\"" + + ",\"variables\":null" + + "}}"; + + CamundaResponse response = mapper.readValue(content, CamundaResponse.class); + + assertEquals( + "CamundaResponse[processInstanceId=4d3b3201a7ce,messageCode=202,message=Successfully started the process,variables=null,content=xml]", + response.toString()); + } +} \ No newline at end of file diff --git a/mso-api-handlers/mso-api-handler-common/src/test/java/org/openecomp/mso/camunda/tests/ResponseHandlerTest.java b/mso-api-handlers/mso-api-handler-common/src/test/java/org/openecomp/mso/camunda/tests/ResponseHandlerTest.java index d0031f3946..e04aba0ede 100644 --- a/mso-api-handlers/mso-api-handler-common/src/test/java/org/openecomp/mso/camunda/tests/ResponseHandlerTest.java +++ b/mso-api-handlers/mso-api-handler-common/src/test/java/org/openecomp/mso/camunda/tests/ResponseHandlerTest.java @@ -47,13 +47,15 @@ public class ResponseHandlerTest { @Test public void tesParseCamundaResponse () throws JsonGenerationException, JsonMappingException, IOException { - // String body - // ="{\"links\":[{\"method\":\"GET\",\"href\":\"http://localhost:9080/engine-rest/process-instance/2047c658-37ae-11e5-9505-7a1020524153\",\"rel\":\"self\"}],\"id\":\"2047c658-37ae-11e5-9505-7a1020524153\",\"definitionId\":\"dummy:10:73298961-37ad-11e5-9505-7a1020524153\",\"businessKey\":null,\"caseInstanceId\":null,\"ended\":true,\"suspended\":false}"; - String body = "{ \"response\": \"xml\"," + "\"messageCode\": 200," - + "\"message\": \"Successfully started the process\"}"; + String content = "{\"WorkflowResponse\":{" + + "\"messageCode\":202" + + ",\"message\":\"Successfully started the process\"" + + ",\"content\":\"xml\"" + + ",\"processInstanceId\":\"4d3b3201a7ce\"" + + "}}"; - HttpResponse response = createResponse (200, body, "application/json"); + HttpResponse response = createResponse (200, content, "application/json"); ResponseHandler respHandler = new ResponseHandler (response, 1); @@ -81,7 +83,7 @@ public class ResponseHandlerTest { int status = respHandler.getStatus (); assertEquals (status, HttpStatus.SC_ACCEPTED); - assertTrue (respHandler.getResponseBody () != null); + assertTrue (respHandler.getContent() != null); } @Test @@ -100,17 +102,21 @@ public class ResponseHandlerTest { @Test public void tesGenricErrorResponse () throws JsonGenerationException, JsonMappingException, IOException { - String body = "{ \"response\": \"xml\"," + "\"messageCode\": 500," - + "\"message\": \"Something went wrong\"}"; + String content = "{\"WorkflowResponse\":{" + + "\"messageCode\":500" + + ",\"message\":\"Something went wrong\"" + + ",\"content\":\"xml\"" + + ",\"processInstanceId\":\"4d3b3201a7ce\"" + + "}}"; - HttpResponse response = createResponse (500, body, "application/json"); + HttpResponse response = createResponse (500, content, "application/json"); ResponseHandler respHandler = new ResponseHandler (response, 1); int status = respHandler.getStatus (); assertEquals (HttpStatus.SC_BAD_GATEWAY, status); assertEquals (respHandler.getResponse ().getMessage (), "Something went wrong"); - System.out.println (respHandler.getResponseBody ()); + System.out.println (respHandler.getContent()); } -- cgit 1.2.3-korg