Implant vid-app-common org.onap.vid.job (main and test)
[vid.git] / vid-app-common / src / main / java / org / onap / vid / services / AsyncInstantiationBusinessLogicImpl.java
index df8e92d..92a6d5f 100644 (file)
@@ -2,15 +2,14 @@
  * ============LICENSE_START=======================================================
  * VID
  * ================================================================================
- * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved.
- * Modifications Copyright (C) 2018 Nokia. All rights reserved.
+ * Copyright (C) 2017 - 2019 AT&T Intellectual Property. All rights reserved.
  * ================================================================================
  * 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.
 
 package org.onap.vid.services;
 
+import static org.apache.commons.lang3.ObjectUtils.defaultIfNull;
+import static org.onap.vid.controller.MsoController.SVC_INSTANCE_ID;
+import static org.onap.vid.controller.MsoController.VNF_INSTANCE_ID;
+import static org.onap.vid.utils.KotlinUtilsKt.JACKSON_OBJECT_MAPPER;
+
 import com.google.common.collect.ImmutableMap;
-import io.joshworks.restclient.http.HttpResponse;
 import java.io.IOException;
-import org.apache.commons.collections.CollectionUtils;
-import org.apache.commons.io.IOUtils;
+import java.time.ZonedDateTime;
+import java.util.ArrayList;
+import java.util.Calendar;
+import java.util.Date;
+import java.util.List;
+import java.util.Map;
+import java.util.UUID;
+import java.util.function.Consumer;
 import org.apache.commons.lang3.StringUtils;
 import org.hibernate.SessionFactory;
+import org.onap.portalsdk.core.logging.logic.EELFLoggerDelegate;
 import org.onap.vid.aai.AaiClientInterface;
-import org.onap.vid.aai.AaiOverTLSClientInterface;
-import org.onap.vid.aai.AaiResponse;
-import org.onap.vid.aai.exceptions.InvalidAAIResponseException;
-import org.onap.vid.aai.model.AaiNodeQueryResponse;
+import org.onap.vid.aai.ExceptionWithRequestInfo;
 import org.onap.vid.aai.model.ResourceType;
-import org.onap.vid.changeManagement.RequestDetailsWrapper;
-import org.onap.vid.domain.mso.CloudConfiguration;
-import org.onap.vid.domain.mso.SubscriberInfo;
+import org.onap.vid.dal.AsyncInstantiationRepository;
 import org.onap.vid.exceptions.DbFailureUncheckedException;
 import org.onap.vid.exceptions.GenericUncheckedException;
 import org.onap.vid.exceptions.MaxRetriesException;
@@ -46,369 +51,339 @@ import org.onap.vid.job.Job.JobStatus;
 import org.onap.vid.job.JobAdapter;
 import org.onap.vid.job.JobType;
 import org.onap.vid.job.JobsBrokerService;
-import org.onap.vid.model.JobAuditStatus;
+import org.onap.vid.job.impl.JobSharedData;
+import org.onap.vid.model.Action;
 import org.onap.vid.model.NameCounter;
+import org.onap.vid.model.ResourceInfo;
 import org.onap.vid.model.ServiceInfo;
+import org.onap.vid.model.serviceInstantiation.BaseResource;
 import org.onap.vid.model.serviceInstantiation.ServiceInstantiation;
-import org.onap.vid.model.serviceInstantiation.VfModule;
-import org.onap.vid.model.serviceInstantiation.Vnf;
 import org.onap.vid.mso.MsoBusinessLogicImpl;
 import org.onap.vid.mso.MsoProperties;
-import org.onap.vid.mso.model.ServiceInstantiationRequestDetails;
+import org.onap.vid.mso.MsoUtil;
+import org.onap.vid.mso.RestObject;
 import org.onap.vid.mso.rest.AsyncRequestStatus;
+import org.onap.vid.mso.rest.RequestStatus;
+import org.onap.vid.properties.Features;
 import org.onap.vid.utils.DaoUtils;
-import org.onap.portalsdk.core.logging.logic.EELFLoggerDelegate;
-import org.onap.portalsdk.core.service.DataAccessService;
+import org.onap.vid.utils.TimeUtils;
 import org.springframework.beans.factory.annotation.Autowired;
-import org.springframework.beans.factory.annotation.Qualifier;
 import org.springframework.stereotype.Service;
-
-import java.sql.Timestamp;
-import java.time.LocalDateTime;
-import java.util.*;
-import java.util.function.Consumer;
-import java.util.stream.Collectors;
-
-import static org.onap.vid.utils.Logging.debugRequestDetails;
+import org.togglz.core.manager.FeatureManager;
 
 @Service
