Identify whether the Service is of A-la-carte or macro type
[externalapi/nbi.git] / src / main / java / org / onap / nbi / apis / serviceorder / workflow / SOTaskProcessor.java
index 94d5553..d63d122 100644 (file)
@@ -1,30 +1,38 @@
 /**
  * Copyright (c) 2018 Orange
  *
- * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except
- * in compliance with the License. You may obtain a copy of the License at
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
  *
  * http://www.apache.org/licenses/LICENSE-2.0
  *
- * Unless required by applicable law or agreed to in writing, software distributed under the License
- * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
- * or implied. See the License for the specific language governing permissions and limitations under
- * the License.
+ * Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on
+ * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations under the License.
  */
+
 package org.onap.nbi.apis.serviceorder.workflow;
 
-import org.onap.nbi.apis.serviceorder.SoClient;
-import org.onap.nbi.apis.serviceorder.model.ServiceCharacteristic;
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Date;
+import java.util.List;
+import java.util.Optional;
+import org.onap.nbi.apis.serviceorder.model.ActionType;
 import org.onap.nbi.apis.serviceorder.model.ServiceOrder;
 import org.onap.nbi.apis.serviceorder.model.ServiceOrderItem;
 import org.onap.nbi.apis.serviceorder.model.StateType;
-import org.onap.nbi.apis.serviceorder.model.consumer.*;
+import org.onap.nbi.apis.serviceorder.model.consumer.CreateE2EServiceInstanceResponse;
+import org.onap.nbi.apis.serviceorder.model.consumer.CreateServiceInstanceResponse;
 import org.onap.nbi.apis.serviceorder.model.orchestrator.ExecutionTask;
 import org.onap.nbi.apis.serviceorder.model.orchestrator.ServiceOrderInfo;
-import org.onap.nbi.apis.serviceorder.model.orchestrator.ServiceOrderInfoJson;
 import org.onap.nbi.apis.serviceorder.repositories.ExecutionTaskRepository;
-import org.onap.nbi.apis.serviceorder.repositories.ServiceOrderRepository;
+import org.onap.nbi.apis.serviceorder.service.ServiceOrderService;
+import org.onap.nbi.apis.serviceorder.utils.E2EServiceUtils;
 import org.onap.nbi.apis.serviceorder.utils.JsonEntityConverter;
+import org.onap.nbi.apis.serviceorder.utils.MacroServiceUtils;
+import org.onap.nbi.exceptions.TechnicalException;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 import org.springframework.beans.factory.annotation.Autowired;
@@ -34,121 +42,111 @@ import org.springframework.http.ResponseEntity;
 import org.springframework.stereotype.Service;
 import org.springframework.util.CollectionUtils;
 
