2 * Copyright (c) 2018 Orange
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
7 * http://www.apache.org/licenses/LICENSE-2.0
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.
14 package org.onap.nbi.apis.serviceorder.workflow;
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.apis.serviceorder.utils.MacroServiceUtils;
35 import org.onap.nbi.exceptions.TechnicalException;
36 import org.slf4j.Logger;
37 import org.slf4j.LoggerFactory;
38 import org.springframework.beans.factory.annotation.Autowired;
39 import org.springframework.beans.factory.annotation.Value;
40 import org.springframework.http.HttpStatus;
41 import org.springframework.http.ResponseEntity;
42 import org.springframework.stereotype.Service;
43 import org.springframework.util.CollectionUtils;
46 public class SOTaskProcessor {
49 private ServiceOrderService serviceOrderService;
52 private ExecutionTaskRepository executionTaskRepository;
55 private PostSoProcessor postSoProcessor;
58 private SOGetStatusManager sOGetStatusManager;
60 @Value("${scheduler.pollingDurationInMins}")
61 private float pollingDurationInMins;
63 private static final Logger LOGGER = LoggerFactory.getLogger(SOTaskProcessor.class);
66 * Run the ServiceOrchestrator processing for a serviceOrderItem which with any sub relations
68 public void processOrderItem(ExecutionTask executionTask) {
70 executionTask.setLastAttemptDate(new Date());
71 executionTaskRepository.save(executionTask);
73 ServiceOrderInfo serviceOrderInfo = getServiceOrderInfo(executionTask);
75 Optional<ServiceOrder> optionalServiceOrder =
76 serviceOrderService.findServiceOrderById(serviceOrderInfo.getServiceOrderId());
77 if (!optionalServiceOrder.isPresent()) {
78 throw new TechnicalException(
79 "Unable to retrieve service order for id " + serviceOrderInfo.getServiceOrderId());
81 ServiceOrder serviceOrder = optionalServiceOrder.get();
82 ServiceOrderItem serviceOrderItem = getServiceOrderItem(executionTask, serviceOrder);
84 E2EServiceUtils.isE2EService(serviceOrderInfo.getServiceOrderItemInfos().get(serviceOrderItem.getId()));
85 boolean macroService = MacroServiceUtils
86 .isMacroService(serviceOrderInfo.getServiceOrderItemInfos().get(serviceOrderItem.getId()));
88 if (shouldPostSo(serviceOrderItem)) {
90 ResponseEntity<CreateE2EServiceInstanceResponse> response =
91 postSoProcessor.postE2EServiceOrderItem(serviceOrderInfo, serviceOrderItem, serviceOrder);
92 updateE2EServiceOrderItem(response, serviceOrderItem, serviceOrder);
93 } else if (macroService) {
94 LOGGER.info("Mode type macro");
95 //TODO: Add logic to construct SO macro request body and call SO macro flow.(EXTAPI-368)
99 ResponseEntity<CreateServiceInstanceResponse> response =
100 postSoProcessor.postServiceOrderItem(serviceOrderInfo, serviceOrderItem);
101 updateServiceOrderItem(response, serviceOrderItem, serviceOrder);
105 boolean shouldStopPolling = shouldStopPolling(executionTask);
106 if (!shouldStopPolling && StateType.FAILED != serviceOrderItem.getState()) {
107 // TODO lancer en asynchrone
108 sOGetStatusManager.pollRequestStatus(serviceOrder, serviceOrderItem, e2eService);
110 if (serviceOrderItem.getState().equals(StateType.COMPLETED)) {
111 updateSuccessTask(executionTask);
113 } else if (shouldStopPolling && StateType.FAILED != serviceOrderItem.getState()) {
114 serviceOrderService.addOrderItemMessage(serviceOrder, serviceOrderItem, "504");
115 updateFailedTask(executionTask, serviceOrder);
117 updateFailedTask(executionTask, serviceOrder);
120 updateServiceOrder(serviceOrder);
123 private boolean shouldPostSo(ServiceOrderItem serviceOrderItem) {
124 return StateType.ACKNOWLEDGED == serviceOrderItem.getState()
125 || StateType.INPROGRESS_MODIFY_ITEM_TO_CREATE == serviceOrderItem.getState();
128 private ServiceOrderItem getServiceOrderItem(ExecutionTask executionTask, ServiceOrder serviceOrder) {
129 for (ServiceOrderItem item : serviceOrder.getOrderItem()) {
130 if (item.getId().equals(executionTask.getOrderItemId())) {
134 throw new TechnicalException(
135 "Unable to retrieve serviceOrderItem for executionTaskId " + executionTask.getInternalId());
138 private ServiceOrderInfo getServiceOrderInfo(ExecutionTask executionTask) {
139 String serviceOrderInfoJson = executionTask.getServiceOrderInfoJson();
140 ServiceOrderInfo serviceOrderInfo = null;
142 serviceOrderInfo = JsonEntityConverter.convertJsonToServiceOrderInfo(serviceOrderInfoJson);
143 } catch (IOException e) {
144 LOGGER.error("Unable to read ServiceOrderInfo Json for executionTaskId " + executionTask.getInternalId(),
146 throw new TechnicalException(
147 "Unable to read ServiceOrderInfo Json for executionTaskId " + executionTask.getInternalId());
149 return serviceOrderInfo;
152 private void updateServiceOrder(ServiceOrder serviceOrder) {
153 boolean atLeastOneCompleted = false;
154 boolean atLeastOneNotFinished = false;
155 boolean atLeastOneFailed = false;
157 for (ServiceOrderItem serviceOrderItem : serviceOrder.getOrderItem()) {
158 switch (serviceOrderItem.getState()) {
160 atLeastOneCompleted = true;
164 atLeastOneNotFinished = true;
167 atLeastOneFailed = true;
174 if (atLeastOneNotFinished) {
175 serviceOrderService.updateOrderState(serviceOrder, StateType.INPROGRESS);
177 StateType finalState;
178 if (atLeastOneFailed) {
179 if (!atLeastOneCompleted) {
180 finalState = StateType.FAILED;
182 finalState = StateType.PARTIAL;
185 finalState = StateType.COMPLETED;
187 serviceOrderService.updateOrderState(serviceOrder, finalState);
192 * Update ServiceOrderItem with SO response by using serviceOrderRepository with the serviceOrderId
194 private void updateServiceOrderItem(ResponseEntity<CreateServiceInstanceResponse> response,
195 ServiceOrderItem orderItem, ServiceOrder serviceOrder) {
197 if (response == null || !response.getStatusCode().is2xxSuccessful()) {
198 LOGGER.warn("response ko for serviceOrderItem.id=" + orderItem.getId());
199 serviceOrderService.updateOrderItemState(serviceOrder, orderItem, StateType.FAILED);
200 buildOrderMessageIfNeeded(orderItem, serviceOrder, response);
202 CreateServiceInstanceResponse createServiceInstanceResponse = response.getBody();
203 if (createServiceInstanceResponse != null && !orderItem.getState().equals(StateType.FAILED)) {
204 orderItem.getService().setId(createServiceInstanceResponse.getRequestReferences().getInstanceId());
205 orderItem.setRequestId(createServiceInstanceResponse.getRequestReferences().getRequestId());
208 if (!response.getStatusCode().is2xxSuccessful() || response.getBody() == null
209 || response.getBody().getRequestReferences() == null) {
210 serviceOrderService.updateOrderItemState(serviceOrder, orderItem, StateType.FAILED);
211 LOGGER.warn("order item {} failed , status {} , response {}", orderItem.getId(),
212 response.getStatusCode(), response.getBody());
214 updateOrderItemToInProgress(serviceOrder, orderItem);
219 private void updateOrderItemToInProgress(ServiceOrder serviceOrder, ServiceOrderItem serviceOrderItem) {
220 if (serviceOrderItem.getAction() != ActionType.MODIFY) {
221 serviceOrderService.updateOrderItemState(serviceOrder, serviceOrderItem, StateType.INPROGRESS);
223 if (StateType.ACKNOWLEDGED == serviceOrderItem.getState()) {
224 serviceOrderService.updateOrderItemState(serviceOrder, serviceOrderItem,
225 StateType.INPROGRESS_MODIFY_REQUEST_DELETE_SEND);
227 serviceOrderService.updateOrderItemState(serviceOrder, serviceOrderItem,
228 StateType.INPROGRESS_MODIFY_REQUEST_CREATE_SEND);
233 private void buildOrderMessageIfNeeded(ServiceOrderItem serviceOrderItem, ServiceOrder serviceOrder,
234 ResponseEntity<?> response) {
235 if (response != null) {
236 if (response.getStatusCode() == HttpStatus.INTERNAL_SERVER_ERROR) {
237 serviceOrderService.addOrderMessage(serviceOrder, "502");
238 } else if (response.getStatusCode() == HttpStatus.BAD_REQUEST) {
239 ResponseEntity<?> messageError = response;
240 if (messageError.getBody().toString().toLowerCase().contains("serviceinstance already exists")) {
241 serviceOrderService.addOrderItemMessage(serviceOrder, serviceOrderItem, "105");
243 serviceOrderService.addOrderItemMessageRequestSo(serviceOrder, serviceOrderItem,
244 messageError.getBody().toString());
251 * Update E2EServiceOrderItem with SO response by using serviceOrderRepository with the serviceOrderId
253 private void updateE2EServiceOrderItem(ResponseEntity<CreateE2EServiceInstanceResponse> response,
254 ServiceOrderItem orderItem, ServiceOrder serviceOrder) {
256 if (response == null || !response.getStatusCode().is2xxSuccessful()) {
257 LOGGER.warn("response ko for serviceOrderItem.id=" + orderItem.getId());
258 serviceOrderService.updateOrderItemState(serviceOrder, orderItem, StateType.FAILED);
260 CreateE2EServiceInstanceResponse createE2EServiceInstanceResponse = response.getBody();
261 if (createE2EServiceInstanceResponse != null && !orderItem.getState().equals(StateType.FAILED)) {
262 orderItem.getService().setId(createE2EServiceInstanceResponse.getService().getServiceId());
263 orderItem.setRequestId(createE2EServiceInstanceResponse.getService().getOperationId());
266 if (!response.getStatusCode().is2xxSuccessful() || response.getBody() == null
267 || response.getBody().getService().getOperationId() == null
268 || response.getBody().getService().getServiceId() == null) {
269 serviceOrderService.updateOrderItemState(serviceOrder, orderItem, StateType.FAILED);
270 LOGGER.warn("order item {} failed , status {} , response {}", orderItem.getId(),
271 response.getStatusCode(), response.getBody());
273 serviceOrderService.updateOrderItemState(serviceOrder, orderItem, StateType.INPROGRESS);
279 * Update an executionTask in database when it's process with a success
281 private void updateSuccessTask(ExecutionTask executionTask) {
282 executionTaskRepository.deleteById(executionTask.getInternalId());
283 executionTaskRepository.updateReliedTaskAfterDelete(executionTask.getInternalId());
288 * @param executionTask
289 * @param serviceOrder
291 private void updateFailedTask(ExecutionTask executionTask, ServiceOrder serviceOrder) {
292 List<ExecutionTask> executionTasksToDelete = findExecutionTasksRecursively(executionTask);
293 for (ExecutionTask taskId : executionTasksToDelete) {
294 executionTaskRepository.delete(taskId);
295 LOGGER.warn("task {} with orderitem id {} deleted cause orderitem id {} failed ", taskId.getInternalId(),
296 taskId.getOrderItemId(), executionTask.getOrderItemId());
298 for (ServiceOrderItem item : serviceOrder.getOrderItem()) {
299 for (ExecutionTask taskToDelete : executionTasksToDelete) {
300 if (taskToDelete.getOrderItemId().equals(item.getId())) {
301 serviceOrderService.updateOrderItemState(serviceOrder, item, StateType.FAILED);
302 LOGGER.warn("task {} with orderitem id {} failed cause orderitem id {} failed ",
303 taskToDelete.getInternalId(), taskToDelete.getOrderItemId(),
304 executionTask.getOrderItemId());
312 * @param executionTask
315 private List<ExecutionTask> findExecutionTasksRecursively(ExecutionTask executionTask) {
317 List<ExecutionTask> executionTasks = new ArrayList<>();
319 List<ExecutionTask> tasksReliedToAnOrderItemId =
320 executionTaskRepository.findTasksReliedToAnOrderItemId(executionTask.getInternalId());
322 if (CollectionUtils.isEmpty(tasksReliedToAnOrderItemId)) {
323 return Arrays.asList(executionTask);
325 for (ExecutionTask task : tasksReliedToAnOrderItemId) {
326 executionTasks.addAll(findExecutionTasksRecursively(task));
329 executionTasks.add(executionTask);
330 return executionTasks;
333 private boolean shouldStopPolling(ExecutionTask executionTask) {
334 long createTimeinMillis = executionTask.getCreateDate().getTime();
335 long lastAttemptTimeInMillis = executionTask.getLastAttemptDate().getTime();
336 long differenceInMillis = lastAttemptTimeInMillis - createTimeinMillis;
337 float pollingDurationInMillis = pollingDurationInMins * 60000;
338 LOGGER.debug("Task {} with orderitem id {}: Task create date: {} Task last attempt date: {}",
339 executionTask.getInternalId(), executionTask.getOrderItemId(), createTimeinMillis,
340 lastAttemptTimeInMillis);
341 LOGGER.debug("Difference {} and Polling Duration {}", differenceInMillis, pollingDurationInMins);
342 return (differenceInMillis > pollingDurationInMillis);