1 package org.onap.so.apihandlerinfra;
3 import java.security.GeneralSecurityException;
4 import java.util.ArrayList;
5 import java.util.HashMap;
8 import javax.ws.rs.core.UriBuilder;
9 import javax.xml.bind.DatatypeConverter;
10 import org.camunda.bpm.engine.impl.persistence.entity.HistoricActivityInstanceEntity;
11 import org.camunda.bpm.engine.impl.persistence.entity.HistoricProcessInstanceEntity;
12 import org.json.JSONObject;
13 import org.onap.logging.filter.spring.SpringClientPayloadFilter;
14 import org.onap.so.logging.jaxrs.filter.SOSpringClientFilter;
15 import org.onap.so.utils.CryptoUtils;
16 import org.onap.so.apihandlerinfra.exceptions.ContactCamundaException;
17 import org.slf4j.Logger;
18 import org.slf4j.LoggerFactory;
19 import org.springframework.beans.factory.annotation.Autowired;
20 import org.springframework.core.ParameterizedTypeReference;
21 import org.springframework.core.env.Environment;
22 import org.springframework.http.HttpEntity;
23 import org.springframework.http.HttpHeaders;
24 import org.springframework.http.HttpMethod;
25 import org.springframework.http.ResponseEntity;
26 import org.springframework.http.client.BufferingClientHttpRequestFactory;
27 import org.springframework.http.client.HttpComponentsClientHttpRequestFactory;
28 import org.springframework.retry.policy.SimpleRetryPolicy;
29 import org.springframework.retry.support.RetryTemplate;
30 import org.springframework.stereotype.Component;
31 import org.springframework.web.client.ResourceAccessException;
32 import org.springframework.web.client.RestClientException;
33 import org.springframework.web.client.RestTemplate;
34 import org.springframework.web.reactive.function.BodyInserters;
35 import org.springframework.web.reactive.function.client.WebClient;
36 import reactor.core.publisher.Flux;
39 public class CamundaRequestHandler {
41 private static Logger logger = LoggerFactory.getLogger(CamundaRequestHandler.class);
42 private static final String TIMEOUT = "30000";
43 private static final String RETRY_TIMEOUT = "15000";
44 private static final String TIMEOUT_PROPERTY = "mso.camunda.request.timeout";
45 private static final String RETRY_TIMEOUT_PROPERTY = "mso.camunda.request.timeout.retry";
48 private Environment env;
50 private String buildCamundaUrlString(boolean historyLookup, boolean sort, boolean active, String lookupId) {
51 UriBuilder uriBuilder = UriBuilder.fromUri(env.getProperty("mso.camundaURL"));
53 uriBuilder.path(env.getProperty("mso.camunda.rest.history.uri"));
54 uriBuilder.queryParam("processInstanceBusinessKey", lookupId);
56 uriBuilder.queryParam("active", true);
59 uriBuilder.queryParam("sortBy", "startTime");
60 uriBuilder.queryParam("sortOrder", "desc");
63 uriBuilder.path(env.getProperty("mso.camunda.rest.activity.uri"));
64 uriBuilder.queryParam("processInstanceId", lookupId);
66 uriBuilder.queryParam("maxResults", 1);
67 return uriBuilder.build().toString();
70 public ResponseEntity<List<HistoricProcessInstanceEntity>> getCamundaProcessInstanceHistory(String requestId,
71 boolean retry, boolean activeOnly, boolean sort) {
72 String targetUrl = buildCamundaUrlString(true, sort, activeOnly, requestId);
74 setCamundaHeaders(env.getRequiredProperty("mso.camundaAuth"), env.getRequiredProperty("mso.msoKey"));
76 HttpEntity<?> requestEntity = new HttpEntity<>(headers);
79 RestTemplate restTemplate = getRestTemplate(retry);
80 RetryTemplate retryTemplate = getRetryTemplate();
81 return retryTemplate.execute(context -> {
82 if (context.getLastThrowable() != null) {
83 logger.error("Retrying: Last call resulted in exception: ", context.getLastThrowable());
85 if (context.getRetryCount() == 0) {
86 logger.info("Querying Camunda for process-instance history for requestId: {}", requestId);
89 "Retry: Querying Camunda for process-instance history for retryCount: {} and requestId: {}",
90 context.getRetryCount(), requestId);
92 return restTemplate.exchange(targetUrl, HttpMethod.GET, requestEntity,
93 new ParameterizedTypeReference<List<HistoricProcessInstanceEntity>>() {});
96 RestTemplate restTemplate = getRestTemplate(retry);
97 return restTemplate.exchange(targetUrl, HttpMethod.GET, requestEntity,
98 new ParameterizedTypeReference<List<HistoricProcessInstanceEntity>>() {});
102 protected ResponseEntity<List<HistoricActivityInstanceEntity>> getCamundaActivityHistory(String processInstanceId) {
103 RestTemplate restTemplate = getRestTemplate(false);
104 String targetUrl = buildCamundaUrlString(false, false, false, processInstanceId);
105 HttpHeaders headers =
106 setCamundaHeaders(env.getRequiredProperty("mso.camundaAuth"), env.getRequiredProperty("mso.msoKey"));
107 HttpEntity<?> requestEntity = new HttpEntity<>(headers);
109 return restTemplate.exchange(targetUrl, HttpMethod.GET, requestEntity,
110 new ParameterizedTypeReference<List<HistoricActivityInstanceEntity>>() {});
113 protected String getTaskName(String requestId) {
114 ResponseEntity<List<HistoricProcessInstanceEntity>> response = null;
116 String taskInformation = null;
118 response = getCamundaProcessInstanceHistory(requestId, false, false, true);
119 } catch (RestClientException e) {
120 logger.warn("Error querying Camunda for process-instance history for requestId: {}, exception: {}",
121 requestId, e.getMessage());
124 if (response != null) {
125 taskInformation = getTaskInformation(response, requestId);
127 return taskInformation;
130 protected String getTaskInformation(ResponseEntity<List<HistoricProcessInstanceEntity>> response,
132 List<HistoricProcessInstanceEntity> historicProcessInstanceList = response.getBody();
133 ResponseEntity<List<HistoricActivityInstanceEntity>> activityResponse = null;
134 String processInstanceId = null;
135 String taskInformation = null;
137 if (historicProcessInstanceList != null && !historicProcessInstanceList.isEmpty()) {
138 processInstanceId = historicProcessInstanceList.get(0).getId();
140 logger.warn("No processInstances returned for requestId: {} to get TaskInformation", requestId);
143 if (processInstanceId != null) {
145 activityResponse = getCamundaActivityHistory(processInstanceId);
146 } catch (RestClientException e) {
148 "Error querying Camunda for activity-instance history for processInstanceId: {}, for requestId: {}, exception: {}",
149 processInstanceId, requestId, e.getMessage());
152 logger.warn("No processInstanceId returned for requestId: {} to get TaskInformation", requestId);
155 if (activityResponse != null) {
156 taskInformation = getActivityName(activityResponse.getBody());
158 logger.warn("No activity history information returned for requestId: {} to get TaskInformation", requestId);
160 return taskInformation;
163 protected String getActivityName(List<HistoricActivityInstanceEntity> activityInstanceList) {
164 String activityName = null;
165 HistoricActivityInstanceEntity activityInstance = null;
166 String result = null;
168 if (activityInstanceList == null || activityInstanceList.isEmpty()) {
169 result = "No results returned on activityInstance history lookup.";
171 activityInstance = activityInstanceList.get(0);
172 activityName = activityInstance.getActivityName();
174 if (activityName == null) {
175 result = "Task name is null.";
177 result = "Last task executed: " + activityName;
184 protected HttpHeaders setCamundaHeaders(String auth, String msoKey) {
185 HttpHeaders headers = new HttpHeaders();
186 List<org.springframework.http.MediaType> acceptableMediaTypes = new ArrayList<>();
187 acceptableMediaTypes.add(org.springframework.http.MediaType.APPLICATION_JSON);
188 headers.setAccept(acceptableMediaTypes);
190 String userCredentials = CryptoUtils.decrypt(auth, msoKey);
191 if (userCredentials != null) {
192 headers.add(HttpHeaders.AUTHORIZATION,
193 "Basic " + DatatypeConverter.printBase64Binary(userCredentials.getBytes()));
195 } catch (GeneralSecurityException e) {
196 logger.error("Security exception", e);
201 protected RetryTemplate getRetryTemplate() {
202 RetryTemplate retryTemplate = new RetryTemplate();
203 Map<Class<? extends Throwable>, Boolean> retryableExceptions = new HashMap<>();
204 retryableExceptions.put(ResourceAccessException.class, true);
205 SimpleRetryPolicy policy = new SimpleRetryPolicy(2, retryableExceptions);
206 retryTemplate.setRetryPolicy(policy);
207 return retryTemplate;
210 protected void sendCamundaMessages(JSONObject msgJson) {
211 String url = env.getProperty("mso.camundaURL") + "/sobpmnengine/message";
212 HttpHeaders headers =
213 setCamundaHeaders(env.getRequiredProperty("mso.camundaAuth"), env.getRequiredProperty("mso.msoKey"));
214 headers.setContentType(org.springframework.http.MediaType.APPLICATION_JSON);
215 // Workflow may take a long time so use non-blocking request
216 Flux<String> flux = WebClient.create().post().uri(url).headers(httpHeaders -> {
217 httpHeaders.set(httpHeaders.AUTHORIZATION, headers.get(httpHeaders.AUTHORIZATION).get(0));
218 httpHeaders.set(httpHeaders.ACCEPT, headers.get(httpHeaders.ACCEPT).get(0));
219 httpHeaders.set(httpHeaders.CONTENT_TYPE, headers.get(httpHeaders.CONTENT_TYPE).get(0));
220 }).body(BodyInserters.fromObject(msgJson.toString())).retrieve().bodyToFlux(String.class);
221 flux.subscribe(res -> logger.debug("Send Camunda Message: " + res));
224 protected RestTemplate getRestTemplate(boolean retry) {
227 timeout = Integer.parseInt(env.getProperty(RETRY_TIMEOUT_PROPERTY, RETRY_TIMEOUT));
229 timeout = Integer.parseInt(env.getProperty(TIMEOUT_PROPERTY, TIMEOUT));
232 RestTemplate restTemplate = new RestTemplate();
233 HttpComponentsClientHttpRequestFactory factory = new HttpComponentsClientHttpRequestFactory();
234 factory.setConnectionRequestTimeout(timeout);
235 factory.setReadTimeout(timeout);
236 factory.setConnectTimeout(timeout);
237 restTemplate.setRequestFactory(new BufferingClientHttpRequestFactory(factory));
238 restTemplate.getInterceptors().add(new SOSpringClientFilter());
239 restTemplate.getInterceptors().add((new SpringClientPayloadFilter()));