From e58d8dd892f1839514bd4b29756ee552c3f169ca Mon Sep 17 00:00:00 2001 From: "Plummer, Brittany" Date: Mon, 22 Jul 2019 08:44:15 -0500 Subject: enhance get orchestration request Enhance get orchestration request to include workflow step Began working on adding call for activity name Added call to return activity information Updated to return last task executed Added last task executed info to returned string Updated mocks to fix failing unit tests Added responses for mocks to Camunda for process and activity history Added tests to cover taskName changes Began adding tests to cover changes to RequestHandlerUtils Added more unit tests for activity lookup Updated error messages for taskName Moved properties to application.yaml file Added unit tests to add more coverage to task retrieval Moved Camunda calls to CamundaRequestHandler class Removed unused imports from RequestHandlerUtils Fixed formatting of tests and removed handler where not used Removed CamundaRequestHandler from JerseyConfiguration Added retryTemplate for camunda calls Issue-ID: SO-2142 Signed-off-by: Benjamin, Max (mb388a) Change-Id: I09a82e3458e8f611e4bbaf3ce9ab5de36b1b060a --- .../so/apihandlerinfra/CamundaRequestHandler.java | 180 +++++++++++++++++++++ .../so/apihandlerinfra/OrchestrationRequests.java | 15 +- .../so/apihandlerinfra/RequestHandlerUtils.java | 49 ++---- .../src/main/resources/application.yaml | 4 + 4 files changed, 208 insertions(+), 40 deletions(-) create mode 100644 mso-api-handlers/mso-api-handler-infra/src/main/java/org/onap/so/apihandlerinfra/CamundaRequestHandler.java (limited to 'mso-api-handlers/mso-api-handler-infra/src/main') diff --git a/mso-api-handlers/mso-api-handler-infra/src/main/java/org/onap/so/apihandlerinfra/CamundaRequestHandler.java b/mso-api-handlers/mso-api-handler-infra/src/main/java/org/onap/so/apihandlerinfra/CamundaRequestHandler.java new file mode 100644 index 0000000000..451fa64585 --- /dev/null +++ b/mso-api-handlers/mso-api-handler-infra/src/main/java/org/onap/so/apihandlerinfra/CamundaRequestHandler.java @@ -0,0 +1,180 @@ +package org.onap.so.apihandlerinfra; + +import java.security.GeneralSecurityException; +import java.util.ArrayList; +import java.util.Collections; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import javax.xml.bind.DatatypeConverter; +import org.apache.http.HttpStatus; +import org.camunda.bpm.engine.impl.persistence.entity.HistoricActivityInstanceEntity; +import org.camunda.bpm.engine.impl.persistence.entity.HistoricProcessInstanceEntity; +import org.onap.so.apihandler.common.ErrorNumbers; +import org.onap.so.apihandlerinfra.exceptions.ContactCamundaException; +import org.onap.so.utils.CryptoUtils; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.core.ParameterizedTypeReference; +import org.springframework.core.env.Environment; +import org.springframework.http.HttpEntity; +import org.springframework.http.HttpHeaders; +import org.springframework.http.HttpMethod; +import org.springframework.http.ResponseEntity; +import org.springframework.retry.policy.SimpleRetryPolicy; +import org.springframework.retry.support.RetryTemplate; +import org.springframework.stereotype.Component; +import org.springframework.web.client.ResourceAccessException; +import org.springframework.web.client.RestClientException; +import org.springframework.web.client.RestTemplate; + +@Component +public class CamundaRequestHandler { + + private static Logger logger = LoggerFactory.getLogger(CamundaRequestHandler.class); + + @Autowired + private RestTemplate restTemplate; + + @Autowired + private Environment env; + + public ResponseEntity> getCamundaProcessInstanceHistory(String requestId) { + RetryTemplate retryTemplate = setRetryTemplate(); + String path = env.getProperty("mso.camunda.rest.history.uri") + requestId; + String targetUrl = env.getProperty("mso.camundaURL") + path; + HttpHeaders headers = + setCamundaHeaders(env.getRequiredProperty("mso.camundaAuth"), env.getRequiredProperty("mso.msoKey")); + + HttpEntity requestEntity = new HttpEntity<>(headers); + + return retryTemplate.execute(context -> { + if (context.getLastThrowable() != null) { + logger.error("Retrying: Last call resulted in exception: ", context.getLastThrowable()); + } + if (context.getRetryCount() == 0) { + logger.info("Querying Camunda for process-instance history for requestId: {}", requestId); + } else { + logger.info("Retry: {} of 3. Querying Camunda for process-instance history for requestId: {}", + context.getRetryCount(), requestId); + } + return restTemplate.exchange(targetUrl, HttpMethod.GET, requestEntity, + new ParameterizedTypeReference>() {}); + }); + } + + protected ResponseEntity> getCamundaActivityHistory(String processInstanceId, + String requestId) throws ContactCamundaException { + RetryTemplate retryTemplate = setRetryTemplate(); + String path = env.getProperty("mso.camunda.rest.activity.uri") + processInstanceId; + String targetUrl = env.getProperty("mso.camundaURL") + path; + HttpHeaders headers = + setCamundaHeaders(env.getRequiredProperty("mso.camundaAuth"), env.getRequiredProperty("mso.msoKey")); + HttpEntity requestEntity = new HttpEntity<>(headers); + try { + return retryTemplate.execute(context -> { + if (context.getLastThrowable() != null) { + logger.error("Retrying: Last call resulted in exception: ", context.getLastThrowable()); + } + if (context.getRetryCount() == 0) { + logger.info( + "Querying Camunda for activity-instance history for processInstanceId: {}, for requestId: {}", + processInstanceId, requestId); + } else { + logger.info( + "Retry: {} of 3. Querying Camunda for activity-instance history for processInstanceId: {}, for requestId: {}", + context.getRetryCount(), processInstanceId, requestId); + } + + return restTemplate.exchange(targetUrl, HttpMethod.GET, requestEntity, + new ParameterizedTypeReference>() {}); + }); + + } catch (RestClientException e) { + logger.error( + "Error querying Camunda for activity-instance history for processInstanceId: {}, for requestId: {}, exception: {}", + processInstanceId, requestId, e.getMessage()); + throw new ContactCamundaException.Builder("activity-instance", requestId, e.toString(), + HttpStatus.SC_INTERNAL_SERVER_ERROR, ErrorNumbers.SVC_DETAILED_SERVICE_ERROR).cause(e).build(); + } + } + + protected String getTaskName(String requestId) throws ContactCamundaException { + ResponseEntity> response = null; + ResponseEntity> activityResponse = null; + String processInstanceId = null; + try { + response = getCamundaProcessInstanceHistory(requestId); + } catch (RestClientException e) { + logger.error("Error querying Camunda for process-instance history for requestId: {}, exception: {}", + requestId, e.getMessage()); + throw new ContactCamundaException.Builder("process-instance", requestId, e.toString(), + HttpStatus.SC_INTERNAL_SERVER_ERROR, ErrorNumbers.SVC_DETAILED_SERVICE_ERROR).cause(e).build(); + } + + List historicProcessInstanceList = response.getBody(); + + if (historicProcessInstanceList != null) { + Collections.reverse(historicProcessInstanceList); + processInstanceId = historicProcessInstanceList.get(0).getId(); + } else { + return "No processInstances returned for requestId: " + requestId; + } + + if (processInstanceId != null) { + activityResponse = getCamundaActivityHistory(processInstanceId, requestId); + } else { + return "No processInstanceId returned for requestId: " + requestId; + } + + return getActivityName(activityResponse.getBody()); + } + + protected String getActivityName(List activityInstanceList) { + String activityName = null; + HistoricActivityInstanceEntity activityInstance = null; + String result = null; + + if (activityInstanceList == null || activityInstanceList.isEmpty()) { + result = "No results returned on activityInstance history lookup."; + } else { + activityInstance = activityInstanceList.get(0); + activityName = activityInstance.getActivityName(); + + if (activityName == null) { + result = "Task name is null."; + } else { + result = "Last task executed: " + activityName; + } + } + + return result; + } + + protected HttpHeaders setCamundaHeaders(String auth, String msoKey) { + HttpHeaders headers = new HttpHeaders(); + List acceptableMediaTypes = new ArrayList<>(); + acceptableMediaTypes.add(org.springframework.http.MediaType.APPLICATION_JSON); + headers.setAccept(acceptableMediaTypes); + try { + String userCredentials = CryptoUtils.decrypt(auth, msoKey); + if (userCredentials != null) { + headers.add(HttpHeaders.AUTHORIZATION, + "Basic " + DatatypeConverter.printBase64Binary(userCredentials.getBytes())); + } + } catch (GeneralSecurityException e) { + logger.error("Security exception", e); + } + return headers; + } + + protected RetryTemplate setRetryTemplate() { + RetryTemplate retryTemplate = new RetryTemplate(); + Map, Boolean> retryableExceptions = new HashMap<>(); + retryableExceptions.put(ResourceAccessException.class, true); + SimpleRetryPolicy policy = new SimpleRetryPolicy(4, retryableExceptions); + retryTemplate.setRetryPolicy(policy); + return retryTemplate; + } +} diff --git a/mso-api-handlers/mso-api-handler-infra/src/main/java/org/onap/so/apihandlerinfra/OrchestrationRequests.java b/mso-api-handlers/mso-api-handler-infra/src/main/java/org/onap/so/apihandlerinfra/OrchestrationRequests.java index 9e92c293bf..6f36fb2aff 100644 --- a/mso-api-handlers/mso-api-handler-infra/src/main/java/org/onap/so/apihandlerinfra/OrchestrationRequests.java +++ b/mso-api-handlers/mso-api-handler-infra/src/main/java/org/onap/so/apihandlerinfra/OrchestrationRequests.java @@ -46,6 +46,7 @@ import org.apache.http.HttpStatus; import org.onap.so.apihandler.common.ErrorNumbers; import org.onap.so.apihandler.common.ResponseBuilder; import org.onap.so.apihandlerinfra.exceptions.ApiException; +import org.onap.so.apihandlerinfra.exceptions.ContactCamundaException; import org.onap.so.apihandlerinfra.exceptions.ValidateException; import org.onap.so.apihandlerinfra.logging.ErrorLoggerInfo; import org.onap.so.constants.OrchestrationRequestFormat; @@ -91,6 +92,9 @@ public class OrchestrationRequests { @Autowired private ResponseBuilder builder; + @Autowired + private CamundaRequestHandler camundaRequestHandler; + @GET @Path("/{version:[vV][4-7]}/{requestId}") @ApiOperation(value = "Find Orchestrated Requests for a given requestId", response = Response.class) @@ -424,10 +428,19 @@ public class OrchestrationRequests { } protected void mapRequestStatusAndExtSysErrSrcToRequest(InfraActiveRequests iar, RequestStatus status, - String format) { + String format) throws ContactCamundaException { String rollbackStatusMessage = iar.getRollbackStatusMessage(); String flowStatusMessage = iar.getFlowStatus(); String retryStatusMessage = iar.getRetryStatusMessage(); + String taskName = null; + + if (flowStatusMessage != null && !flowStatusMessage.equals("Successfully completed all Building Blocks") + && !flowStatusMessage.equals("All Rollback flows have completed successfully")) { + taskName = camundaRequestHandler.getTaskName(iar.getRequestId()); + if (taskName != null) { + flowStatusMessage = flowStatusMessage + " TASK INFORMATION: " + taskName; + } + } String statusMessages = null; if (iar.getStatusMessage() != null) { diff --git a/mso-api-handlers/mso-api-handler-infra/src/main/java/org/onap/so/apihandlerinfra/RequestHandlerUtils.java b/mso-api-handlers/mso-api-handler-infra/src/main/java/org/onap/so/apihandlerinfra/RequestHandlerUtils.java index c3f323459c..9ab95a2319 100644 --- a/mso-api-handlers/mso-api-handler-infra/src/main/java/org/onap/so/apihandlerinfra/RequestHandlerUtils.java +++ b/mso-api-handlers/mso-api-handler-infra/src/main/java/org/onap/so/apihandlerinfra/RequestHandlerUtils.java @@ -27,7 +27,6 @@ package org.onap.so.apihandlerinfra; import static org.onap.so.logger.HttpHeadersConstants.REQUESTOR_ID; import java.io.IOException; import java.net.URL; -import java.security.GeneralSecurityException; import java.sql.Timestamp; import java.util.ArrayList; import java.util.HashMap; @@ -37,7 +36,6 @@ import java.util.Optional; import javax.ws.rs.container.ContainerRequestContext; import javax.ws.rs.core.MultivaluedMap; import javax.ws.rs.core.Response; -import javax.xml.bind.DatatypeConverter; import org.apache.commons.lang.StringUtils; import org.apache.http.HttpResponse; import org.apache.http.HttpStatus; @@ -78,21 +76,16 @@ import org.onap.so.serviceinstancebeans.RelatedInstanceList; import org.onap.so.serviceinstancebeans.RequestParameters; import org.onap.so.serviceinstancebeans.ServiceInstancesRequest; import org.onap.so.serviceinstancebeans.ServiceInstancesResponse; -import org.onap.so.utils.CryptoUtils; import org.onap.so.utils.UUIDChecker; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.slf4j.MDC; import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.core.ParameterizedTypeReference; import org.springframework.core.env.Environment; -import org.springframework.http.HttpEntity; -import org.springframework.http.HttpHeaders; -import org.springframework.http.HttpMethod; import org.springframework.http.ResponseEntity; import org.springframework.stereotype.Component; import org.springframework.web.client.HttpStatusCodeException; -import org.springframework.web.client.RestTemplate; +import org.springframework.web.client.RestClientException; import com.fasterxml.jackson.annotation.JsonInclude.Include; import com.fasterxml.jackson.databind.ObjectMapper; @@ -119,7 +112,7 @@ public class RequestHandlerUtils extends AbstractRestHandler { private MsoRequest msoRequest; @Autowired - private RestTemplate restTemplate; + private CamundaRequestHandler camundaRequestHandler; @Autowired private CatalogDbClient catalogDbClient; @@ -323,25 +316,20 @@ public class RequestHandlerUtils extends AbstractRestHandler { public boolean camundaHistoryCheck(InfraActiveRequests duplicateRecord, InfraActiveRequests currentActiveReq) throws RequestDbFailureException, ContactCamundaException { String requestId = duplicateRecord.getRequestId(); - String path = env.getProperty("mso.camunda.rest.history.uri") + requestId; - String targetUrl = env.getProperty("mso.camundaURL") + path; - HttpHeaders headers = - setCamundaHeaders(env.getRequiredProperty("mso.camundaAuth"), env.getRequiredProperty("mso.msoKey")); - HttpEntity requestEntity = new HttpEntity<>(headers); ResponseEntity> response = null; try { - response = restTemplate.exchange(targetUrl, HttpMethod.GET, requestEntity, - new ParameterizedTypeReference>() {}); - } catch (HttpStatusCodeException e) { - ErrorLoggerInfo errorLoggerInfo = - new ErrorLoggerInfo.Builder(MessageEnum.APIH_DUPLICATE_CHECK_EXC, ErrorCode.DataError) - .errorSource(Constants.MSO_PROP_APIHANDLER_INFRA).build(); + response = camundaRequestHandler.getCamundaProcessInstanceHistory(requestId); + } catch (RestClientException e) { + logger.error("Error querying Camunda for process-instance history for requestId: {}, exception: {}", + requestId, e.getMessage()); ContactCamundaException contactCamundaException = - new ContactCamundaException.Builder(requestId, e.toString(), HttpStatus.SC_INTERNAL_SERVER_ERROR, - ErrorNumbers.SVC_DETAILED_SERVICE_ERROR).cause(e).errorInfo(errorLoggerInfo).build(); + new ContactCamundaException.Builder("process-instance", requestId, e.toString(), + HttpStatus.SC_INTERNAL_SERVER_ERROR, ErrorNumbers.SVC_DETAILED_SERVICE_ERROR).cause(e) + .build(); updateStatus(currentActiveReq, Status.FAILED, contactCamundaException.getMessage()); throw contactCamundaException; } + if (response.getBody().isEmpty()) { updateStatus(duplicateRecord, Status.COMPLETE, "Request Completed"); } @@ -355,23 +343,6 @@ public class RequestHandlerUtils extends AbstractRestHandler { return false; } - protected HttpHeaders setCamundaHeaders(String auth, String msoKey) { - HttpHeaders headers = new HttpHeaders(); - List acceptableMediaTypes = new ArrayList<>(); - acceptableMediaTypes.add(org.springframework.http.MediaType.APPLICATION_JSON); - headers.setAccept(acceptableMediaTypes); - try { - String userCredentials = CryptoUtils.decrypt(auth, msoKey); - if (userCredentials != null) { - headers.add(HttpHeaders.AUTHORIZATION, - "Basic " + DatatypeConverter.printBase64Binary(userCredentials.getBytes())); - } - } catch (GeneralSecurityException e) { - logger.error("Security exception", e); - } - return headers; - } - public ServiceInstancesRequest convertJsonToServiceInstanceRequest(String requestJSON, Actions action, String requestId, String requestUri) throws ApiException { try { diff --git a/mso-api-handlers/mso-api-handler-infra/src/main/resources/application.yaml b/mso-api-handlers/mso-api-handler-infra/src/main/resources/application.yaml index 136acfb9e1..93a4ae9489 100644 --- a/mso-api-handlers/mso-api-handler-infra/src/main/resources/application.yaml +++ b/mso-api-handlers/mso-api-handler-infra/src/main/resources/application.yaml @@ -26,6 +26,10 @@ mso: uri: /sobpmnengine/task history: uri: /sobpmnengine/history/process-instance?variables=mso-request-id_eq_ + activity: + uri: /sobpmnengine/history/activity-instance?processInstanceId= + camundaURL: http://localhost:8089 + camundaAuth: E8E19DD16CC90D2E458E8FF9A884CC0452F8F3EB8E321F96038DE38D5C1B0B02DFAE00B88E2CF6E2A4101AB2C011FC161212EE spring: datasource: -- cgit 1.2.3-korg