Format Java code with respect to ONAP Code Style
[externalapi/nbi.git] / src / main / java / org / onap / nbi / apis / serviceorder / workflow / SOTaskProcessor.java
1 /**
2  * Copyright (c) 2018 Orange
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with
5  * the License. You may obtain a copy of the License at
6  *
7  * http://www.apache.org/licenses/LICENSE-2.0
8  *
9  * Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on
10  * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the
11  * specific language governing permissions and limitations under the License.
12  */
13
14 package org.onap.nbi.apis.serviceorder.workflow;
15
16 import java.io.IOException;
17 import java.util.ArrayList;
18 import java.util.Arrays;
19 import java.util.Date;
20 import java.util.List;
21 import java.util.Optional;
22 import org.onap.nbi.apis.serviceorder.model.ActionType;
23 import org.onap.nbi.apis.serviceorder.model.ServiceOrder;
24 import org.onap.nbi.apis.serviceorder.model.ServiceOrderItem;
25 import org.onap.nbi.apis.serviceorder.model.StateType;
26 import org.onap.nbi.apis.serviceorder.model.consumer.CreateE2EServiceInstanceResponse;
27 import org.onap.nbi.apis.serviceorder.model.consumer.CreateServiceInstanceResponse;
28 import org.onap.nbi.apis.serviceorder.model.orchestrator.ExecutionTask;
29 import org.onap.nbi.apis.serviceorder.model.orchestrator.ServiceOrderInfo;
30 import org.onap.nbi.apis.serviceorder.repositories.ExecutionTaskRepository;
31 import org.onap.nbi.apis.serviceorder.service.ServiceOrderService;
32 import org.onap.nbi.apis.serviceorder.utils.E2EServiceUtils;
33 import org.onap.nbi.apis.serviceorder.utils.JsonEntityConverter;
34 import org.onap.nbi.exceptions.TechnicalException;
35 import org.slf4j.Logger;
36 import org.slf4j.LoggerFactory;
37 import org.springframework.beans.factory.annotation.Autowired;
38 import org.springframework.beans.factory.annotation.Value;
39 import org.springframework.http.HttpStatus;
40 import org.springframework.http.ResponseEntity;
41 import org.springframework.stereotype.Service;
42 import org.springframework.util.CollectionUtils;
43
44 @Service
45 public class SOTaskProcessor {
46
47     @Autowired
48     private ServiceOrderService serviceOrderService;
49
50     @Autowired
51     private ExecutionTaskRepository executionTaskRepository;
52
53     @Autowired
54     private PostSoProcessor postSoProcessor;
55
56     @Autowired
57     private SOGetStatusManager sOGetStatusManager;
58
59     @Value("${scheduler.pollingDurationInMins}")
60     private float pollingDurationInMins;
61
62     private static final Logger LOGGER = LoggerFactory.getLogger(SOTaskProcessor.class);
63
64     /**
65      * Run the ServiceOrchestrator processing for a serviceOrderItem which with any sub relations
66      */
67     public void processOrderItem(ExecutionTask executionTask) {
68
69         executionTask.setLastAttemptDate(new Date());
70         executionTaskRepository.save(executionTask);
71
72         ServiceOrderInfo serviceOrderInfo = getServiceOrderInfo(executionTask);
73
74         Optional<ServiceOrder> optionalServiceOrder =
75                 serviceOrderService.findServiceOrderById(serviceOrderInfo.getServiceOrderId());
76         if (!optionalServiceOrder.isPresent()) {
77             throw new TechnicalException(
78                     "Unable to retrieve service order for id " + serviceOrderInfo.getServiceOrderId());
79         }
80         ServiceOrder serviceOrder = optionalServiceOrder.get();
81         ServiceOrderItem serviceOrderItem = getServiceOrderItem(executionTask, serviceOrder);
82         boolean e2eService =
83                 E2EServiceUtils.isE2EService(serviceOrderInfo.getServiceOrderItemInfos().get(serviceOrderItem.getId()));
84
85         if (shouldPostSo(serviceOrderItem)) {
86             if (e2eService) {
87                 ResponseEntity<CreateE2EServiceInstanceResponse> response =
88                         postSoProcessor.postE2EServiceOrderItem(serviceOrderInfo, serviceOrderItem, serviceOrder);
89                 updateE2EServiceOrderItem(response, serviceOrderItem, serviceOrder);
90             } else {
91
92                 ResponseEntity<CreateServiceInstanceResponse> response =
93                         postSoProcessor.postServiceOrderItem(serviceOrderInfo, serviceOrderItem);
94                 updateServiceOrderItem(response, serviceOrderItem, serviceOrder);
95             }
96         }
97
98         boolean shouldStopPolling = shouldStopPolling(executionTask);
99         if (!shouldStopPolling && StateType.FAILED != serviceOrderItem.getState()) {
100             // TODO lancer en asynchrone
101             sOGetStatusManager.pollRequestStatus(serviceOrder, serviceOrderItem, e2eService);
102
103             if (serviceOrderItem.getState().equals(StateType.COMPLETED)) {
104                 updateSuccessTask(executionTask);
105             }
106         } else if (shouldStopPolling && StateType.FAILED != serviceOrderItem.getState()) {
107             serviceOrderService.addOrderItemMessage(serviceOrder, serviceOrderItem, "504");
108             updateFailedTask(executionTask, serviceOrder);
109         } else {
110             updateFailedTask(executionTask, serviceOrder);
111         }
112
113         updateServiceOrder(serviceOrder);
114     }
115
116     private boolean shouldPostSo(ServiceOrderItem serviceOrderItem) {
117         return StateType.ACKNOWLEDGED == serviceOrderItem.getState()
118                 || StateType.INPROGRESS_MODIFY_ITEM_TO_CREATE == serviceOrderItem.getState();
119     }
120
121     private ServiceOrderItem getServiceOrderItem(ExecutionTask executionTask, ServiceOrder serviceOrder) {
122         for (ServiceOrderItem item : serviceOrder.getOrderItem()) {
123             if (item.getId().equals(executionTask.getOrderItemId())) {
124                 return item;
125             }
126         }
127         throw new TechnicalException(
128                 "Unable to retrieve serviceOrderItem for executionTaskId " + executionTask.getInternalId());
129     }
130
131     private ServiceOrderInfo getServiceOrderInfo(ExecutionTask executionTask) {
132         String serviceOrderInfoJson = executionTask.getServiceOrderInfoJson();
133         ServiceOrderInfo serviceOrderInfo = null;
134         try {
135             serviceOrderInfo = JsonEntityConverter.convertJsonToServiceOrderInfo(serviceOrderInfoJson);
136         } catch (IOException e) {
137             LOGGER.error("Unable to read ServiceOrderInfo Json for executionTaskId " + executionTask.getInternalId(),
138                     e);
139             throw new TechnicalException(
140                     "Unable to read ServiceOrderInfo Json for executionTaskId " + executionTask.getInternalId());
141         }
142         return serviceOrderInfo;
143     }
144
145     private void updateServiceOrder(ServiceOrder serviceOrder) {
146         boolean atLeastOneCompleted = false;
147         boolean atLeastOneNotFinished = false;
148         boolean atLeastOneFailed = false;
149
150         for (ServiceOrderItem serviceOrderItem : serviceOrder.getOrderItem()) {
151             switch (serviceOrderItem.getState()) {
152                 case COMPLETED:
153                     atLeastOneCompleted = true;
154                     break;
155                 case INPROGRESS:
156                 case ACKNOWLEDGED:
157                     atLeastOneNotFinished = true;
158                     break;
159                 case FAILED:
160                     atLeastOneFailed = true;
161                     break;
162                 default:
163                     break;
164
165             }
166         }
167         if (atLeastOneNotFinished) {
168             serviceOrderService.updateOrderState(serviceOrder, StateType.INPROGRESS);
169         } else {
170             StateType finalState;
171             if (atLeastOneFailed) {
172                 if (!atLeastOneCompleted) {
173                     finalState = StateType.FAILED;
174                 } else {
175                     finalState = StateType.PARTIAL;
176                 }
177             } else {
178                 finalState = StateType.COMPLETED;
179             }
180             serviceOrderService.updateOrderState(serviceOrder, finalState);
181         }
182     }
183
184     /**
185      * Update ServiceOrderItem with SO response by using serviceOrderRepository with the serviceOrderId
186      */
187     private void updateServiceOrderItem(ResponseEntity<CreateServiceInstanceResponse> response,
188             ServiceOrderItem orderItem, ServiceOrder serviceOrder) {
189
190         if (response == null || !response.getStatusCode().is2xxSuccessful()) {
191             LOGGER.warn("response ko for serviceOrderItem.id=" + orderItem.getId());
192             serviceOrderService.updateOrderItemState(serviceOrder, orderItem, StateType.FAILED);
193             buildOrderMessageIfNeeded(orderItem, serviceOrder, response);
194         } else {
195             CreateServiceInstanceResponse createServiceInstanceResponse = response.getBody();
196             if (createServiceInstanceResponse != null && !orderItem.getState().equals(StateType.FAILED)) {
197                 orderItem.getService().setId(createServiceInstanceResponse.getRequestReferences().getInstanceId());
198                 orderItem.setRequestId(createServiceInstanceResponse.getRequestReferences().getRequestId());
199             }
200
201             if (!response.getStatusCode().is2xxSuccessful() || response.getBody() == null
202                     || response.getBody().getRequestReferences() == null) {
203                 serviceOrderService.updateOrderItemState(serviceOrder, orderItem, StateType.FAILED);
204                 LOGGER.warn("order item {} failed , status {} , response {}", orderItem.getId(),
205                         response.getStatusCode(), response.getBody());
206             } else {
207                 updateOrderItemToInProgress(serviceOrder, orderItem);
208             }
209         }
210     }
211
212     private void updateOrderItemToInProgress(ServiceOrder serviceOrder, ServiceOrderItem serviceOrderItem) {
213         if (serviceOrderItem.getAction() != ActionType.MODIFY) {
214             serviceOrderService.updateOrderItemState(serviceOrder, serviceOrderItem, StateType.INPROGRESS);
215         } else {
216             if (StateType.ACKNOWLEDGED == serviceOrderItem.getState()) {
217                 serviceOrderService.updateOrderItemState(serviceOrder, serviceOrderItem,
218                         StateType.INPROGRESS_MODIFY_REQUEST_DELETE_SEND);
219             } else {
220                 serviceOrderService.updateOrderItemState(serviceOrder, serviceOrderItem,
221                         StateType.INPROGRESS_MODIFY_REQUEST_CREATE_SEND);
222             }
223         }
224     }
225
226     private void buildOrderMessageIfNeeded(ServiceOrderItem serviceOrderItem, ServiceOrder serviceOrder,
227             ResponseEntity<?> response) {
228         if (response != null) {
229             if (response.getStatusCode() == HttpStatus.INTERNAL_SERVER_ERROR) {
230                 serviceOrderService.addOrderMessage(serviceOrder, "502");
231             } else if (response.getStatusCode() == HttpStatus.BAD_REQUEST) {
232                 ResponseEntity<?> messageError = response;
233                 if (messageError.getBody().toString().toLowerCase().contains("serviceinstance already exists")) {
234                     serviceOrderService.addOrderItemMessage(serviceOrder, serviceOrderItem, "105");
235                 } else {
236                     serviceOrderService.addOrderItemMessageRequestSo(serviceOrder, serviceOrderItem,
237                             messageError.getBody().toString());
238                 }
239             }
240         }
241     }
242
243     /**
244      * Update E2EServiceOrderItem with SO response by using serviceOrderRepository with the serviceOrderId
245      */
246     private void updateE2EServiceOrderItem(ResponseEntity<CreateE2EServiceInstanceResponse> response,
247             ServiceOrderItem orderItem, ServiceOrder serviceOrder) {
248
249         if (response == null || !response.getStatusCode().is2xxSuccessful()) {
250             LOGGER.warn("response ko for serviceOrderItem.id=" + orderItem.getId());
251             serviceOrderService.updateOrderItemState(serviceOrder, orderItem, StateType.FAILED);
252         } else {
253             CreateE2EServiceInstanceResponse createE2EServiceInstanceResponse = response.getBody();
254             if (createE2EServiceInstanceResponse != null && !orderItem.getState().equals(StateType.FAILED)) {
255                 orderItem.getService().setId(createE2EServiceInstanceResponse.getService().getServiceId());
256                 orderItem.setRequestId(createE2EServiceInstanceResponse.getService().getOperationId());
257             }
258
259             if (!response.getStatusCode().is2xxSuccessful() || response.getBody() == null
260                     || response.getBody().getService().getOperationId() == null
261                     || response.getBody().getService().getServiceId() == null) {
262                 serviceOrderService.updateOrderItemState(serviceOrder, orderItem, StateType.FAILED);
263                 LOGGER.warn("order item {} failed , status {} , response {}", orderItem.getId(),
264                         response.getStatusCode(), response.getBody());
265             } else {
266                 serviceOrderService.updateOrderItemState(serviceOrder, orderItem, StateType.INPROGRESS);
267             }
268         }
269     }
270
271     /**
272      * Update an executionTask in database when it's process with a success
273      */
274     private void updateSuccessTask(ExecutionTask executionTask) {
275         executionTaskRepository.deleteById(executionTask.getInternalId());
276         executionTaskRepository.updateReliedTaskAfterDelete(executionTask.getInternalId());
277
278     }
279
280     /**
281      * @param executionTask
282      * @param serviceOrder
283      */
284     private void updateFailedTask(ExecutionTask executionTask, ServiceOrder serviceOrder) {
285         List<ExecutionTask> executionTasksToDelete = findExecutionTasksRecursively(executionTask);
286         for (ExecutionTask taskId : executionTasksToDelete) {
287             executionTaskRepository.delete(taskId);
288             LOGGER.warn("task {} with orderitem id {} deleted cause orderitem id {} failed ", taskId.getInternalId(),
289                     taskId.getOrderItemId(), executionTask.getOrderItemId());
290         }
291         for (ServiceOrderItem item : serviceOrder.getOrderItem()) {
292             for (ExecutionTask taskToDelete : executionTasksToDelete) {
293                 if (taskToDelete.getOrderItemId().equals(item.getId())) {
294                     serviceOrderService.updateOrderItemState(serviceOrder, item, StateType.FAILED);
295                     LOGGER.warn("task {} with orderitem id {} failed cause orderitem id {} failed ",
296                             taskToDelete.getInternalId(), taskToDelete.getOrderItemId(),
297                             executionTask.getOrderItemId());
298
299                 }
300             }
301         }
302     }
303
304     /**
305      * @param executionTask
306      * @return
307      */
308     private List<ExecutionTask> findExecutionTasksRecursively(ExecutionTask executionTask) {
309
310         List<ExecutionTask> executionTasks = new ArrayList<>();
311
312         List<ExecutionTask> tasksReliedToAnOrderItemId =
313                 executionTaskRepository.findTasksReliedToAnOrderItemId(executionTask.getInternalId());
314
315         if (CollectionUtils.isEmpty(tasksReliedToAnOrderItemId)) {
316             return Arrays.asList(executionTask);
317         } else {
318             for (ExecutionTask task : tasksReliedToAnOrderItemId) {
319                 executionTasks.addAll(findExecutionTasksRecursively(task));
320             }
321         }
322         executionTasks.add(executionTask);
323         return executionTasks;
324     }
325
326     private boolean shouldStopPolling(ExecutionTask executionTask) {
327         long createTimeinMillis = executionTask.getCreateDate().getTime();
328         long lastAttemptTimeInMillis = executionTask.getLastAttemptDate().getTime();
329         long differenceInMillis = lastAttemptTimeInMillis - createTimeinMillis;
330         float pollingDurationInMillis = pollingDurationInMins * 60000;
331         LOGGER.debug("Task {} with orderitem id {}: Task create date: {} Task last attempt date: {}",
332                 executionTask.getInternalId(), executionTask.getOrderItemId(), createTimeinMillis,
333                 lastAttemptTimeInMillis);
334         LOGGER.debug("Difference {} and Polling Duration {}", differenceInMillis, pollingDurationInMins);
335         return (differenceInMillis > pollingDurationInMillis);
336     }
337 }