ServiceOrder Modification Implementation
[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 package org.onap.nbi.apis.serviceorder.workflow;
14
15 import java.io.IOException;
16 import java.util.ArrayList;
17 import java.util.Arrays;
18 import java.util.Date;
19 import java.util.List;
20 import org.onap.nbi.apis.serviceorder.model.ActionType;
21 import org.onap.nbi.apis.serviceorder.model.ServiceOrder;
22 import org.onap.nbi.apis.serviceorder.model.ServiceOrderItem;
23 import org.onap.nbi.apis.serviceorder.model.StateType;
24 import org.onap.nbi.apis.serviceorder.model.consumer.CreateE2EServiceInstanceResponse;
25 import org.onap.nbi.apis.serviceorder.model.consumer.CreateServiceInstanceResponse;
26 import org.onap.nbi.apis.serviceorder.model.orchestrator.ExecutionTask;
27 import org.onap.nbi.apis.serviceorder.model.orchestrator.ServiceOrderInfo;
28 import org.onap.nbi.apis.serviceorder.repositories.ExecutionTaskRepository;
29 import org.onap.nbi.apis.serviceorder.service.ServiceOrderService;
30 import org.onap.nbi.apis.serviceorder.utils.E2EServiceUtils;
31 import org.onap.nbi.apis.serviceorder.utils.JsonEntityConverter;
32 import org.onap.nbi.exceptions.TechnicalException;
33 import org.slf4j.Logger;
34 import org.slf4j.LoggerFactory;
35 import org.springframework.beans.factory.annotation.Autowired;
36 import org.springframework.http.HttpStatus;
37 import org.springframework.http.ResponseEntity;
38 import org.springframework.stereotype.Service;
39 import org.springframework.util.CollectionUtils;
40
41 @Service
42 public class SOTaskProcessor {
43
44
45     @Autowired
46     private ServiceOrderService serviceOrderService;
47
48     @Autowired
49     private ExecutionTaskRepository executionTaskRepository;
50
51     @Autowired
52     private PostSoProcessor postSoProcessor;
53
54     @Autowired
55     private SOGetStatusManager sOGetStatusManager;
56
57     private static final Logger LOGGER = LoggerFactory.getLogger(SOTaskProcessor.class);
58
59     /**
60      * Run the ServiceOrchestrator processing for a serviceOrderItem which with any sub relations
61      */
62     public void processOrderItem(ExecutionTask executionTask) throws InterruptedException {
63
64         ServiceOrderInfo serviceOrderInfo = getServiceOrderInfo(executionTask);
65
66         ServiceOrder serviceOrder = serviceOrderService.findServiceOrderById(serviceOrderInfo.getServiceOrderId());
67         ServiceOrderItem serviceOrderItem = getServiceOrderItem(executionTask, serviceOrder);
68         boolean e2eService = E2EServiceUtils
69             .isE2EService(serviceOrderInfo.getServiceOrderItemInfos().get(serviceOrderItem.getId()));
70
71         if (shouldPostSo(serviceOrderItem)) {
72             if (e2eService) {
73                 ResponseEntity<CreateE2EServiceInstanceResponse> response = postSoProcessor
74                     .postE2EServiceOrderItem(serviceOrderInfo,
75                         serviceOrderItem, serviceOrder);
76                 updateE2EServiceOrderItem(response, serviceOrderItem, serviceOrder);
77             } else {
78
79                 ResponseEntity<CreateServiceInstanceResponse> response = postSoProcessor
80                     .postServiceOrderItem(serviceOrderInfo,serviceOrderItem);
81                 updateServiceOrderItem(response, serviceOrderItem, serviceOrder);
82             }
83         }
84
85         if (executionTask.getNbRetries() > 0 && StateType.FAILED != serviceOrderItem.getState()
86             ) {
87             // TODO lancer en asynchrone
88             sOGetStatusManager.pollRequestStatus(serviceOrder, serviceOrderItem, e2eService);
89
90             if (serviceOrderItem.getState().equals(StateType.COMPLETED)) {
91                 updateSuccessTask(executionTask);
92             } else if(shouldDecrementNbRetries(serviceOrderItem)){
93                 int nbRetries = executionTask.getNbRetries();
94                 executionTask.setNbRetries(--nbRetries);
95                 executionTask.setLastAttemptDate(new Date());
96                 executionTaskRepository.save(executionTask);
97             }
98         } else {
99             updateFailedTask(executionTask, serviceOrder);
100         }
101
102         updateServiceOrder(serviceOrder);
103     }
104
105     private boolean shouldDecrementNbRetries(ServiceOrderItem serviceOrderItem) {
106         return ActionType.MODIFY!=serviceOrderItem.getAction() || (StateType.INPROGRESS_MODIFY_REQUEST_CREATE_SEND ==serviceOrderItem.getState() || StateType.INPROGRESS_MODIFY_REQUEST_DELETE_SEND
107             ==serviceOrderItem.getState());
108     }
109
110     private boolean shouldPostSo(ServiceOrderItem serviceOrderItem) {
111         return StateType.ACKNOWLEDGED == serviceOrderItem.getState() || StateType.INPROGRESS_MODIFY_ITEM_TO_CREATE == serviceOrderItem.getState();
112     }
113
114     private ServiceOrderItem getServiceOrderItem(ExecutionTask executionTask, ServiceOrder serviceOrder) {
115         for (ServiceOrderItem item : serviceOrder.getOrderItem()) {
116             if (item.getId().equals(executionTask.getOrderItemId())) {
117                 return item;
118             }
119         }
120         throw new TechnicalException(
121             "Unable to retrieve serviceOrderItem for executionTaskId " + executionTask.getInternalId());
122     }
123
124     private ServiceOrderInfo getServiceOrderInfo(ExecutionTask executionTask) {
125         String serviceOrderInfoJson = executionTask.getServiceOrderInfoJson();
126         ServiceOrderInfo serviceOrderInfo = null;
127         try {
128             serviceOrderInfo =
129                 JsonEntityConverter.convertJsonToServiceOrderInfo(serviceOrderInfoJson);
130         } catch (IOException e) {
131             LOGGER
132                 .error("Unable to read ServiceOrderInfo Json for executionTaskId " + executionTask.getInternalId(), e);
133             throw new TechnicalException(
134                 "Unable to read ServiceOrderInfo Json for executionTaskId " + executionTask.getInternalId());
135         }
136         return serviceOrderInfo;
137     }
138
139
140     private void updateServiceOrder(ServiceOrder serviceOrder) {
141         boolean atLeastOneCompleted = false;
142         boolean atLeastOneNotFinished = false;
143         boolean atLeastOneFailed = false;
144
145         for (ServiceOrderItem serviceOrderItem : serviceOrder.getOrderItem()) {
146             switch (serviceOrderItem.getState()) {
147                 case COMPLETED:
148                     atLeastOneCompleted = true;
149                     break;
150                 case INPROGRESS:
151                 case ACKNOWLEDGED:
152                     atLeastOneNotFinished = true;
153                     break;
154                 case FAILED:
155                     atLeastOneFailed = true;
156                     break;
157                 default:
158                     break;
159
160             }
161         }
162         if (atLeastOneNotFinished) {
163             serviceOrderService.updateOrderState(serviceOrder, StateType.INPROGRESS);
164         } else {
165             StateType finalState;
166             if (atLeastOneFailed) {
167                 if (!atLeastOneCompleted) {
168                     finalState = StateType.FAILED;
169                 } else {
170                     finalState = StateType.PARTIAL;
171                 }
172             } else {
173                 finalState = StateType.COMPLETED;
174             }
175             serviceOrderService.updateOrderState(serviceOrder, finalState);
176         }
177     }
178
179
180
181     /**
182      * Update ServiceOrderItem with SO response by using serviceOrderRepository with the serviceOrderId
183      */
184     private void updateServiceOrderItem(ResponseEntity<CreateServiceInstanceResponse> response,
185         ServiceOrderItem orderItem, ServiceOrder serviceOrder) {
186
187         if (response == null || !response.getStatusCode().is2xxSuccessful()) {
188             LOGGER.warn("response ko for serviceOrderItem.id=" + orderItem.getId());
189             serviceOrderService.updateOrderItemState(serviceOrder, orderItem, StateType.FAILED);
190             buildOrderMessageIfNeeded(orderItem,serviceOrder,response);
191         } else {
192             CreateServiceInstanceResponse createServiceInstanceResponse = response.getBody();
193             if (createServiceInstanceResponse != null && !orderItem.getState().equals(StateType.FAILED)) {
194                 orderItem.getService().setId(createServiceInstanceResponse.getRequestReferences().getInstanceId());
195                 orderItem.setRequestId(createServiceInstanceResponse.getRequestReferences().getRequestId());
196             }
197
198             if (!response.getStatusCode().is2xxSuccessful() || response.getBody() == null
199                 || response.getBody().getRequestReferences() == null) {
200                 serviceOrderService.updateOrderItemState(serviceOrder, orderItem, StateType.FAILED);
201                 LOGGER
202                     .warn("order item {} failed , status {} , response {}", orderItem.getId(), response.getStatusCode(),
203                         response.getBody());
204             } else {
205                 updateOrderItemToInProgress(serviceOrder, orderItem);
206             }
207         }
208     }
209
210
211     private void updateOrderItemToInProgress(ServiceOrder serviceOrder, ServiceOrderItem serviceOrderItem){
212         if(serviceOrderItem.getAction()!= ActionType.MODIFY){
213             serviceOrderService.updateOrderItemState(serviceOrder, serviceOrderItem, StateType.INPROGRESS);
214         } else {
215             if(StateType.ACKNOWLEDGED==serviceOrderItem.getState()){
216                 serviceOrderService.updateOrderItemState(serviceOrder, serviceOrderItem, StateType.INPROGRESS_MODIFY_REQUEST_DELETE_SEND);
217             } else {
218                 serviceOrderService.updateOrderItemState(serviceOrder,serviceOrderItem,StateType.INPROGRESS_MODIFY_REQUEST_CREATE_SEND);
219             }
220         }
221     }
222
223
224     private void buildOrderMessageIfNeeded(ServiceOrderItem serviceOrderItem, ServiceOrder serviceOrder,
225         ResponseEntity<?> response) {
226         if(response!=null)
227         {
228             if(response.getStatusCode()== HttpStatus.INTERNAL_SERVER_ERROR) {
229                 serviceOrderService.addOrderMessage(serviceOrder, "502");
230             }
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, messageError.getBody().toString());
237                 }
238             }
239         }
240     }
241
242     /**
243      * Update E2EServiceOrderItem with SO response by using serviceOrderRepository with the serviceOrderId
244      */
245     private void updateE2EServiceOrderItem(ResponseEntity<CreateE2EServiceInstanceResponse> response,
246         ServiceOrderItem orderItem, ServiceOrder serviceOrder) {
247
248         if (response == null || !response.getStatusCode().is2xxSuccessful()) {
249             LOGGER.warn("response ko for serviceOrderItem.id=" + orderItem.getId());
250             serviceOrderService.updateOrderItemState(serviceOrder, orderItem, StateType.FAILED);
251         } else {
252             CreateE2EServiceInstanceResponse createE2EServiceInstanceResponse = response.getBody();
253             if (createE2EServiceInstanceResponse != null && !orderItem.getState().equals(StateType.FAILED)) {
254                 orderItem.getService().setId(createE2EServiceInstanceResponse.getService().getServiceId());
255                 orderItem.setRequestId(createE2EServiceInstanceResponse.getService().getOperationId());
256             }
257
258             if (!response.getStatusCode().is2xxSuccessful() || response.getBody() == null
259                 || response.getBody().getService().getOperationId() == null
260                 || response.getBody().getService().getServiceId() == null) {
261                 serviceOrderService.updateOrderItemState(serviceOrder, orderItem, StateType.FAILED);
262                 LOGGER
263                     .warn("order item {} failed , status {} , response {}", orderItem.getId(), response.getStatusCode(),
264                         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.delete(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 {}  to failed cause orderitem id {} failed ",
296                         taskToDelete.getInternalId(), taskToDelete.getOrderItemId(), executionTask.getOrderItemId());
297
298                 }
299             }
300         }
301     }
302
303     /**
304      * @param executionTask
305      * @return
306      */
307     private List<ExecutionTask> findExecutionTasksRecursively(ExecutionTask executionTask) {
308
309         List<ExecutionTask> executionTasks = new ArrayList<>();
310
311         List<ExecutionTask> tasksReliedToAnOrderItemId =
312             executionTaskRepository.findTasksReliedToAnOrderItemId(executionTask.getInternalId());
313
314         if (CollectionUtils.isEmpty(tasksReliedToAnOrderItemId)) {
315             return Arrays.asList(executionTask);
316         } else {
317             for (ExecutionTask task : tasksReliedToAnOrderItemId) {
318                 executionTasks.addAll(findExecutionTasksRecursively(task));
319             }
320         }
321         executionTasks.add(executionTask);
322         return executionTasks;
323     }
324
325
326 }