f30b66c6b5b3189515fb9729becd229a9761c1dc
[so.git] /
1 package org.onap.so.apihandlerinfra;
2
3 import java.security.GeneralSecurityException;
4 import java.util.ArrayList;
5 import java.util.HashMap;
6 import java.util.List;
7 import java.util.Map;
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;
37
38 @Component
39 public class CamundaRequestHandler {
40
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";
46
47     @Autowired
48     private Environment env;
49
50     private String buildCamundaUrlString(boolean historyLookup, boolean sort, boolean active, String lookupId) {
51         UriBuilder uriBuilder = UriBuilder.fromUri(env.getProperty("mso.camundaURL"));
52         if (historyLookup) {
53             uriBuilder.path(env.getProperty("mso.camunda.rest.history.uri"));
54             uriBuilder.queryParam("processInstanceBusinessKey", lookupId);
55             if (active) {
56                 uriBuilder.queryParam("active", true);
57             }
58             if (sort) {
59                 uriBuilder.queryParam("sortBy", "startTime");
60                 uriBuilder.queryParam("sortOrder", "desc");
61             }
62         } else {
63             uriBuilder.path(env.getProperty("mso.camunda.rest.activity.uri"));
64             uriBuilder.queryParam("processInstanceId", lookupId);
65         }
66         uriBuilder.queryParam("maxResults", 1);
67         return uriBuilder.build().toString();
68     }
69
70     public ResponseEntity<List<HistoricProcessInstanceEntity>> getCamundaProcessInstanceHistory(String requestId,
71             boolean retry, boolean activeOnly, boolean sort) {
72         String targetUrl = buildCamundaUrlString(true, sort, activeOnly, requestId);
73         HttpHeaders headers =
74                 setCamundaHeaders(env.getRequiredProperty("mso.camundaAuth"), env.getRequiredProperty("mso.msoKey"));
75
76         HttpEntity<?> requestEntity = new HttpEntity<>(headers);
77
78         if (retry) {
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());
84                 }
85                 if (context.getRetryCount() == 0) {
86                     logger.info("Querying Camunda for process-instance history for requestId: {}", requestId);
87                 } else {
88                     logger.info(
89                             "Retry: Querying Camunda for process-instance history for retryCount: {} and requestId: {}",
90                             context.getRetryCount(), requestId);
91                 }
92                 return restTemplate.exchange(targetUrl, HttpMethod.GET, requestEntity,
93                         new ParameterizedTypeReference<List<HistoricProcessInstanceEntity>>() {});
94             });
95         } else {
96             RestTemplate restTemplate = getRestTemplate(retry);
97             return restTemplate.exchange(targetUrl, HttpMethod.GET, requestEntity,
98                     new ParameterizedTypeReference<List<HistoricProcessInstanceEntity>>() {});
99         }
100     }
101
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);
108
109         return restTemplate.exchange(targetUrl, HttpMethod.GET, requestEntity,
110                 new ParameterizedTypeReference<List<HistoricActivityInstanceEntity>>() {});
111     }
112
113     protected String getTaskName(String requestId) {
114         ResponseEntity<List<HistoricProcessInstanceEntity>> response = null;
115
116         String taskInformation = null;
117         try {
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());
122         }
123
124         if (response != null) {
125             taskInformation = getTaskInformation(response, requestId);
126         }
127         return taskInformation;
128     }
129
130     protected String getTaskInformation(ResponseEntity<List<HistoricProcessInstanceEntity>> response,
131             String requestId) {
132         List<HistoricProcessInstanceEntity> historicProcessInstanceList = response.getBody();
133         ResponseEntity<List<HistoricActivityInstanceEntity>> activityResponse = null;
134         String processInstanceId = null;
135         String taskInformation = null;
136
137         if (historicProcessInstanceList != null && !historicProcessInstanceList.isEmpty()) {
138             processInstanceId = historicProcessInstanceList.get(0).getId();
139         } else {
140             logger.warn("No processInstances returned for requestId: {} to get TaskInformation", requestId);
141         }
142
143         if (processInstanceId != null) {
144             try {
145                 activityResponse = getCamundaActivityHistory(processInstanceId);
146             } catch (RestClientException e) {
147                 logger.warn(
148                         "Error querying Camunda for activity-instance history for processInstanceId: {}, for requestId: {}, exception: {}",
149                         processInstanceId, requestId, e.getMessage());
150             }
151         } else {
152             logger.warn("No processInstanceId returned for requestId: {} to get TaskInformation", requestId);
153         }
154
155         if (activityResponse != null) {
156             taskInformation = getActivityName(activityResponse.getBody());
157         } else {
158             logger.warn("No activity history information returned for requestId: {} to get TaskInformation", requestId);
159         }
160         return taskInformation;
161     }
162
163     protected String getActivityName(List<HistoricActivityInstanceEntity> activityInstanceList) {
164         String activityName = null;
165         HistoricActivityInstanceEntity activityInstance = null;
166         String result = null;
167
168         if (activityInstanceList == null || activityInstanceList.isEmpty()) {
169             result = "No results returned on activityInstance history lookup.";
170         } else {
171             activityInstance = activityInstanceList.get(0);
172             activityName = activityInstance.getActivityName();
173
174             if (activityName == null) {
175                 result = "Task name is null.";
176             } else {
177                 result = "Last task executed: " + activityName;
178             }
179         }
180
181         return result;
182     }
183
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);
189         try {
190             String userCredentials = CryptoUtils.decrypt(auth, msoKey);
191             if (userCredentials != null) {
192                 headers.add(HttpHeaders.AUTHORIZATION,
193                         "Basic " + DatatypeConverter.printBase64Binary(userCredentials.getBytes()));
194             }
195         } catch (GeneralSecurityException e) {
196             logger.error("Security exception", e);
197         }
198         return headers;
199     }
200
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;
208     }
209
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));
222     }
223
224     protected RestTemplate getRestTemplate(boolean retry) {
225         int timeout;
226         if (retry) {
227             timeout = Integer.parseInt(env.getProperty(RETRY_TIMEOUT_PROPERTY, RETRY_TIMEOUT));
228         } else {
229             timeout = Integer.parseInt(env.getProperty(TIMEOUT_PROPERTY, TIMEOUT));
230         }
231
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()));
240         return restTemplate;
241     }
242 }