-public class AsyncInstantiationBusinessLogicImpl implements AsyncInstantiationBusinessLogic {
+public class AsyncInstantiationBusinessLogicImpl implements
+        AsyncInstantiationBusinessLogic {
 
     private static final int MAX_RETRIES_GETTING_COUNTER = 100;
     private static final int MAX_RETRIES_GETTING_FREE_NAME_FROM_AAI = 10000;
-    private static final String NAME_FOR_CHECK_AAI_STATUS = "NAME_FOR_CHECK_AAI_STATUS";
-
-    private final DataAccessService dataAccessService;
+    public static final String NAME_FOR_CHECK_AAI_STATUS = "NAME_FOR_CHECK_AAI_STATUS";
 
     private final JobAdapter jobAdapter;
 
     private final JobsBrokerService jobService;
 
+    private final CloudOwnerService cloudOwnerService;
+
+    private final AsyncInstantiationRepository asyncInstantiationRepository;
+
     private SessionFactory sessionFactory;
 
-    private AaiOverTLSClientInterface aaiOverTLSClient;
+    private AaiClientInterface aaiClient;
+
+    private FeatureManager featureManager;
+
+    private AuditService auditService;
+
 
     private int maxRetriesGettingFreeNameFromAai = MAX_RETRIES_GETTING_FREE_NAME_FROM_AAI;
 
-    private static final EELFLoggerDelegate logger = EELFLoggerDelegate
-        .getLogger(AsyncInstantiationBusinessLogicImpl.class);
+    private static final EELFLoggerDelegate logger = EELFLoggerDelegate.getLogger(AsyncInstantiationBusinessLogicImpl.class);
     private Map<String, JobStatus> msoStateToJobStatusMap = ImmutableMap.<String, JobStatus>builder()
-        .put("inprogress", JobStatus.IN_PROGRESS)
-        .put("failed", JobStatus.FAILED)
-        .put("pause", JobStatus.PAUSE)
-        .put("paused", JobStatus.PAUSE)
-        .put("complete", JobStatus.COMPLETED)
-        .put("pending", JobStatus.IN_PROGRESS)
-        .put("pendingmanualtask", JobStatus.PAUSE)
-        .put("unlocked", JobStatus.IN_PROGRESS)
-        .build();
+            .put("inprogress", JobStatus.IN_PROGRESS)
+            .put("failed", JobStatus.FAILED)
+            .put("pause", JobStatus.PAUSE)
+            .put("paused", JobStatus.PAUSE)
+            .put("complete", JobStatus.COMPLETED)
+            .put("pending", JobStatus.IN_PROGRESS)
+            .put("pendingmanualtask", JobStatus.PAUSE)
+            .put("unlocked", JobStatus.IN_PROGRESS)
+            .put("aborted", JobStatus.COMPLETED_WITH_ERRORS)
+            .put("rolledback", JobStatus.FAILED)
+            .put("rolledbacktoassigned", JobStatus.FAILED)
+            .put("rolledbacktocreated", JobStatus.FAILED)
+            .build();
 
 
     @Autowired
-    public AsyncInstantiationBusinessLogicImpl(DataAccessService dataAccessService,
-        JobAdapter jobAdapter,
-        JobsBrokerService jobService,
-        SessionFactory sessionFactory,
-        @Qualifier("aaiClientForFasterXmlMapping")  AaiOverTLSClientInterface aaiOverTLSClient) {
-        this.dataAccessService = dataAccessService;
+    public AsyncInstantiationBusinessLogicImpl(JobAdapter jobAdapter,
+                                               JobsBrokerService jobService,
+                                               SessionFactory sessionFactory,
+                                               AaiClientInterface aaiClient,
+                                               FeatureManager featureManager,
+                                               CloudOwnerService cloudOwnerService, AsyncInstantiationRepository asyncInstantiationRepository,
+                                               AuditService auditService) {
         this.jobAdapter = jobAdapter;
         this.jobService = jobService;
         this.sessionFactory = sessionFactory;
-        this.aaiOverTLSClient = aaiOverTLSClient;
+        this.aaiClient = aaiClient;
+        this.featureManager = featureManager;
+        this.cloudOwnerService = cloudOwnerService;
+        this.asyncInstantiationRepository = asyncInstantiationRepository;
+        this.auditService = auditService;
     }
 
     @Override
     public List<ServiceInfo> getAllServicesInfo() {
-        return dataAccessService
-            .getList(ServiceInfo.class, filterByCreationDateAndNotDeleted(), orderByCreatedDateAndStatus(), null);
-    }
-
-    private String filterByCreationDateAndNotDeleted() {
-        LocalDateTime minus3Months = LocalDateTime.now().minusMonths(3);
-        Timestamp filterDate = Timestamp.valueOf(minus3Months);
-        return " where" +
-            "   hidden = false" +
-            "   and deleted_at is null" +  // don't fetch deleted
-            "   and created >= '" + filterDate + "' ";
-    }
-
-    private String orderByCreatedDateAndStatus() {
-        return " createdBulkDate DESC ,\n" +
-            "  (CASE jobStatus\n" +
-            "   WHEN 'COMPLETED' THEN 0\n" +
-            "   WHEN 'FAILED' THEN 0\n" +
-            "   WHEN 'IN_PROGRESS' THEN 1\n" +
-            "   WHEN 'PAUSE' THEN 2\n" +
-            "   WHEN 'PENDING' THEN 3\n" +
-            "   WHEN 'STOPPED' THEN 3 END),\n" +
-            "  statusModifiedDate ";
+        return asyncInstantiationRepository.getAllServicesInfo();
+    }
+
+    JobType getJobType(ServiceInstantiation request) {
+        if (request.isALaCarte()) {
+            switch (defaultIfNull(request.getAction(), Action.Create)) {
+                case Delete:
+                    return JobType.ALaCarteService;
+                case None:
+                    return JobType.ALaCarteService;
+                default:
+                    return JobType.ALaCarteServiceInstantiation;
+            }
+        } else {
+            return JobType.MacroServiceInstantiation;
+        }
     }
 
     @Override
     public List<UUID> pushBulkJob(ServiceInstantiation request, String userId) {
+
         List<UUID> uuids = new ArrayList<>();
         Date createdBulkDate = Calendar.getInstance().getTime();
         int bulkSize = request.getBulkSize();
         UUID templateId = UUID.randomUUID();
         for (int i = 0; i < bulkSize; i++) {
-            Job job = jobAdapter.createJob(JobType.ServiceInstantiation, request, templateId, userId, i);
-            UUID jobId = jobService.add(job);
-            auditVidStatus(jobId, job.getStatus());
+            ServiceInstantiation requestPerJob = prepareServiceToBeUnique(request);
+            ServiceInfo.ServiceAction serviceAction = getAction(requestPerJob);
+            JobType jobType = getJobType(requestPerJob);
+            final String optimisticUniqueServiceInstanceName = bulkSize>1 ? //only bulk with more than 1 service need to get multiple names
+                    getOptimisticUniqueServiceInstanceName(requestPerJob.getInstanceName()) : requestPerJob.getInstanceName();
+            Job job = jobAdapter.createServiceInstantiationJob(jobType, requestPerJob, templateId, userId, request.getTestApi(), optimisticUniqueServiceInstanceName, i);
+            UUID jobId = job.getUuid();
+
+            asyncInstantiationRepository.saveServiceInfo(createServiceInfo(userId, requestPerJob, jobId, templateId, createdBulkDate, optimisticUniqueServiceInstanceName, serviceAction));
+            asyncInstantiationRepository.addJobRequest(jobId, requestPerJob);
+            auditService.auditVidStatus(jobId, job.getStatus());
             uuids.add(jobId);
-            dataAccessService.saveDomainObject(createServiceInfo(userId, request, jobId, templateId, createdBulkDate),
-                DaoUtils.getPropsMap());
+
+            jobService.add(job);
         }
         return uuids;
     }
 
-    private ServiceInfo createServiceInfo(String userId, ServiceInstantiation serviceInstantiation, UUID jobId,
-        UUID templateId, Date createdBulkDate) {
-        return new ServiceInfo(
-            userId, Job.JobStatus.PENDING, serviceInstantiation.isPause(), jobId, templateId,
-            serviceInstantiation.getOwningEntityId(),
-            serviceInstantiation.getOwningEntityName(),
-            serviceInstantiation.getProjectName(),
-            serviceInstantiation.getAicZoneId(),
-            serviceInstantiation.getAicZoneName(),
-            serviceInstantiation.getTenantId(),
-            serviceInstantiation.getTenantName(),
-            serviceInstantiation.getLcpCloudRegionId(),
-            null,
-            serviceInstantiation.getSubscriptionServiceType(),
-            serviceInstantiation.getSubscriberName(),
-            null,
-            serviceInstantiation.getInstanceName(),
-            serviceInstantiation.getModelInfo().getModelInvariantId(),
-            serviceInstantiation.getModelInfo().getModelName(),
-            serviceInstantiation.getModelInfo().getModelVersion(),
-            createdBulkDate
-        );
+    private ServiceInfo.ServiceAction getAction(ServiceInstantiation request) {
+        if (request.getAction() == null) {
+            //throw new GenericUncheckedException("Required 'action' field not provided at service level");
+            return Action.Create.getServiceAction();
+        }
+        return request.getAction().getServiceAction();
     }
 
 
-    @Override
-    public RequestDetailsWrapper<ServiceInstantiationRequestDetails> generateServiceInstantiationRequest(UUID jobId,
-        ServiceInstantiation payload, String userId) {
-
-        ServiceInstantiationRequestDetails.ServiceInstantiationOwningEntity owningEntity = new ServiceInstantiationRequestDetails.ServiceInstantiationOwningEntity(
-            payload.getOwningEntityId(), payload.getOwningEntityName());
+    private String getOptimisticUniqueServiceInstanceName(String instanceName) {
+        return StringUtils.isNotEmpty(instanceName) ? getUniqueNameFromDbOnly(instanceName) : instanceName;
+    }
 
-        SubscriberInfo subscriberInfo = new SubscriberInfo();
-        subscriberInfo.setGlobalSubscriberId(payload.getGlobalSubscriberId());
+    protected ServiceInfo createServiceInfo(String userId, ServiceInstantiation serviceInstantiation, UUID jobId, UUID templateId, Date createdBulkDate, String optimisticUniqueServiceInstanceName, ServiceInfo.ServiceAction serviceAction) {
+        return new ServiceInfo(
+                userId,
+                serviceInstantiation.isALaCarte(),
+                Job.JobStatus.PENDING, serviceInstantiation.isPause(), jobId, templateId,
+                serviceInstantiation.getOwningEntityId(),
+                serviceInstantiation.getOwningEntityName(),
+                serviceInstantiation.getProjectName(),
+                serviceInstantiation.getAicZoneId(),
+                serviceInstantiation.getAicZoneName(),
+                serviceInstantiation.getTenantId(),
+                serviceInstantiation.getTenantName(),
+                serviceInstantiation.getLcpCloudRegionId(),
+                null,
+                serviceInstantiation.getSubscriptionServiceType(),
+                serviceInstantiation.getSubscriberName(),
+                serviceInstantiation.getGlobalSubscriberId(),
+                serviceInstantiation.getInstanceId(),
+                optimisticUniqueServiceInstanceName,
+                serviceInstantiation.getModelInfo().getModelVersionId(),
+                serviceInstantiation.getModelInfo().getModelName(),
+                serviceInstantiation.getModelInfo().getModelVersion(),
+                createdBulkDate,
+                serviceAction,
+                false);
+    }
 
-        String serviceInstanceName = null;
-        if (payload.isUserProvidedNaming()) {
-            serviceInstanceName = getUniqueName(payload.getInstanceName(), ResourceType.SERVICE_INSTANCE);
-            String finalServiceInstanceName = serviceInstanceName;
-            updateServiceInfo(jobId, x -> x.setServiceInstanceName(finalServiceInstanceName));
-        }
-        ServiceInstantiationRequestDetails.RequestInfo requestInfo = new ServiceInstantiationRequestDetails.RequestInfo(
-            serviceInstanceName,
-            payload.getProductFamilyId(),
-            "VID",
-            payload.isRollbackOnFailure(),
-            userId);
-
-        List<ServiceInstantiationRequestDetails.ServiceInstantiationService> serviceInstantiationService = new LinkedList<>();
-        List<Map<String, String>> unFilteredInstanceParams =
-            payload.getInstanceParams() != null ? payload.getInstanceParams() : new LinkedList<>();
-        List<Map<String, String>> filteredInstanceParams = removeUnNeededParams(unFilteredInstanceParams);
-        ServiceInstantiationRequestDetails.ServiceInstantiationService serviceInstantiationService1 = new ServiceInstantiationRequestDetails.ServiceInstantiationService(
-            payload.getModelInfo(),
-            serviceInstanceName,
-            filteredInstanceParams,
-            createServiceInstantiationVnfList(payload)
-        );
-        serviceInstantiationService.add(serviceInstantiationService1);
+    @Override
+    public boolean isPartOfBulk(UUID jobId) {
+        if (jobId == null) {
+            return false;
+    }
+        ServiceInfo serviceInfo = asyncInstantiationRepository.getServiceInfoByJobId(jobId);
+        UUID templateId = serviceInfo.getTemplateId();
+        if (templateId != null) {
+            return getNumberOfJobsInBulk(templateId) > 1;
+    }
+        return false;
 
-        ServiceInstantiationRequestDetails.RequestParameters requestParameters = new ServiceInstantiationRequestDetails.RequestParameters(
-            payload.getSubscriptionServiceType(), false, serviceInstantiationService);
+    }
 
-        ServiceInstantiationRequestDetails.Project project =
-            payload.getProjectName() != null ? new ServiceInstantiationRequestDetails.Project(payload.getProjectName())
-                : null;
+    private int getNumberOfJobsInBulk(UUID templateId) {
+        String hqlSelectJob = "from JobDaoImpl where templateId = :templateId";
+        return DaoUtils.tryWithSessionAndTransaction(sessionFactory, session ->
+            session.createQuery(hqlSelectJob)
+                    .setText("templateId", templateId.toString())
+                    .list()
+                    .size()
+        );
+    }
 
-        ServiceInstantiationRequestDetails requestDetails = new ServiceInstantiationRequestDetails(
-            payload.getModelInfo(), owningEntity, subscriberInfo,
-            project, requestInfo, requestParameters);
+    @Override
+    public String getServiceInstantiationPath(ServiceInstantiation serviceInstantiationRequest) {
+        //in case pause flag is true - use assign , else - use create.
+        return MsoBusinessLogicImpl.validateEndpointPath(
+                serviceInstantiationRequest.isPause() ?
+                        MsoProperties.MSO_REST_API_SERVICE_INSTANCE_ASSIGN : MsoProperties.MSO_REST_API_SERVICE_INSTANCE_CREATE
+        );
+    }
 
-        RequestDetailsWrapper<ServiceInstantiationRequestDetails> requestDetailsWrapper = new RequestDetailsWrapper(
-            requestDetails);
-        debugRequestDetails(requestDetailsWrapper, logger);
-        return requestDetailsWrapper;
+    @Override
+    public String getServiceDeletionPath(String serviceInstanceId) {
+        return MsoBusinessLogicImpl.validateEndpointPath( MsoProperties.MSO_DELETE_OR_UNASSIGN_REST_API_SVC_INSTANCE)  + "/" + serviceInstanceId;
     }
 
-    private List<Map<String, String>> removeUnNeededParams(List<Map<String, String>> instanceParams) {
-        List<String> keysToRemove = new ArrayList<>();
-        if (instanceParams != null && !instanceParams.isEmpty()) {
-            for (String key : instanceParams.get(0).keySet()) {
-                for (String paramToIgnore : PARAMS_TO_IGNORE) {
-                    if ((key.equalsIgnoreCase(paramToIgnore))) {
-                        keysToRemove.add(key);
-                    }
-                }
-            }
-            for (String key : keysToRemove) {
-                instanceParams.get(0).remove(key);
-            }
-            //TODO will be removed on once we stop using List<Map<String, String>>
-            if (instanceParams.get(0).isEmpty()) {
-                return Collections.emptyList();
-            }
-        }
-        return instanceParams;
-    }
-
-    private ServiceInstantiationRequestDetails.ServiceInstantiationVnfList createServiceInstantiationVnfList(
-        ServiceInstantiation payload) {
-        CloudConfiguration cloudConfiguration = new CloudConfiguration();
-        cloudConfiguration.setTenantId(payload.getTenantId());
-        cloudConfiguration.setLcpCloudRegionId(payload.getLcpCloudRegionId());
-
-        Map<String, Vnf> vnfs = payload.getVnfs();
-        List<ServiceInstantiationRequestDetails.ServiceInstantiationVnf> vnfList = new ArrayList<>();
-        for (Vnf vnf : vnfs.values()) {
-            Map<String, Map<String, VfModule>> vfModules = vnf.getVfModules();
-            List<VfModule> convertedUnFilteredVfModules = convertVfModuleMapToList(vfModules);
-            List<VfModule> filteredVfModules = filterInstanceParamsFromVfModuleAndUniqueNames(
-                convertedUnFilteredVfModules, vnf.isUserProvidedNaming());
-            ServiceInstantiationRequestDetails.ServiceInstantiationVnf serviceInstantiationVnf = new ServiceInstantiationRequestDetails.ServiceInstantiationVnf(
-                vnf.getModelInfo(),
-                cloudConfiguration,
-                vnf.getPlatformName(),
-                vnf.getLineOfBusiness(),
-                payload.getProductFamilyId(),
-                removeUnNeededParams(vnf.getInstanceParams()),
-                filteredVfModules,
-                vnf.isUserProvidedNaming() ? getUniqueName(vnf.getInstanceName(), ResourceType.GENERIC_VNF) : null
-            );
-            vnfList.add(serviceInstantiationVnf);
-        }
+    @Override
+    public String getVnfInstantiationPath(String serviceInstanceId) {
+        return MsoBusinessLogicImpl.validateEndpointPath(MsoProperties.MSO_REST_API_VNF_INSTANCE).
+                replaceFirst(SVC_INSTANCE_ID, serviceInstanceId);
+    }
 
-        return new ServiceInstantiationRequestDetails.ServiceInstantiationVnfList(vnfList);
+    @Override
+    public String getVnfDeletionPath(String serviceInstanceId, String vnfInstanceId) {
+        return (MsoBusinessLogicImpl.validateEndpointPath(MsoProperties.MSO_REST_API_VNF_INSTANCE)
+                + '/' + vnfInstanceId)
+                .replaceFirst(SVC_INSTANCE_ID, serviceInstanceId).replaceFirst(VNF_INSTANCE_ID, vnfInstanceId);
     }
 
-    private List<VfModule> convertVfModuleMapToList(Map<String, Map<String, VfModule>> vfModules) {
-        return vfModules.values().stream().flatMap(vfModule -> vfModule.values().stream()).collect(Collectors.toList());
+    @Override
+    public String getNetworkInstantiationPath(String serviceInstanceId) {
+        return MsoBusinessLogicImpl.validateEndpointPath(MsoProperties.MSO_REST_API_NETWORK_INSTANCE).
+                replaceFirst(SVC_INSTANCE_ID, serviceInstanceId);
     }
 
-    private List<VfModule> filterInstanceParamsFromVfModuleAndUniqueNames(List<VfModule> unFilteredVfModules,
-        boolean isUserProvidedNaming) {
-        return unFilteredVfModules.stream().map(vfModule ->
-            new VfModule(
-                vfModule.getModelInfo(),
-                getUniqueNameIfNeeded(isUserProvidedNaming, vfModule.getInstanceName(), ResourceType.VF_MODULE),
-                getUniqueNameIfNeeded(isUserProvidedNaming, vfModule.getVolumeGroupInstanceName(),
-                    ResourceType.VOLUME_GROUP),
-                removeUnNeededParams(vfModule.getInstanceParams())))
-            .collect(Collectors.toList());
+    @Override
+    public String getVfmoduleInstantiationPath(String serviceInstanceId, String vnfInstanceId) {
+        return MsoBusinessLogicImpl.validateEndpointPath(MsoProperties.MSO_REST_API_VF_MODULE_INSTANCE)
+                .replaceFirst(SVC_INSTANCE_ID, serviceInstanceId)
+                .replaceFirst(VNF_INSTANCE_ID, vnfInstanceId);
     }
 
-    private String getUniqueNameIfNeeded(boolean isUserProvidedNaming, String name, ResourceType resourceType) {
-        return isUserProvidedNaming && !StringUtils.isEmpty(name) ?
-            getUniqueName(name, resourceType) : null;
+    @Override
+    public String getVfModuleReplacePath(String serviceInstanceId, String vnfInstanceId, String vfModuleInstanceId)
+    {
+        return MsoBusinessLogicImpl.validateEndpointPath(MsoProperties.MSO_REST_API_VF_MODULE_INSTANCE)
+                .replaceFirst(SVC_INSTANCE_ID, serviceInstanceId)
+                .replaceFirst(VNF_INSTANCE_ID, vnfInstanceId)
+                + "/" + vfModuleInstanceId
+                + "/replace";
     }
 
     @Override
-    public String getServiceInstantiationPath(ServiceInstantiation serviceInstantiationRequest) {
-        //in case pause flag is true - use assign , else - use create.
-        return MsoBusinessLogicImpl.validateEndpointPath(
-            serviceInstantiationRequest.isPause() ?
-                "mso.restapi.serviceInstanceAssign" : "mso.restapi.serviceInstanceCreate"
-        );
+    public String getVfModuleDeletePath(String serviceInstanceId, String vnfInstanceId, String vfModuleInstanceId) {
+        return MsoBusinessLogicImpl.validateEndpointPath(MsoProperties.MSO_REST_API_VF_MODULE_INSTANCE)
+                .replaceFirst(SVC_INSTANCE_ID, serviceInstanceId)
+                .replaceFirst(VNF_INSTANCE_ID, vnfInstanceId)
+                + "/" + vfModuleInstanceId;
     }
 
     @Override
-    public String getOrchestrationRequestsPath() {
-        return MsoBusinessLogicImpl.validateEndpointPath(MsoProperties.MSO_REST_API_GET_ORC_REQ);
+    public String getVolumeGroupInstantiationPath(String serviceInstanceId, String vnfInstanceId) {
+        return MsoBusinessLogicImpl.validateEndpointPath(MsoProperties.MSO_REST_API_VOLUME_GROUP_INSTANCE)
+                .replaceFirst(SVC_INSTANCE_ID, serviceInstanceId)
+                .replaceFirst(VNF_INSTANCE_ID, vnfInstanceId);
     }
 
     @Override
-    public ServiceInfo updateServiceInfo(UUID jobUUID, Consumer<ServiceInfo> serviceUpdater) {
-        ServiceInfo serviceInfo = getServiceInfoByJobId(jobUUID);
-        serviceUpdater.accept(serviceInfo);
-        dataAccessService.saveDomainObject(serviceInfo, DaoUtils.getPropsMap());
-        return serviceInfo;
+    public String getInstanceGroupInstantiationPath() {
+        return MsoBusinessLogicImpl.validateEndpointPath(MsoProperties.MSO_REST_API_INSTANCE_GROUP);
     }
 
     @Override
-    public ServiceInfo updateServiceInfoAndAuditStatus(UUID jobUuid, JobStatus jobStatus) {
-        auditVidStatus(jobUuid, jobStatus);
-        return updateServiceInfo(jobUuid, x -> setServiceInfoStatus(x, jobStatus));
+    public String getInstanceGroupMemberInstantiationPath(String vnfGroupInstanceId) {
+        return MsoBusinessLogicImpl.validateEndpointPath(MsoProperties.MSO_REST_API_INSTANCE_GROUP)
+                + '/' + vnfGroupInstanceId + "/addMembers";
     }
 
-    private void setServiceInfoStatus(ServiceInfo serviceInfo, JobStatus jobStatus) {
-        serviceInfo.setJobStatus(jobStatus);
-        serviceInfo.setStatusModifiedDate(new Date());
+    @Override
+    public String getInstanceGroupDeletePath(String instanceGroupId) {
+        return MsoBusinessLogicImpl.validateEndpointPath(MsoProperties.MSO_REST_API_INSTANCE_GROUP)
+                + '/' + instanceGroupId;
     }
 
-    public ServiceInfo getServiceInfoByJobId(UUID jobUUID) {
-        List<ServiceInfo> serviceInfoList = dataAccessService
-            .getList(ServiceInfo.class, String.format(" where jobId = '%s' ", jobUUID), null, null);
-        if (serviceInfoList.size() != 1) {
-            throw new GenericUncheckedException(
-                "Failed to retrieve job with uuid " + jobUUID + " from ServiceInfo table. Instances found: "
-                    + serviceInfoList.size());
-        }
-        return serviceInfoList.get(0);
+    @Override
+    public String getInstanceGroupMemberDeletePath(String vnfGroupInstanceId){
+        return MsoBusinessLogicImpl.validateEndpointPath(MsoProperties.MSO_REST_API_INSTANCE_GROUP)
+                + '/' + vnfGroupInstanceId + "/removeMembers";
     }
 
-    public List<JobAuditStatus> getAuditStatuses(UUID jobUUID, JobAuditStatus.SourceStatus source) {
-        return dataAccessService.getList(
-            JobAuditStatus.class,
-            String.format(" where SOURCE = '%s' and JOB_ID = '%s'", source, jobUUID),
-            " CREATED_DATE ", null);
+    @Override
+    public String getNetworkDeletePath(String serviceInstanceId, String networkInstanceId) {
+        return (MsoBusinessLogicImpl.validateEndpointPath(MsoProperties.MSO_REST_API_NETWORK_INSTANCE)
+                + "/" + networkInstanceId)
+                .replaceFirst(SVC_INSTANCE_ID, serviceInstanceId);
     }
 
-    private JobAuditStatus getLatestAuditStatus(UUID jobUUID, JobAuditStatus.SourceStatus source) {
-        List<JobAuditStatus> list = getAuditStatuses(jobUUID, source);
-        return !list.isEmpty() ? list.get(list.size() - 1) : null;
+    @Override
+    public String getResumeRequestPath(String requestId) {
+        return MsoBusinessLogicImpl.validateEndpointPath("mso.restapi.resume.orc.req")
+                .replaceFirst("<request_id>", requestId);
     }
 
     @Override
-    public void auditVidStatus(UUID jobUUID, JobStatus jobStatus) {
-        JobAuditStatus vidStatus = new JobAuditStatus(jobUUID, jobStatus.toString(), JobAuditStatus.SourceStatus.VID);
-        auditStatus(vidStatus);
+    public String getOrchestrationRequestsPath() {
+        return MsoBusinessLogicImpl.validateEndpointPath(MsoProperties.MSO_REST_API_GET_ORC_REQ);
     }
 
     @Override
-    public void auditMsoStatus(UUID jobUUID, AsyncRequestStatus.Request msoRequestStatus) {
-        auditMsoStatus(jobUUID, msoRequestStatus.requestStatus.getRequestState(), msoRequestStatus.requestId,
-            msoRequestStatus.requestStatus.getStatusMessage());
+    public ServiceInfo updateServiceInfo(UUID jobUUID, Consumer<ServiceInfo> serviceUpdater) {
+        ServiceInfo serviceInfo = asyncInstantiationRepository.getServiceInfoByJobId(jobUUID);
+        serviceUpdater.accept(serviceInfo);
+        asyncInstantiationRepository.saveServiceInfo(serviceInfo);
+        return serviceInfo;
     }
 
     @Override
-    public void auditMsoStatus(UUID jobUUID, String jobStatus, String requestId, String additionalInfo) {
-        JobAuditStatus msoStatus = new JobAuditStatus(jobUUID, jobStatus, JobAuditStatus.SourceStatus.MSO,
-            requestId != null ? UUID.fromString(requestId) : null,
-            additionalInfo);
-        auditStatus(msoStatus);
+    public ServiceInfo updateServiceInfoAndAuditStatus(UUID jobUuid, JobStatus jobStatus) {
+        auditService.auditVidStatus(jobUuid, jobStatus);
+        return updateServiceInfo(jobUuid, x -> setServiceInfoStatus(x, jobStatus));
     }
 
-    private void auditStatus(JobAuditStatus jobAuditStatus) {
-        JobAuditStatus latestStatus = getLatestAuditStatus(jobAuditStatus.getJobId(), jobAuditStatus.getSource());
-        if (latestStatus == null || !latestStatus.equals(jobAuditStatus)) {
-            dataAccessService.saveDomainObject(jobAuditStatus, DaoUtils.getPropsMap());
-        }
+    private boolean isRetryEnabledForStatus(JobStatus jobStatus) {
+        return featureManager.isActive(Features.FLAG_1902_RETRY_JOB) &&
+                (jobStatus==JobStatus.COMPLETED_WITH_ERRORS || jobStatus==JobStatus.FAILED);
+    }
 
+    private void setServiceInfoStatus(ServiceInfo serviceInfo, JobStatus jobStatus) {
+        serviceInfo.setJobStatus(jobStatus);
+        serviceInfo.setStatusModifiedDate(new Date());
+        serviceInfo.setRetryEnabled(isRetryEnabledForStatus(jobStatus));
     }
 
     public Job.JobStatus calcStatus(AsyncRequestStatus asyncRequestStatus) {
-        String msoRequestState = asyncRequestStatus.request.requestStatus.getRequestState().toLowerCase()
-            .replaceAll("[^a-z]+", "");
+        String msoRequestState = asyncRequestStatus.request.requestStatus.getRequestState().toLowerCase().replaceAll("[^a-z]+", "");
         JobStatus jobStatus = msoStateToJobStatusMap.get(msoRequestState);
         return (jobStatus != null ? jobStatus : JobStatus.IN_PROGRESS);
     }
 
     @Override
     public void handleFailedInstantiation(UUID jobUUID) {
-        ServiceInfo serviceInfo = updateServiceInfoAndAuditStatus(jobUUID, JobStatus.FAILED);
-        List<ServiceInfo> serviceInfoList = dataAccessService.getList(
-            ServiceInfo.class,
-            String.format(" where templateId = '%s' and jobStatus = '%s'",
-                serviceInfo.getTemplateId(),
-                JobStatus.PENDING),
-            null, null);
+        ServiceInfo serviceInfo = asyncInstantiationRepository.getServiceInfoByJobId(jobUUID);
+        List<ServiceInfo> serviceInfoList = asyncInstantiationRepository.getServiceInfoByTemplateIdAndJobStatus(serviceInfo.getTemplateId(), JobStatus.PENDING);
         serviceInfoList.forEach(si -> updateServiceInfoAndAuditStatus(si.getJobId(), JobStatus.STOPPED));
     }
 
@@ -421,44 +396,43 @@ public class AsyncInstantiationBusinessLogicImpl implements AsyncInstantiationBu
 
     @Override
     public void hideServiceInfo(UUID jobUUID) {
-        ServiceInfo serviceInfo = getServiceInfoByJobId(jobUUID);
+        ServiceInfo serviceInfo = asyncInstantiationRepository.getServiceInfoByJobId(jobUUID);
         if (!serviceInfo.getJobStatus().isFinal()) {
             String message = String.format("jobId %s: Service status does not allow hide service, status = %s",
-                serviceInfo.getJobId(),
-                serviceInfo.getJobStatus());
+                    serviceInfo.getJobId(),
+                    serviceInfo.getJobStatus());
             logger.error(EELFLoggerDelegate.errorLogger, message);
             throw new OperationNotAllowedException(message);
         }
         serviceInfo.setHidden(true);
-        dataAccessService.saveDomainObject(serviceInfo, DaoUtils.getPropsMap());
+        asyncInstantiationRepository.saveServiceInfo(serviceInfo);
     }
 
     @Override
-    public int
-
-    getCounterForName(String name) {
+    public int getCounterForName(String name) {
 
         String hqlSelectNC = "from NameCounter where name = :name";
         String hqlUpdateCounter = "update NameCounter set counter = :newCounter " +
-            "where name= :name " +
-            "and counter= :prevCounter";
+                "where name= :name " +
+                "and counter= :prevCounter";
 
         Integer counter = null;
         GenericUncheckedException lastException = null;
-        for (int i = 0; i < MAX_RETRIES_GETTING_COUNTER && counter == null; i++) {
+        for (int i = 0; i< MAX_RETRIES_GETTING_COUNTER && counter==null; i++) {
             try {
                 counter = calcCounter(name, hqlSelectNC, hqlUpdateCounter);
-            } catch (GenericUncheckedException exception) {
+            }
+            catch (GenericUncheckedException exception) {
                 lastException = exception; //do nothing, we will try again in the loop
             }
         }
 
-        if (counter != null) {
+        if (counter!=null) {
             return counter;
         }
 
-        throw lastException != null ? new DbFailureUncheckedException(lastException) :
-            new DbFailureUncheckedException("Failed to get counter for " + name + " due to unknown error");
+        throw lastException!=null ? new DbFailureUncheckedException(lastException) :
+                new DbFailureUncheckedException("Failed to get counter for "+name+" due to unknown error");
 
     }
 
@@ -466,14 +440,14 @@ public class AsyncInstantiationBusinessLogicImpl implements AsyncInstantiationBu
         Integer counter;
         counter = DaoUtils.tryWithSessionAndTransaction(sessionFactory, session -> {
             NameCounter nameCounter = (NameCounter) session.createQuery(hqlSelectNC)
-                .setText("name", name)
-                .uniqueResult();
+                    .setText("name", name)
+                    .uniqueResult();
             if (nameCounter != null) {
                 int updatedRows = session.createQuery(hqlUpdateCounter)
-                    .setText("name", nameCounter.getName())
-                    .setInteger("prevCounter", nameCounter.getCounter())
-                    .setInteger("newCounter", nameCounter.getCounter() + 1)
-                    .executeUpdate();
+                        .setText("name", nameCounter.getName())
+                        .setInteger("prevCounter", nameCounter.getCounter())
+                        .setInteger("newCounter", nameCounter.getCounter() + 1)
+                        .executeUpdate();
                 if (updatedRows == 1) {
                     return nameCounter.getCounter() + 1;
                 }
@@ -481,7 +455,7 @@ public class AsyncInstantiationBusinessLogicImpl implements AsyncInstantiationBu
                 Object nameAsId = session.save(new NameCounter(name));
                 //if save success
                 if (nameAsId != null) {
-                    return 1;
+                    return 0;
                 }
             }
             //in case of failure return null, in order to continue the loop
@@ -506,34 +480,136 @@ public class AsyncInstantiationBusinessLogicImpl implements AsyncInstantiationBu
         //Prevents unnecessary increasing of the counter while AAI doesn't response
         isNameFreeInAai(NAME_FOR_CHECK_AAI_STATUS, resourceType);
 
-        for (int i = 0; i < getMaxRetriesGettingFreeNameFromAai(); i++) {
-            int counter = getCounterForName(name);
-            String newName = formatNameAndCounter(name, counter);
+        for (int i=0; i<getMaxRetriesGettingFreeNameFromAai(); i++) {
+            String newName = getUniqueNameFromDbOnly(name);
             if (isNameFreeInAai(newName, resourceType)) {
                 return newName;
             }
         }
 
-        throw new MaxRetriesException("find unused name for " + name, getMaxRetriesGettingFreeNameFromAai());
+        throw new MaxRetriesException("can't find unused name for "+name, getMaxRetriesGettingFreeNameFromAai());
+    }
+
+    @Override
+    public ServiceInstantiation prepareServiceToBeUnique(ServiceInstantiation serviceInstantiation) {
+        try {
+            ServiceInstantiation clonedServiceInstantiation = JACKSON_OBJECT_MAPPER.readValue(
+                    JACKSON_OBJECT_MAPPER.writeValueAsBytes(serviceInstantiation), ServiceInstantiation.class);
+            clonedServiceInstantiation.setBulkSize(1);
+            return replaceAllTrackById(clonedServiceInstantiation);
+        } catch (IOException e) {
+            throw new GenericUncheckedException(e);
+        }
+
+    }
+
+    private<T extends BaseResource> T replaceAllTrackById(T resource) {
+        resource.setTrackById(UUID.randomUUID().toString());
+        resource.getChildren().forEach(this::replaceAllTrackById);
+        return resource;
+    }
+
+    @Override
+    public List<UUID> retryJob(ServiceInstantiation request, UUID jobId, String userId ) {
+        updateServiceInfo(jobId, si->si.setRetryEnabled(false));
+        return pushBulkJob(request, userId);
+    }
+
+    @Override
+    public List<UUID> retryJob(UUID jobId, String userId) {
+        ServiceInstantiation serviceInstantiationRequest = asyncInstantiationRepository.getJobRequest(jobId);
+        enrichBulkForRetry(serviceInstantiationRequest, jobId);
+
+        try {
+            logger.debug(EELFLoggerDelegate.debugLogger, "retry ServiceInstantiation request: "+
+                    JACKSON_OBJECT_MAPPER.writeValueAsString(serviceInstantiationRequest));
+        } catch (Exception e) {
+            logger.error(EELFLoggerDelegate.errorLogger, "failed to log retry of ServiceInstantiation request ", e);
+        }
+        return retryJob(serviceInstantiationRequest, jobId, userId);
+    }
+
+    @Override
+    public ServiceInstantiation getBulkForRetry(UUID jobId) {
+         return enrichBulkForRetry( asyncInstantiationRepository.getJobRequest(jobId), jobId);
+    }
+
+    @Override
+    public void addResourceInfo(JobSharedData sharedData, Job.JobStatus jobStatus, String instanceId) {
+        String trackById = ((BaseResource) sharedData.getRequest()).getTrackById();
+        ResourceInfo resourceInfo = new ResourceInfo(trackById, sharedData.getRootJobId(), instanceId, jobStatus, null);
+        asyncInstantiationRepository.saveResourceInfo(resourceInfo);
+    }
+
+    @Override
+    public void addFailedResourceInfo(JobSharedData sharedData, RestObject msoResponse) {
+        String trackById = ((BaseResource) sharedData.getRequest()).getTrackById();
+        String errorMessage = MsoUtil.formatExceptionAdditionalInfo(msoResponse.getStatusCode(), msoResponse.getRaw());
+        AsyncRequestStatus asyncRequestStatus = convertMessageToAsyncRequestStatus(errorMessage);
+        ResourceInfo resourceInfo = new ResourceInfo(trackById, sharedData.getRootJobId(), null, JobStatus.FAILED, asyncRequestStatus);
+
+        asyncInstantiationRepository.saveResourceInfo(resourceInfo);
+    }
+
+    @Override
+    public void updateResourceInfo(JobSharedData sharedData, JobStatus jobStatus, AsyncRequestStatus message) {
+        ResourceInfo resourceInfo = asyncInstantiationRepository.getResourceInfoByTrackId(((BaseResource) sharedData.getRequest()).getTrackById());
+        resourceInfo.setJobStatus(jobStatus);
+        if (jobStatus.isFailure()) {
+            resourceInfo.setErrorMessage(message);
+        }
+        asyncInstantiationRepository.saveResourceInfo(resourceInfo);
+    }
+
+    public AsyncRequestStatus convertMessageToAsyncRequestStatus(String message) {
+        RequestStatus requestStatus = new RequestStatus("FAILED", message, TimeUtils.zonedDateTimeToString(ZonedDateTime.now()));
+        AsyncRequestStatus.Request request = new AsyncRequestStatus.Request(requestStatus);
+        return new AsyncRequestStatus(request);
+    }
+
+    protected String getUniqueNameFromDbOnly(String name) {
+        int counter = getCounterForName(name);
+        return formatNameAndCounter(name, counter);
     }
 
     //the method is protected so we can call it in the UT
     protected String formatNameAndCounter(String name, int counter) {
-        return name + "_" + String.format("%03d", counter);
+        return counter==0 ? name : name + "_" + String.format("%03d", counter);
     }
 
-    private boolean isNameFreeInAai(String name, ResourceType resourceType) throws InvalidAAIResponseException {
-        HttpResponse<AaiNodeQueryResponse> aaiResponse = aaiOverTLSClient
-            .searchNodeTypeByName(name, resourceType);
-        if (aaiResponse.getStatus() > 399 || aaiResponse.getBody() == null) {
-            try {
-                String message = IOUtils.toString(aaiResponse.getRawBody(), "UTF-8");
-                throw new InvalidAAIResponseException(aaiResponse.getStatus(), message);
-            } catch (IOException e) {
-                throw new InvalidAAIResponseException(aaiResponse.getStatus(), aaiResponse.getStatusText());
+    private boolean isNameFreeInAai(String name, ResourceType resourceType) throws ExceptionWithRequestInfo {
+        return !aaiClient.isNodeTypeExistsByName(name, resourceType);
+    }
+
+    @Override
+    public ServiceInstantiation enrichBulkForRetry(ServiceInstantiation serviceInstantiation, UUID jobId){
+        Map<String, ResourceInfo> resourceInfoByTrackId = asyncInstantiationRepository.getResourceInfoByRootJobId(jobId);
+
+        return setResourceStatus(resourceInfoByTrackId, serviceInstantiation);
+    }
+
+    protected String readStatusMsg(ResourceInfo resourceInfo){
+        if(resourceInfo!=null && resourceInfo.getErrorMessage()!=null && resourceInfo.getErrorMessage().request != null &&resourceInfo.getErrorMessage().request.requestStatus != null ) {
+            return resourceInfo.getErrorMessage().request.requestStatus.getStatusMessage();
+        }
+        return null;
+    }
+
+    private<T extends BaseResource> T setResourceStatus(Map<String, ResourceInfo> resourceInfoByTrackId, T resource) {
+        ResourceInfo resourceInfo = resourceInfoByTrackId.get(resource.getTrackById());
+        if(resourceInfo != null) {
+            boolean failed = resourceInfo.getJobStatus().isFailure();
+            resource.setIsFailed(failed);
+            resource.setStatusMessage(readStatusMsg(resourceInfo));
+            if (!failed) {
+                // if(resource.getAction().equals(Action.Delete)){
+                // TODO not yet implemented- completed after delete should remove the node
+                resource.setAction(Action.None);
+                resource.setInstanceId(resourceInfo.getInstanceId());
             }
         }
-        return CollectionUtils.isEmpty(aaiResponse.getBody().resultData);
+        resource.getChildren().forEach(child -> setResourceStatus(resourceInfoByTrackId, child));
+        return resource;
     }
 
 }