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