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.slf4j.Logger;
17 import org.slf4j.LoggerFactory;
18 import org.springframework.beans.factory.annotation.Autowired;
19 import org.springframework.core.ParameterizedTypeReference;
20 import org.springframework.core.env.Environment;
21 import org.springframework.http.HttpEntity;
22 import org.springframework.http.HttpHeaders;
23 import org.springframework.http.HttpMethod;
24 import org.springframework.http.ResponseEntity;
25 import org.springframework.http.client.BufferingClientHttpRequestFactory;
26 import org.springframework.http.client.HttpComponentsClientHttpRequestFactory;
27 import org.springframework.retry.policy.SimpleRetryPolicy;
28 import org.springframework.retry.support.RetryTemplate;
29 import org.springframework.stereotype.Component;
30 import org.springframework.web.client.ResourceAccessException;
31 import org.springframework.web.client.RestClientException;
32 import org.springframework.web.client.RestTemplate;
33 import org.springframework.web.reactive.function.BodyInserters;
34 import org.springframework.web.reactive.function.client.WebClient;
35 import reactor.core.publisher.Flux;
38 public class CamundaRequestHandler {
40 private static Logger logger = LoggerFactory.getLogger(CamundaRequestHandler.class);
41 private static final String TIMEOUT = "30000";
42 private static final String RETRY_TIMEOUT = "15000";
43 private static final String TIMEOUT_PROPERTY = "mso.camunda.request.timeout";
44 private static final String RETRY_TIMEOUT_PROPERTY = "mso.camunda.request.timeout.retry";
47 private Environment env;
49 private String buildCamundaUrlString(boolean historyLookup, boolean sort, boolean active, String lookupId) {
50 UriBuilder uriBuilder = UriBuilder.fromUri(env.getProperty("mso.camundaURL"));
52 uriBuilder.path(env.getProperty("mso.camunda.rest.history.uri"));
53 uriBuilder.queryParam("processInstanceBusinessKey", lookupId);
55 uriBuilder.queryParam("active", true);
58 uriBuilder.queryParam("sortBy", "startTime");
59 uriBuilder.queryParam("sortOrder", "desc");
62 uriBuilder.path(env.getProperty("mso.camunda.rest.activity.uri"));
63 uriBuilder.queryParam("processInstanceId", lookupId);
65 uriBuilder.queryParam("maxResults", 1);
66 return uriBuilder.build().toString();
69 public ResponseEntity<List<HistoricProcessInstanceEntity>> getCamundaProcessInstanceHistory(String requestId,
70 boolean retry, boolean activeOnly, boolean sort) {
71 String targetUrl = buildCamundaUrlString(true, sort, activeOnly, requestId);
73 setCamundaHeaders(env.getRequiredProperty("mso.camundaAuth"), env.getRequiredProperty("mso.msoKey"));
75 HttpEntity<?> requestEntity = new HttpEntity<>(headers);
78 RestTemplate restTemplate = getRestTemplate(retry);
79 RetryTemplate retryTemplate = getRetryTemplate();
80 return retryTemplate.execute(context -> {
81 if (context.getLastThrowable() != null) {
82 logger.error("Retrying: Last call resulted in exception: ", context.getLastThrowable());
84 if (context.getRetryCount() == 0) {
85 logger.info("Querying Camunda for process-instance history for requestId: {}", requestId);
88 "Retry: Querying Camunda for process-instance history for retryCount: {} and requestId: {}",
89 context.getRetryCount(), requestId);
91 return restTemplate.exchange(targetUrl, HttpMethod.GET, requestEntity,
92 new ParameterizedTypeReference<List<HistoricProcessInstanceEntity>>() {});
95 RestTemplate restTemplate = getRestTemplate(retry);
96 return restTemplate.exchange(targetUrl, HttpMethod.GET, requestEntity,
97 new ParameterizedTypeReference<List<HistoricProcessInstanceEntity>>() {});
101 protected ResponseEntity<List<HistoricActivityInstanceEntity>> getCamundaActivityHistory(String processInstanceId) {
102 RestTemplate restTemplate = getRestTemplate(false);
103 String targetUrl = buildCamundaUrlString(false, false, false, processInstanceId);
104 HttpHeaders headers =
105 setCamundaHeaders(env.getRequiredProperty("mso.camundaAuth"), env.getRequiredProperty("mso.msoKey"));
106 HttpEntity<?> requestEntity = new HttpEntity<>(headers);
108 return restTemplate.exchange(targetUrl, HttpMethod.GET, requestEntity,
109 new ParameterizedTypeReference<List<HistoricActivityInstanceEntity>>() {});
112 protected String getTaskName(String requestId) {
113 ResponseEntity<List<HistoricProcessInstanceEntity>> response = null;
115 String taskInformation = null;
117 response = getCamundaProcessInstanceHistory(requestId, false, false, true);
118 } catch (RestClientException e) {
119 logger.warn("Error querying Camunda for process-instance history for requestId: {}, exception: {}",
120 requestId, e.getMessage());
123 if (response != null) {
124 taskInformation = getTaskInformation(response, requestId);
126 return taskInformation;
129 protected String getTaskInformation(ResponseEntity<List<HistoricProcessInstanceEntity>> response,
131 List<HistoricProcessInstanceEntity> historicProcessInstanceList = response.getBody();
132 ResponseEntity<List<HistoricActivityInstanceEntity>> activityResponse = null;
133 String processInstanceId = null;
134 String taskInformation = null;
136 if (historicProcessInstanceList != null && !historicProcessInstanceList.isEmpty()) {
137 processInstanceId = historicProcessInstanceList.get(0).getId();
139 logger.warn("No processInstances returned for requestId: {} to get TaskInformation", requestId);
142 if (processInstanceId != null) {
144 activityResponse = getCamundaActivityHistory(processInstanceId);
145 } catch (RestClientException e) {
147 "Error querying Camunda for activity-instance history for processInstanceId: {}, for requestId: {}, exception: {}",
148 processInstanceId, requestId, e.getMessage());
151 logger.warn("No processInstanceId returned for requestId: {} to get TaskInformation", requestId);
154 if (activityResponse != null) {
155 taskInformation = getActivityName(activityResponse.getBody());
157 logger.warn("No activity history information returned for requestId: {} to get TaskInformation", requestId);
159 return taskInformation;
162 protected String getActivityName(List<HistoricActivityInstanceEntity> activityInstanceList) {
163 String activityName = null;
164 HistoricActivityInstanceEntity activityInstance = null;
165 String result = null;
167 if (activityInstanceList == null || activityInstanceList.isEmpty()) {
168 result = "No results returned on activityInstance history lookup.";
170 activityInstance = activityInstanceList.get(0);
171 activityName = activityInstance.getActivityName();
173 if (activityName == null) {
174 result = "Task name is null.";
176 result = "Last task executed: " + activityName;
183 protected HttpHeaders setCamundaHeaders(String auth, String msoKey) {
184 HttpHeaders headers = new HttpHeaders();
185 List<org.springframework.http.MediaType> acceptableMediaTypes = new ArrayList<>();
186 acceptableMediaTypes.add(org.springframework.http.MediaType.APPLICATION_JSON);
187 headers.setAccept(acceptableMediaTypes);
189 String userCredentials = CryptoUtils.decrypt(auth, msoKey);
190 if (userCredentials != null) {
191 headers.add(HttpHeaders.AUTHORIZATION,
192 "Basic " + DatatypeConverter.printBase64Binary(userCredentials.getBytes()));
194 } catch (GeneralSecurityException e) {
195 logger.error("Security exception", e);
200 protected RetryTemplate getRetryTemplate() {
201 RetryTemplate retryTemplate = new RetryTemplate();
202 Map<Class<? extends Throwable>, Boolean> retryableExceptions = new HashMap<>();
203 retryableExceptions.put(ResourceAccessException.class, true);
204 SimpleRetryPolicy policy = new SimpleRetryPolicy(2, retryableExceptions);
205 retryTemplate.setRetryPolicy(policy);
206 return retryTemplate;
209 protected void sendCamundaMessages(JSONObject msgJson) {
210 String url = env.getProperty("mso.camundaURL") + "/sobpmnengine/message";
211 HttpHeaders headers =
212 setCamundaHeaders(env.getRequiredProperty("mso.camundaAuth"), env.getRequiredProperty("mso.msoKey"));
213 headers.setContentType(org.springframework.http.MediaType.APPLICATION_JSON);
214 // Workflow may take a long time so use non-blocking request
215 Flux<String> flux = WebClient.create().post().uri(url).headers(httpHeaders -> {
216 httpHeaders.set(httpHeaders.AUTHORIZATION, headers.get(httpHeaders.AUTHORIZATION).get(0));
217 httpHeaders.set(httpHeaders.ACCEPT, headers.get(httpHeaders.ACCEPT).get(0));
218 httpHeaders.set(httpHeaders.CONTENT_TYPE, headers.get(httpHeaders.CONTENT_TYPE).get(0));
219 }).body(BodyInserters.fromObject(msgJson.toString())).retrieve().bodyToFlux(String.class);
220 flux.subscribe(res -> logger.debug("Send Camunda Message: " + res));
223 protected RestTemplate getRestTemplate(boolean retry) {
226 timeout = Integer.parseInt(env.getProperty(RETRY_TIMEOUT_PROPERTY, RETRY_TIMEOUT));
228 timeout = Integer.parseInt(env.getProperty(TIMEOUT_PROPERTY, TIMEOUT));
231 RestTemplate restTemplate = new RestTemplate();
232 HttpComponentsClientHttpRequestFactory factory = new HttpComponentsClientHttpRequestFactory();
233 factory.setConnectionRequestTimeout(timeout);
234 factory.setReadTimeout(timeout);
235 factory.setConnectTimeout(timeout);
236 restTemplate.setRequestFactory(new BufferingClientHttpRequestFactory(factory));
237 restTemplate.getInterceptors().add(new SOSpringClientFilter());
238 restTemplate.getInterceptors().add((new SpringClientPayloadFilter()));