-import java.io.IOException;
-import java.util.*;
-
 @Service
 public class SOTaskProcessor {
 
-    @Value("${nbi.callForVNF}")
-    private boolean enableCallForVNF;
-
-    @Value("${onap.lcpCloudRegionId}")
-    private String lcpCloudRegionId;
-
-    @Value("${onap.tenantId}")
-    private String tenantId;
-
     @Autowired
-    private ServiceOrderRepository serviceOrderRepository;
+    private ServiceOrderService serviceOrderService;
 
     @Autowired
     private ExecutionTaskRepository executionTaskRepository;
 
     @Autowired
-    private SoClient soClient;
+    private PostSoProcessor postSoProcessor;
 
+    @Autowired
+    private SOGetStatusManager sOGetStatusManager;
+
+    @Value("${scheduler.pollingDurationInMins}")
+    private float pollingDurationInMins;
 
     private static final Logger LOGGER = LoggerFactory.getLogger(SOTaskProcessor.class);
 
     /**
      * Run the ServiceOrchestrator processing for a serviceOrderItem which with any sub relations
-     *
-     * @throws InterruptedException
      */
-    public void processOrderItem(ExecutionTask executionTask) throws InterruptedException {
+    public void processOrderItem(ExecutionTask executionTask) {
 
+        executionTask.setLastAttemptDate(new Date());
+        executionTaskRepository.save(executionTask);
 
-        ServiceOrderInfoJson serviceOrderInfoJson = executionTask.getServiceOrderInfoJson();
-        ServiceOrder serviceOrder = serviceOrderRepository.findOne(serviceOrderInfoJson.getServiceOrderId());
-        ServiceOrderItem serviceOrderItem = null;
-        for (ServiceOrderItem item : serviceOrder.getOrderItem()) {
-            if (item.getId().equals(executionTask.getOrderItemId())) {
-                serviceOrderItem = item;
-            }
-        }
+        ServiceOrderInfo serviceOrderInfo = getServiceOrderInfo(executionTask);
 
-        ServiceOrderInfo serviceOrderInfo = null;
-        try {
-            serviceOrderInfo =
-                    JsonEntityConverter.convertJsonToServiceOrderInfo(serviceOrderInfoJson.getServiceOrderInfoJson());
-        } catch (IOException e) {
-            LOGGER.warn("Unable to read ServiceOrderInfo Json for serviceOrderId " + serviceOrder.getId(), e);
+        Optional<ServiceOrder> optionalServiceOrder =
+                serviceOrderService.findServiceOrderById(serviceOrderInfo.getServiceOrderId());
+        if (!optionalServiceOrder.isPresent()) {
+            throw new TechnicalException(
+                    "Unable to retrieve service order for id " + serviceOrderInfo.getServiceOrderId());
         }
+        ServiceOrder serviceOrder = optionalServiceOrder.get();
+        ServiceOrderItem serviceOrderItem = getServiceOrderItem(executionTask, serviceOrder);
+        boolean e2eService =
+                E2EServiceUtils.isE2EService(serviceOrderInfo.getServiceOrderItemInfos().get(serviceOrderItem.getId()));
+        boolean macroService = MacroServiceUtils
+                .isMacroService(serviceOrderInfo.getServiceOrderItemInfos().get(serviceOrderItem.getId()));
+
+        if (shouldPostSo(serviceOrderItem)) {
+            if (e2eService) {
+                ResponseEntity<CreateE2EServiceInstanceResponse> response =
+                        postSoProcessor.postE2EServiceOrderItem(serviceOrderInfo, serviceOrderItem, serviceOrder);
+                updateE2EServiceOrderItem(response, serviceOrderItem, serviceOrder);
+            } else if (macroService) {
+              LOGGER.info("Mode type macro");
+              //TODO: Add logic to construct SO macro request body and call SO macro flow.(EXTAPI-368)
 
-        if (serviceOrderItem != null && StateType.ACKNOWLEDGED == serviceOrderItem.getState()) {
-
-            ResponseEntity<CreateServiceInstanceResponse> response = null;
-            try {
-                response = postSORequest(serviceOrderItem, serviceOrderInfo);
-            } catch (NullPointerException e) {
-                LOGGER.warn("Enable to create service instance for serviceOrderItem.id=" + serviceOrderItem.getId(), e);
-                response = null;
-            }
-
-            if (response == null) {
-                LOGGER.warn("response=null for serviceOrderItem.id=" + serviceOrderItem.getId());
-                serviceOrderItem.setState(StateType.FAILED);
             } else {
-                updateServiceOrderItem(response.getBody(), serviceOrderItem);
 
-                if (response.getStatusCode() != HttpStatus.CREATED || response.getBody() == null
-                        || response.getBody().getRequestReference() == null) {
-                    serviceOrderItem.setState(StateType.FAILED);
-                } else {
-                    serviceOrderItem.setState(StateType.INPROGRESS);
-                }
+                ResponseEntity<CreateServiceInstanceResponse> response =
+                        postSoProcessor.postServiceOrderItem(serviceOrderInfo, serviceOrderItem);
+                updateServiceOrderItem(response, serviceOrderItem, serviceOrder);
             }
         }
 
-        if (executionTask.getNbRetries() > 0) {
+        boolean shouldStopPolling = shouldStopPolling(executionTask);
+        if (!shouldStopPolling && StateType.FAILED != serviceOrderItem.getState()) {
             // TODO lancer en asynchrone
-            pollSoRequestStatus(serviceOrderItem);
+            sOGetStatusManager.pollRequestStatus(serviceOrder, serviceOrderItem, e2eService);
+
             if (serviceOrderItem.getState().equals(StateType.COMPLETED)) {
                 updateSuccessTask(executionTask);
-            } else {
-                int nbRetries = executionTask.getNbRetries();
-                executionTask.setNbRetries(--nbRetries);
-                executionTask.setLastAttemptDate(new Date());
-                executionTaskRepository.save(executionTask);
             }
+        } else if (shouldStopPolling && StateType.FAILED != serviceOrderItem.getState()) {
+            serviceOrderService.addOrderItemMessage(serviceOrder, serviceOrderItem, "504");
+            updateFailedTask(executionTask, serviceOrder);
         } else {
             updateFailedTask(executionTask, serviceOrder);
         }
 
-
         updateServiceOrder(serviceOrder);
     }
 
-    private ResponseEntity<CreateServiceInstanceResponse> postSORequest(ServiceOrderItem serviceOrderItem,
-            ServiceOrderInfo serviceOrderInfo) {
-        RequestDetails requestDetails = buildSoRequest(serviceOrderItem,
-                serviceOrderInfo.getServiceOrderItemInfos().get(serviceOrderItem.getId()).getCatalogResponse(),
-                serviceOrderInfo.getSubscriberInfo());
-        MSOPayload msoPayload = new MSOPayload(requestDetails);
-        ResponseEntity<CreateServiceInstanceResponse> response = null;
-
-        switch (serviceOrderItem.getAction()) {
-            case ADD:
-                response = soClient.callCreateServiceInstance(msoPayload);
-                break;
-            case DELETE:
-                response = soClient.callDeleteServiceInstance(msoPayload, serviceOrderItem.getService().getId());
-                break;
-            default:
-                break;
+    private boolean shouldPostSo(ServiceOrderItem serviceOrderItem) {
+        return StateType.ACKNOWLEDGED == serviceOrderItem.getState()
+                || StateType.INPROGRESS_MODIFY_ITEM_TO_CREATE == serviceOrderItem.getState();
+    }
+
+    private ServiceOrderItem getServiceOrderItem(ExecutionTask executionTask, ServiceOrder serviceOrder) {
+        for (ServiceOrderItem item : serviceOrder.getOrderItem()) {
+            if (item.getId().equals(executionTask.getOrderItemId())) {
+                return item;
+            }
+        }
+        throw new TechnicalException(
+                "Unable to retrieve serviceOrderItem for executionTaskId " + executionTask.getInternalId());
+    }
+
+    private ServiceOrderInfo getServiceOrderInfo(ExecutionTask executionTask) {
+        String serviceOrderInfoJson = executionTask.getServiceOrderInfoJson();
+        ServiceOrderInfo serviceOrderInfo = null;
+        try {
+            serviceOrderInfo = JsonEntityConverter.convertJsonToServiceOrderInfo(serviceOrderInfoJson);
+        } catch (IOException e) {
+            LOGGER.error("Unable to read ServiceOrderInfo Json for executionTaskId " + executionTask.getInternalId(),
+                    e);
+            throw new TechnicalException(
+                    "Unable to read ServiceOrderInfo Json for executionTaskId " + executionTask.getInternalId());
         }
-        return response;
+        return serviceOrderInfo;
     }
 
     private void updateServiceOrder(ServiceOrder serviceOrder) {
@@ -156,7 +154,6 @@ public class SOTaskProcessor {
         boolean atLeastOneNotFinished = false;
         boolean atLeastOneFailed = false;
 
-
         for (ServiceOrderItem serviceOrderItem : serviceOrder.getOrderItem()) {
             switch (serviceOrderItem.getState()) {
                 case COMPLETED:
@@ -174,146 +171,117 @@ public class SOTaskProcessor {
 
             }
         }
-
         if (atLeastOneNotFinished) {
-            serviceOrder.setState(StateType.INPROGRESS);
+            serviceOrderService.updateOrderState(serviceOrder, StateType.INPROGRESS);
         } else {
-            serviceOrder.setCompletionDateTime(new Date());
+            StateType finalState;
             if (atLeastOneFailed) {
                 if (!atLeastOneCompleted) {
-                    serviceOrder.setState(StateType.FAILED);
+                    finalState = StateType.FAILED;
                 } else {
-                    serviceOrder.setState(StateType.PARTIAL);
+                    finalState = StateType.PARTIAL;
                 }
             } else {
-                serviceOrder.setState(StateType.COMPLETED);
+                finalState = StateType.COMPLETED;
             }
+            serviceOrderService.updateOrderState(serviceOrder, finalState);
         }
-        serviceOrderRepository.save(serviceOrder);
     }
 
-
     /**
-     * * @param orderItem
-     *
-     * @throws InterruptedException
+     * Update ServiceOrderItem with SO response by using serviceOrderRepository with the serviceOrderId
      */
-    private void pollSoRequestStatus(ServiceOrderItem orderItem) throws InterruptedException {
-        boolean stopPolling = false;
-        String requestId = orderItem.getRequestId();
-        GetRequestStatusResponse response = null;
-        int nbRetries = 0;
-
-        while (!stopPolling) {
-            response = soClient.callGetRequestStatus(requestId);
-            if (response != null) {
-                if (response.getRequest().getRequestStatus().getPercentProgress() != 100) {
-                    nbRetries++;
-                    orderItem.setState(StateType.INPROGRESS);
-                    Thread.sleep(1000);
-                } else if (RequestState.COMPLETE != response.getRequest().getRequestStatus().getRequestState()) {
-                    orderItem.setState(StateType.FAILED);
-                    stopPolling = true;
-                } else {
-                    orderItem.setState(StateType.COMPLETED);
-                    stopPolling = true;
-                }
-            } else {
-                orderItem.setState(StateType.INPROGRESS);
-                stopPolling = true;
+    private void updateServiceOrderItem(ResponseEntity<CreateServiceInstanceResponse> response,
+            ServiceOrderItem orderItem, ServiceOrder serviceOrder) {
+
+        if (response == null || !response.getStatusCode().is2xxSuccessful()) {
+            LOGGER.warn("response ko for serviceOrderItem.id=" + orderItem.getId());
+            serviceOrderService.updateOrderItemState(serviceOrder, orderItem, StateType.FAILED);
+            buildOrderMessageIfNeeded(orderItem, serviceOrder, response);
+        } else {
+            CreateServiceInstanceResponse createServiceInstanceResponse = response.getBody();
+            if (createServiceInstanceResponse != null && !orderItem.getState().equals(StateType.FAILED)) {
+                orderItem.getService().setId(createServiceInstanceResponse.getRequestReferences().getInstanceId());
+                orderItem.setRequestId(createServiceInstanceResponse.getRequestReferences().getRequestId());
             }
-            if (nbRetries == 3) {
-                stopPolling = true;
+
+            if (!response.getStatusCode().is2xxSuccessful() || response.getBody() == null
+                    || response.getBody().getRequestReferences() == null) {
+                serviceOrderService.updateOrderItemState(serviceOrder, orderItem, StateType.FAILED);
+                LOGGER.warn("order item {} failed , status {} , response {}", orderItem.getId(),
+                        response.getStatusCode(), response.getBody());
+            } else {
+                updateOrderItemToInProgress(serviceOrder, orderItem);
             }
         }
     }
 
-    /**
-     * Build SO CREATE request from the ServiceOrder and catalog informations from SDC
-     *
-     * @param orderItem
-     * @param sdcInfos
-     * @param subscriberInfo
-     * @return
-     */
-    private RequestDetails buildSoRequest(ServiceOrderItem orderItem, LinkedHashMap<String, Object> sdcInfos,
-            SubscriberInfo subscriberInfo) {
-        RequestDetails requestDetails = new RequestDetails();
-
-        requestDetails.setSubscriberInfo(subscriberInfo);
-
-        ModelInfo modelInfo = new ModelInfo();
-        modelInfo.setModelType("service");
-        modelInfo.setModelInvariantId((String) sdcInfos.get("invariantUUID"));
-        modelInfo.setModelNameVersionId(orderItem.getService().getServiceSpecification().getId());
-        modelInfo.setModelName((String) sdcInfos.get("name"));
-        modelInfo.setModelVersion((String) sdcInfos.get("version"));
-        requestDetails.setModelInfo(modelInfo);
-
-        RequestInfo requestInfo = new RequestInfo();
-        requestInfo.setInstanceName(orderItem.getService().getName());
-        requestInfo.setSource("VID");
-        requestInfo.setSuppressRollback(false);
-        requestInfo.setRequestorId("NBI");
-        requestDetails.setRequestInfo(requestInfo);
-
-        RequestParameters requestParameters = new RequestParameters();
-        requestParameters.setSubscriptionServiceType((String) sdcInfos.get("name"));
-        requestParameters.setUserParams(
-                retrieveUserParamsFromServiceCharacteristics(orderItem.getService().getServiceCharacteristic()));
-        requestParameters.setaLaCarte(true);
-        requestDetails.setRequestParameters(requestParameters);
-
-        CloudConfiguration cloudConfiguration = new CloudConfiguration(lcpCloudRegionId, tenantId);
-        requestDetails.setCloudConfiguration(cloudConfiguration);
-        return requestDetails;
+    private void updateOrderItemToInProgress(ServiceOrder serviceOrder, ServiceOrderItem serviceOrderItem) {
+        if (serviceOrderItem.getAction() != ActionType.MODIFY) {
+            serviceOrderService.updateOrderItemState(serviceOrder, serviceOrderItem, StateType.INPROGRESS);
+        } else {
+            if (StateType.ACKNOWLEDGED == serviceOrderItem.getState()) {
+                serviceOrderService.updateOrderItemState(serviceOrder, serviceOrderItem,
+                        StateType.INPROGRESS_MODIFY_REQUEST_DELETE_SEND);
+            } else {
+                serviceOrderService.updateOrderItemState(serviceOrder, serviceOrderItem,
+                        StateType.INPROGRESS_MODIFY_REQUEST_CREATE_SEND);
+            }
+        }
     }
 
-    /**
-     * Build a list of UserParams for the SO request by browsing a list of ServiceCharacteristics from
-     * SDC
-     *
-     * @param characteristics
-     * @return
-     */
-    private List<UserParams> retrieveUserParamsFromServiceCharacteristics(List<ServiceCharacteristic> characteristics) {
-        List<UserParams> userParams = new ArrayList<UserParams>();
-
-        if (!CollectionUtils.isEmpty(characteristics)) {
-            for (ServiceCharacteristic characteristic : characteristics) {
-                UserParams userParam = new UserParams(characteristic.getName(),
-                        characteristic.getValue().getServiceCharacteristicValue());
-                userParams.add(userParam);
+    private void buildOrderMessageIfNeeded(ServiceOrderItem serviceOrderItem, ServiceOrder serviceOrder,
+            ResponseEntity<?> response) {
+        if (response != null) {
+            if (response.getStatusCode() == HttpStatus.INTERNAL_SERVER_ERROR) {
+                serviceOrderService.addOrderMessage(serviceOrder, "502");
+            } else if (response.getStatusCode() == HttpStatus.BAD_REQUEST) {
+                ResponseEntity<?> messageError = response;
+                if (messageError.getBody().toString().toLowerCase().contains("serviceinstance already exists")) {
+                    serviceOrderService.addOrderItemMessage(serviceOrder, serviceOrderItem, "105");
+                } else {
+                    serviceOrderService.addOrderItemMessageRequestSo(serviceOrder, serviceOrderItem,
+                            messageError.getBody().toString());
+                }
             }
         }
-
-        return userParams;
     }
 
-
     /**
-     * Update ServiceOrderItem with SO response by using serviceOrderRepository with the serviceOrderId
-     *
-     * @param createServiceInstanceResponse
-     * @param orderItem
+     * Update E2EServiceOrderItem with SO response by using serviceOrderRepository with the serviceOrderId
      */
-    private void updateServiceOrderItem(CreateServiceInstanceResponse createServiceInstanceResponse,
-            ServiceOrderItem orderItem) {
+    private void updateE2EServiceOrderItem(ResponseEntity<CreateE2EServiceInstanceResponse> response,
+            ServiceOrderItem orderItem, ServiceOrder serviceOrder) {
+
+        if (response == null || !response.getStatusCode().is2xxSuccessful()) {
+            LOGGER.warn("response ko for serviceOrderItem.id=" + orderItem.getId());
+            serviceOrderService.updateOrderItemState(serviceOrder, orderItem, StateType.FAILED);
+        } else {
+            CreateE2EServiceInstanceResponse createE2EServiceInstanceResponse = response.getBody();
+            if (createE2EServiceInstanceResponse != null && !orderItem.getState().equals(StateType.FAILED)) {
+                orderItem.getService().setId(createE2EServiceInstanceResponse.getService().getServiceId());
+                orderItem.setRequestId(createE2EServiceInstanceResponse.getService().getOperationId());
+            }
 
-        if (createServiceInstanceResponse != null && !orderItem.getState().equals(StateType.FAILED)) {
-            orderItem.getService().setId(createServiceInstanceResponse.getRequestReference().getInstanceId());
-            orderItem.setRequestId(createServiceInstanceResponse.getRequestReference().getRequestId());
+            if (!response.getStatusCode().is2xxSuccessful() || response.getBody() == null
+                    || response.getBody().getService().getOperationId() == null
+                    || response.getBody().getService().getServiceId() == null) {
+                serviceOrderService.updateOrderItemState(serviceOrder, orderItem, StateType.FAILED);
+                LOGGER.warn("order item {} failed , status {} , response {}", orderItem.getId(),
+                        response.getStatusCode(), response.getBody());
+            } else {
+                serviceOrderService.updateOrderItemState(serviceOrder, orderItem, StateType.INPROGRESS);
+            }
         }
     }
 
     /**
      * Update an executionTask in database when it's process with a success
-     *
-     * @param executionTask
      */
     private void updateSuccessTask(ExecutionTask executionTask) {
-        executionTaskRepository.delete(executionTask.getInternalId());
+        executionTaskRepository.deleteById(executionTask.getInternalId());
         executionTaskRepository.updateReliedTaskAfterDelete(executionTask.getInternalId());
+
     }
 
     /**
@@ -324,12 +292,17 @@ public class SOTaskProcessor {
         List<ExecutionTask> executionTasksToDelete = findExecutionTasksRecursively(executionTask);
         for (ExecutionTask taskId : executionTasksToDelete) {
             executionTaskRepository.delete(taskId);
+            LOGGER.warn("task {} with orderitem id {} deleted cause orderitem id {} failed ", taskId.getInternalId(),
+                    taskId.getOrderItemId(), executionTask.getOrderItemId());
         }
-
         for (ServiceOrderItem item : serviceOrder.getOrderItem()) {
             for (ExecutionTask taskToDelete : executionTasksToDelete) {
                 if (taskToDelete.getOrderItemId().equals(item.getId())) {
-                    item.setState(StateType.FAILED);
+                    serviceOrderService.updateOrderItemState(serviceOrder, item, StateType.FAILED);
+                    LOGGER.warn("task {} with orderitem id {} failed cause orderitem id {} failed ",
+                            taskToDelete.getInternalId(), taskToDelete.getOrderItemId(),
+                            executionTask.getOrderItemId());
+
                 }
             }
         }
@@ -357,5 +330,15 @@ public class SOTaskProcessor {
         return executionTasks;
     }
 
-
+    private boolean shouldStopPolling(ExecutionTask executionTask) {
+        long createTimeinMillis = executionTask.getCreateDate().getTime();
+        long lastAttemptTimeInMillis = executionTask.getLastAttemptDate().getTime();
+        long differenceInMillis = lastAttemptTimeInMillis - createTimeinMillis;
+        float pollingDurationInMillis = pollingDurationInMins * 60000;
+        LOGGER.debug("Task {} with orderitem id {}: Task create date: {} Task last attempt date: {}",
+                executionTask.getInternalId(), executionTask.getOrderItemId(), createTimeinMillis,
+                lastAttemptTimeInMillis);
+        LOGGER.debug("Difference {} and Polling Duration {}", differenceInMillis, pollingDurationInMins);
+        return (differenceInMillis > pollingDurationInMillis);
+    }
 }