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 73056db..92a6d5f 100644 (file)
 
 package org.onap.vid.services;
 
-import com.fasterxml.jackson.core.type.TypeReference;
-import com.fasterxml.jackson.databind.ObjectMapper;
-import com.google.common.collect.ImmutableList;
+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 java.io.IOException;
+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.portalsdk.core.service.DataAccessService;
 import org.onap.vid.aai.AaiClientInterface;
 import org.onap.vid.aai.ExceptionWithRequestInfo;
 import org.onap.vid.aai.model.ResourceType;
-import org.onap.vid.changeManagement.RequestDetailsWrapper;
+import org.onap.vid.dal.AsyncInstantiationRepository;
 import org.onap.vid.exceptions.DbFailureUncheckedException;
 import org.onap.vid.exceptions.GenericUncheckedException;
 import org.onap.vid.exceptions.MaxRetriesException;
@@ -41,37 +51,26 @@ 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.job.impl.JobSharedData;
 import org.onap.vid.model.Action;
-import org.onap.vid.model.JobAuditStatus;
 import org.onap.vid.model.NameCounter;
+import org.onap.vid.model.ResourceInfo;
 import org.onap.vid.model.ServiceInfo;
-import org.onap.vid.model.serviceInstantiation.*;
+import org.onap.vid.model.serviceInstantiation.BaseResource;
+import org.onap.vid.model.serviceInstantiation.ServiceInstantiation;
 import org.onap.vid.mso.MsoBusinessLogicImpl;
 import org.onap.vid.mso.MsoProperties;
-import org.onap.vid.mso.model.*;
-import org.onap.vid.mso.model.ServiceInstantiationRequestDetails.RequestParameters;
-import org.onap.vid.mso.model.ServiceInstantiationRequestDetails.*;
-import org.onap.vid.mso.model.VfModuleInstantiationRequestDetails.RequestParametersVfModule;
-import org.onap.vid.mso.model.VfModuleInstantiationRequestDetails.UserParamMap;
+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.SubscriberInfo;
+import org.onap.vid.mso.rest.RequestStatus;
 import org.onap.vid.properties.Features;
 import org.onap.vid.utils.DaoUtils;
+import org.onap.vid.utils.TimeUtils;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.stereotype.Service;
 import org.togglz.core.manager.FeatureManager;
 
-import java.sql.Timestamp;
-import java.time.LocalDateTime;
-import java.util.*;
-import java.util.function.Consumer;
-import java.util.stream.Collectors;
-
-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.Logging.debugRequestDetails;
-
 @Service
 public class AsyncInstantiationBusinessLogicImpl implements
         AsyncInstantiationBusinessLogic {
@@ -79,9 +78,6 @@ public class AsyncInstantiationBusinessLogicImpl implements
     private static final int MAX_RETRIES_GETTING_COUNTER = 100;
     private static final int MAX_RETRIES_GETTING_FREE_NAME_FROM_AAI = 10000;
     public static final String NAME_FOR_CHECK_AAI_STATUS = "NAME_FOR_CHECK_AAI_STATUS";
-    private static final String VID_SOURCE = "VID";
-
-    private final DataAccessService dataAccessService;
 
     private final JobAdapter jobAdapter;
 
@@ -89,12 +85,17 @@ public class AsyncInstantiationBusinessLogicImpl implements
 
     private final CloudOwnerService cloudOwnerService;
 
+    private final AsyncInstantiationRepository asyncInstantiationRepository;
+
     private SessionFactory sessionFactory;
 
     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);
@@ -107,51 +108,34 @@ public class AsyncInstantiationBusinessLogicImpl implements
             .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,
+    public AsyncInstantiationBusinessLogicImpl(JobAdapter jobAdapter,
                                                JobsBrokerService jobService,
                                                SessionFactory sessionFactory,
                                                AaiClientInterface aaiClient,
                                                FeatureManager featureManager,
-                                               CloudOwnerService cloudOwnerService) {
-        this.dataAccessService = dataAccessService;
+                                               CloudOwnerService cloudOwnerService, AsyncInstantiationRepository asyncInstantiationRepository,
+                                               AuditService auditService) {
         this.jobAdapter = jobAdapter;
         this.jobService = jobService;
         this.sessionFactory = sessionFactory;
         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 'COMPLETED_WITH_ERRORS' 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) {
@@ -171,19 +155,26 @@ public class AsyncInstantiationBusinessLogicImpl implements
 
     @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++) {
-            ServiceInfo.ServiceAction serviceAction = getAction(request);
-            JobType jobType = getJobType(request);
-            final String optimisticUniqueServiceInstanceName = getOptimisticUniqueServiceInstanceName(request);
-            Job job = jobAdapter.createServiceInstantiationJob(jobType, request, templateId, userId, optimisticUniqueServiceInstanceName, i);
-            UUID jobId = jobService.add(job);
-            dataAccessService.saveDomainObject(createServiceInfo(userId, request, jobId, templateId, createdBulkDate, optimisticUniqueServiceInstanceName, serviceAction), DaoUtils.getPropsMap());
-            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);
+
+            jobService.add(job);
         }
         return uuids;
     }
@@ -197,8 +188,8 @@ public class AsyncInstantiationBusinessLogicImpl implements
     }
 
 
-    private String getOptimisticUniqueServiceInstanceName(ServiceInstantiation request) {
-        return StringUtils.isNotEmpty(request.getInstanceName()) ? getUniqueNameFromDbOnly(request.getInstanceName()) : request.getInstanceName();
+    private String getOptimisticUniqueServiceInstanceName(String instanceName) {
+        return StringUtils.isNotEmpty(instanceName) ? getUniqueNameFromDbOnly(instanceName) : instanceName;
     }
 
     protected ServiceInfo createServiceInfo(String userId, ServiceInstantiation serviceInstantiation, UUID jobId, UUID templateId, Date createdBulkDate, String optimisticUniqueServiceInstanceName, ServiceInfo.ServiceAction serviceAction) {
@@ -224,359 +215,32 @@ public class AsyncInstantiationBusinessLogicImpl implements
                 serviceInstantiation.getModelInfo().getModelName(),
                 serviceInstantiation.getModelInfo().getModelVersion(),
                 createdBulkDate,
-                serviceAction
-        );
-    }
-
-
-    @Override
-    public RequestDetailsWrapper<ServiceInstantiationRequestDetails> generateMacroServiceInstantiationRequest(UUID jobId, ServiceInstantiation payload, String optimisticUniqueServiceInstanceName, String userId) {
-        String serviceInstanceName = generateServiceName(jobId, payload, optimisticUniqueServiceInstanceName);
-
-        List<ServiceInstantiationService> serviceInstantiationServiceList = generateServiceInstantiationServicesList(payload, serviceInstanceName, createServiceInstantiationVnfList(payload));
-
-        RequestParameters requestParameters = new RequestParameters(payload.getSubscriptionServiceType(), false, serviceInstantiationServiceList);
-
-        ServiceInstantiationRequestDetails requestDetails = generateServiceInstantiationRequestDetails(payload,requestParameters,serviceInstanceName, userId);
-
-        RequestDetailsWrapper<ServiceInstantiationRequestDetails> requestDetailsWrapper = new RequestDetailsWrapper<>(requestDetails);
-        debugRequestDetails(requestDetailsWrapper, logger);
-
-        return requestDetailsWrapper;
+                serviceAction,
+                false);
     }
 
     @Override
-    public RequestDetailsWrapper<ServiceInstantiationRequestDetails> generateALaCarteServiceInstantiationRequest(UUID jobId, ServiceInstantiation payload, String optimisticUniqueServiceInstanceName, String userId) {
-        String serviceInstanceName = generateServiceName(jobId, payload, optimisticUniqueServiceInstanceName);
-
-        List<UserParamNameAndValue> userParams = generateUserParamList();
-
-        RequestParameters requestParameters = new RequestParameters(payload.getSubscriptionServiceType(), true, userParams, payload.getTestApi());
-
-        ServiceInstantiationRequestDetails requestDetails = generateServiceInstantiationRequestDetails(payload,requestParameters,serviceInstanceName, userId);
-
-        RequestDetailsWrapper<ServiceInstantiationRequestDetails> requestDetailsWrapper = new RequestDetailsWrapper<>(requestDetails);
-        debugRequestDetails(requestDetailsWrapper, logger);
-        return requestDetailsWrapper;
-    }
-
-
-    @Override
-    public RequestDetailsWrapper<ServiceDeletionRequestDetails> generateALaCarteServiceDeletionRequest(UUID jobId, ServiceInstantiation payload, String userId){
-
-        ServiceDeletionRequestDetails.RequestParameters requestParameters = new ServiceDeletionRequestDetails.RequestParameters( true, payload.getTestApi());
-
-        ServiceDeletionRequestDetails.RequestInfo requestInfo = new ServiceDeletionRequestDetails.RequestInfo(
-                VID_SOURCE,
-                userId);
-
-        ServiceDeletionRequestDetails requestDetails = new ServiceDeletionRequestDetails(payload.getModelInfo(), requestInfo, requestParameters);
-
-        RequestDetailsWrapper<ServiceDeletionRequestDetails> requestDetailsWrapper = new RequestDetailsWrapper<>(requestDetails);
-        debugRequestDetails(requestDetailsWrapper, logger);
-        return requestDetailsWrapper;
+    public boolean isPartOfBulk(UUID jobId) {
+        if (jobId == null) {
+            return false;
     }
-
-    @Override
-    public RequestDetailsWrapper<VnfInstantiationRequestDetails> generateVnfInstantiationRequest(Vnf vnfDetails, ModelInfo serviceModelInfo, String serviceInstanceId, String userId) {
-
-        VnfInstantiationRequestDetails.RequestInfo requestInfo = new VnfInstantiationRequestDetails.RequestInfo(
-                getUniqueNameIfNeeded(vnfDetails.getInstanceName(), ResourceType.GENERIC_VNF),
-                vnfDetails.getProductFamilyId(),
-                VID_SOURCE,
-                vnfDetails.isRollbackOnFailure(),
-                userId);
-        CloudConfiguration cloudConfiguration = generateCloudConfiguration(vnfDetails.getLcpCloudRegionId(), vnfDetails.getTenantId());
-        VnfInstantiationRequestDetails.Platform platform = new VnfInstantiationRequestDetails.Platform(vnfDetails.getPlatformName());
-        VnfInstantiationRequestDetails.LineOfBusiness lineOfBusiness = new VnfInstantiationRequestDetails.LineOfBusiness(vnfDetails.getLineOfBusiness());
-        VnfInstantiationRequestDetails.RequestParameters requestParameters = new VnfInstantiationRequestDetails.RequestParameters(generateUserParamList());
-        VnfInstantiationRequestDetails.RelatedInstance serviceInstance = new VnfInstantiationRequestDetails.RelatedInstance(serviceModelInfo, serviceInstanceId);
-        List<VnfInstantiationRequestDetails.RelatedInstance> relatedInstanceList = new ArrayList<>();
-        relatedInstanceList.add(serviceInstance);
-        return new RequestDetailsWrapper<>(new VnfInstantiationRequestDetails(vnfDetails.getModelInfo(), cloudConfiguration, requestInfo, platform, lineOfBusiness, relatedInstanceList, requestParameters));
+        ServiceInfo serviceInfo = asyncInstantiationRepository.getServiceInfoByJobId(jobId);
+        UUID templateId = serviceInfo.getTemplateId();
+        if (templateId != null) {
+            return getNumberOfJobsInBulk(templateId) > 1;
     }
+        return false;
 
-    @Override
-    public RequestDetailsWrapper<VfModuleInstantiationRequestDetails> generateVfModuleInstantiationRequest(VfModule vfModuleDetails, ModelInfo serviceModelInfo, String serviceInstanceId, ModelInfo vnfModelInfo, String vnfInstanceId, String vgInstanceId, String userId) {
-
-        VfModuleInstantiationRequestDetails.RequestInfo requestInfo = new VfModuleInstantiationRequestDetails.RequestInfo(
-                getUniqueNameIfNeeded(vfModuleDetails.getInstanceName(), ResourceType.VF_MODULE),
-                null,
-                VID_SOURCE,
-                vfModuleDetails.isRollbackOnFailure(),
-                userId);
-
-        //cloud configuration
-        CloudConfiguration cloudConfiguration = generateCloudConfiguration(vfModuleDetails.getLcpCloudRegionId(), vfModuleDetails.getTenantId());
-
-        //request parameters
-        List<UserParamMap<String, String>> userParams = aggregateAllInstanceParams(extractActualInstanceParams(vfModuleDetails.getInstanceParams()), vfModuleDetails.getSupplementaryParams());
-        RequestParametersVfModule requestParameters = new RequestParametersVfModule(userParams, vfModuleDetails.isUsePreload());
-
-        //related instance list
-        VfModuleInstantiationRequestDetails.RelatedInstance serviceInstance = new VfModuleInstantiationRequestDetails.RelatedInstance(serviceModelInfo, serviceInstanceId);
-        VfModuleInstantiationRequestDetails.RelatedInstance vnfInstance = new VfModuleInstantiationRequestDetails.RelatedInstance(vnfModelInfo, vnfInstanceId);
-        List<VfModuleInstantiationRequestDetails.RelatedInstance> relatedInstanceList = new ArrayList<>();
-        relatedInstanceList.add(serviceInstance);
-        relatedInstanceList.add(vnfInstance);
-        if (vgInstanceId != null) {
-            ModelInfo volumeGroupModel = new ModelInfo();
-            volumeGroupModel.setModelType("volumeGroup");
-            VfModuleInstantiationRequestDetails.RelatedInstance volumeGroupInstance = new VfModuleInstantiationRequestDetails.RelatedInstance(volumeGroupModel, vgInstanceId, vfModuleDetails.getVolumeGroupInstanceName());
-            relatedInstanceList.add(volumeGroupInstance);
-        }
-
-        return new RequestDetailsWrapper<>(new VfModuleInstantiationRequestDetails(vfModuleDetails.getModelInfo(), cloudConfiguration, requestInfo, relatedInstanceList, requestParameters));
     }
 
-    protected CloudConfiguration generateCloudConfiguration(String lcpCloudRegionId, String tenantId) {
-        CloudConfiguration cloudConfiguration = new CloudConfiguration();
-        cloudConfiguration.setLcpCloudRegionId(lcpCloudRegionId);
-        cloudConfiguration.setTenantId(tenantId);
-        cloudOwnerService.enrichCloudConfigurationWithCloudOwner(cloudConfiguration, lcpCloudRegionId);
-        return cloudConfiguration;
-    }
-
-    @Override
-    public RequestDetailsWrapper<VolumeGroupRequestDetails> generateVolumeGroupInstantiationRequest(VfModule vfModuleDetails, ModelInfo serviceModelInfo, String serviceInstanceId, ModelInfo vnfModelInfo, String vnfInstanceId, String userId) {
-        VolumeGroupRequestDetails.RequestInfo requestInfo = new VolumeGroupRequestDetails.RequestInfo(
-                getUniqueNameIfNeeded(vfModuleDetails.getVolumeGroupInstanceName(), ResourceType.VOLUME_GROUP),
-                null,
-                VID_SOURCE,
-                vfModuleDetails.isRollbackOnFailure(),
-                userId);
-        CloudConfiguration cloudConfiguration = generateCloudConfiguration(vfModuleDetails.getLcpCloudRegionId(), vfModuleDetails.getTenantId());
-
-        List<UserParamMap<String, String>> userParams = aggregateAllInstanceParams(extractActualInstanceParams(vfModuleDetails.getInstanceParams()), vfModuleDetails.getSupplementaryParams());
-        RequestParametersVfModule requestParameters = new RequestParametersVfModule(userParams, vfModuleDetails.isUsePreload());
-
-        VfModuleInstantiationRequestDetails.RelatedInstance serviceInstance = new VfModuleInstantiationRequestDetails.RelatedInstance(serviceModelInfo, serviceInstanceId);
-        VfModuleInstantiationRequestDetails.RelatedInstance vnfInstance = new VfModuleInstantiationRequestDetails.RelatedInstance(vnfModelInfo, vnfInstanceId);
-        List<VfModuleInstantiationRequestDetails.RelatedInstance> relatedInstancs = ImmutableList.of(serviceInstance, vnfInstance);
-
-        ModelInfo modelInfo = vfModuleDetails.getModelInfo();
-        modelInfo.setModelType("volumeGroup");
-        return new RequestDetailsWrapper<>(new VolumeGroupRequestDetails(modelInfo, cloudConfiguration, requestInfo, relatedInstancs, requestParameters));
-    }
-
-    protected List<UserParamMap<String, String>> aggregateAllInstanceParams(Map<String, String> instanceParams, Map<String, String> supplementaryParams) {
-        Map<String, String> instanceParamsFinal = defaultIfNull(instanceParams, new HashMap<>());
-        Map<String, String> supplementaryParamsFinal = defaultIfNull(supplementaryParams, new HashMap<>());
-
-        if (!(instanceParamsFinal.isEmpty() && supplementaryParamsFinal.isEmpty())) {
-            //remove duplicate keys from instanceParams if exist in supplementaryParams
-            instanceParamsFinal = instanceParams.entrySet().stream().filter(m->
-                    !supplementaryParamsFinal.containsKey(m.getKey())
-            ).collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue));
-
-            //aggregate the 2 collections and format them as UserParamMap
-            UserParamMap<String, String> aggregatedParams = new UserParamMap<>();
-            aggregatedParams.putAll(instanceParamsFinal);
-            aggregatedParams.putAll(supplementaryParamsFinal);
-
-            return ImmutableList.of(aggregatedParams);
-        }
-
-        return Collections.emptyList();
-    }
-
-    @Override
-    public RequestDetailsWrapper<NetworkInstantiationRequestDetails> generateNetworkInstantiationRequest(Network networkDetails, ModelInfo serviceModelInfo, String serviceInstanceId, String userId) {
-
-        NetworkInstantiationRequestDetails.RequestInfo requestInfo = new NetworkInstantiationRequestDetails.RequestInfo(
-                getUniqueNameIfNeeded(networkDetails.getInstanceName(), ResourceType.L3_NETWORK),
-                networkDetails.getProductFamilyId(),
-                VID_SOURCE,
-                networkDetails.isRollbackOnFailure(),
-                userId);
-        CloudConfiguration cloudConfiguration = generateCloudConfiguration(networkDetails.getLcpCloudRegionId(), networkDetails.getTenantId());
-        NetworkInstantiationRequestDetails.Platform platform = new NetworkInstantiationRequestDetails.Platform(networkDetails.getPlatformName());
-        NetworkInstantiationRequestDetails.LineOfBusiness lineOfBusiness = new NetworkInstantiationRequestDetails.LineOfBusiness(networkDetails.getLineOfBusiness());
-        NetworkInstantiationRequestDetails.RequestParameters requestParameters = new NetworkInstantiationRequestDetails.RequestParameters(generateUserParamList());
-        NetworkInstantiationRequestDetails.RelatedInstance serviceInstance = new NetworkInstantiationRequestDetails.RelatedInstance(serviceModelInfo, serviceInstanceId);
-        List<NetworkInstantiationRequestDetails.RelatedInstance> relatedInstanceList = new ArrayList<>();
-        relatedInstanceList.add(serviceInstance);
-        return new RequestDetailsWrapper<>(new NetworkInstantiationRequestDetails(networkDetails.getModelInfo(), cloudConfiguration, requestInfo, platform, lineOfBusiness, relatedInstanceList, requestParameters));
-    }
-
-    @Override
-    public RequestDetailsWrapper<InstanceGroupInstantiationRequestDetails> generateInstanceGroupInstantiationRequest(InstanceGroup instanceGroupDetails, ModelInfo serviceModelInfo, String serviceInstanceId, String userId) {
-        InstanceGroupInstantiationRequestDetails.RequestInfo requestInfo = new InstanceGroupInstantiationRequestDetails.RequestInfo(
-                getUniqueNameIfNeeded(instanceGroupDetails.getInstanceName(), ResourceType.INSTANCE_GROUP),
-                null,
-                "VID",
-                instanceGroupDetails.isRollbackOnFailure(),
-                userId);
-        InstanceGroupInstantiationRequestDetails.RequestParameters requestParameters = new InstanceGroupInstantiationRequestDetails.RequestParameters(generateUserParamList());
-        InstanceGroupInstantiationRequestDetails.RelatedInstance serviceInstance = new InstanceGroupInstantiationRequestDetails.RelatedInstance(serviceModelInfo, serviceInstanceId);
-        List<InstanceGroupInstantiationRequestDetails.RelatedInstance> relatedInstanceList = ImmutableList.of(serviceInstance);
-        return new RequestDetailsWrapper<>(new InstanceGroupInstantiationRequestDetails(instanceGroupDetails.getModelInfo(), requestInfo, relatedInstanceList, requestParameters));
-    }
-
-    // TODO
-    private List<UserParamNameAndValue> generateUserParamList() {
-        return Collections.emptyList();
-    }
-
-    protected List<ServiceInstantiationService> generateServiceInstantiationServicesList(ServiceInstantiation payload, String serviceInstanceName, ServiceInstantiationVnfList vnfList) {
-        List<ServiceInstantiationService> serviceInstantiationServiceList = new LinkedList<>();
-        List<Map<String, String>> unFilteredInstanceParams = defaultIfNull(payload.getInstanceParams(), Collections.emptyList());
-        List<Map<String, String>> filteredInstanceParams = removeUnNeededParams(unFilteredInstanceParams);
-        ServiceInstantiationService serviceInstantiationService = new ServiceInstantiationService(
-                payload.getModelInfo(),
-                serviceInstanceName,
-                filteredInstanceParams,
-                vnfList
+    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()
         );
-        serviceInstantiationServiceList.add(serviceInstantiationService);
-        return serviceInstantiationServiceList;
-    }
-
-    private ServiceInstantiationRequestDetails generateServiceInstantiationRequestDetails(ServiceInstantiation payload, RequestParameters requestParameters, String serviceInstanceName, String userId) {
-        ServiceInstantiationRequestDetails.RequestInfo requestInfo = new ServiceInstantiationRequestDetails.RequestInfo(serviceInstanceName,
-                payload.getProductFamilyId(),
-                VID_SOURCE,
-                payload.isRollbackOnFailure(),
-                userId);
-        ServiceInstantiationOwningEntity owningEntity = new ServiceInstantiationOwningEntity(payload.getOwningEntityId(), payload.getOwningEntityName());
-        SubscriberInfo subscriberInfo = generateSubscriberInfo(payload);
-        Project project = payload.getProjectName() != null ?  new Project(payload.getProjectName()) : null;
-        return new ServiceInstantiationRequestDetails(payload.getModelInfo(), owningEntity, subscriberInfo, project, requestInfo, requestParameters);
-    }
-
-
-    protected SubscriberInfo generateSubscriberInfo(ServiceInstantiation payload) {
-        SubscriberInfo subscriberInfo = new SubscriberInfo();
-        subscriberInfo.setGlobalSubscriberId(payload.getGlobalSubscriberId());
-        return subscriberInfo;
-    }
-
-    protected String generateServiceName(UUID jobId, ServiceInstantiation payload, String optimisticUniqueServiceInstanceName) {
-        String serviceInstanceName = null;
-        if(StringUtils.isNotEmpty(optimisticUniqueServiceInstanceName)) {
-            serviceInstanceName = peekServiceName(jobId, payload, optimisticUniqueServiceInstanceName);
-        }
-        return serviceInstanceName;
-    }
-
-    protected String peekServiceName(UUID jobId, ServiceInstantiation payload, String optimisticUniqueServiceInstanceName) {
-        String serviceInstanceName;
-        // unique name already exist in service info. If it's free in AAI we use it
-        if (isNameFreeInAai(optimisticUniqueServiceInstanceName, ResourceType.SERVICE_INSTANCE)) {
-            serviceInstanceName =  optimisticUniqueServiceInstanceName;
-        }
-        //otherwise we used the original service instance name (from payload) to get a new unique name from DB and AAI
-        else {
-            serviceInstanceName = getUniqueName(payload.getInstanceName(), ResourceType.SERVICE_INSTANCE);
-        }
-
-        //update serviceInfo with new name if needed
-        try {
-            updateServiceInfo(jobId, x -> x.setServiceInstanceName(serviceInstanceName));
-        } catch (Exception e) {
-            logger.error("Failed updating service name {} in serviceInfo", serviceInstanceName, e);
-        }
-
-        return serviceInstanceName;
-    }
-
-    @Override
-    public List<Map<String,String>> buildVnfInstanceParams(List<Map<String, String>> currentVnfInstanceParams, List<VfModuleMacro> vfModules){
-        List<Map<String, String>> filteredVnfInstanceParams = removeUnNeededParams(currentVnfInstanceParams);
-
-        if (!featureManager.isActive(Features.FLAG_SHIFT_VFMODULE_PARAMS_TO_VNF)) {
-            return filteredVnfInstanceParams;
-        }
-
-        Map<String,String> vnfInstanceParams = extractActualInstanceParams(filteredVnfInstanceParams);
-        vfModules.stream()
-                .map(x->extractActualInstanceParams(x.getInstanceParams()))
-                .forEach(vnfInstanceParams::putAll);
-        return vnfInstanceParams.isEmpty() ? Collections.emptyList() : ImmutableList.of(vnfInstanceParams);
-    }
-
-    //Make sure we always get a one Map from InstanceParams
-    private Map<String, String> extractActualInstanceParams(List<Map<String, String>> originalInstanceParams) {
-        if (originalInstanceParams==null || originalInstanceParams.isEmpty() || originalInstanceParams.get(0)==null) {
-            return new HashMap<>();
-        }
-        return originalInstanceParams.get(0);
-    }
-
-    private List<Map<String, String>> removeUnNeededParams(List<Map<String, String>> instanceParams) {
-        List<String> keysToRemove = new ArrayList<>();
-        if (instanceParams == null || instanceParams.isEmpty()) {
-            return Collections.emptyList();
-        }
-
-        for (String key : instanceParams.get(0).keySet()) {
-            for (String paramToIgnore : PARAMS_TO_IGNORE)
-                if ((key.equalsIgnoreCase(paramToIgnore))) {
-                    keysToRemove.add(key);
-                }
-        }
-
-        Map<String, String> result = instanceParams.get(0).entrySet().stream()
-                .filter(entry->!keysToRemove.contains(entry.getKey()))
-                .collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue));
-
-        return result.isEmpty() ?  Collections.emptyList() : Collections.singletonList(result);
-    }
-
-    private ServiceInstantiationVnfList createServiceInstantiationVnfList(ServiceInstantiation payload) {
-        CloudConfiguration cloudConfiguration = generateCloudConfiguration(payload.getLcpCloudRegionId(), payload.getTenantId());
-
-        Map<String, Vnf> vnfs = payload.getVnfs();
-        List<ServiceInstantiationVnf> vnfList = new ArrayList<>();
-        for (Vnf vnf : vnfs.values()) {
-            Map<String, Map<String, VfModule>> vfModules = vnf.getVfModules();
-            List<VfModuleMacro> convertedUnFilteredVfModules = convertVfModuleMapToList(vfModules);
-            List<VfModuleMacro> filteredVfModules = filterInstanceParamsFromVfModuleAndUniqueNames(convertedUnFilteredVfModules);
-            ServiceInstantiationVnf serviceInstantiationVnf = new ServiceInstantiationVnf(
-                    vnf.getModelInfo(),
-                    cloudConfiguration,
-                    vnf.getPlatformName(),
-                    vnf.getLineOfBusiness(),
-                    payload.getProductFamilyId(),
-                    buildVnfInstanceParams(vnf.getInstanceParams(), filteredVfModules),
-                    filteredVfModules,
-                    getUniqueNameIfNeeded(vnf.getInstanceName(), ResourceType.GENERIC_VNF)
-            );
-            vnfList.add(serviceInstantiationVnf);
-        }
-
-        return new ServiceInstantiationVnfList(vnfList);
-    }
-
-    private List<VfModuleMacro> convertVfModuleMapToList(Map<String, Map<String, VfModule>> vfModules) {
-        ObjectMapper mapper = new ObjectMapper();
-        return vfModules.values().stream().flatMap(vfModule ->
-                vfModule.values().stream().map(item -> {
-                    List<UserParamMap<String, String>> aggregatedParams = aggregateAllInstanceParams(extractActualInstanceParams(item.getInstanceParams()), item.getSupplementaryParams());
-                    List<Map<String, String>> aggregatedParamsConverted = mapper.convertValue(aggregatedParams, new TypeReference<List<Map>>(){});
-
-                    return new VfModuleMacro(
-                            item.getModelInfo(),
-                            item.getInstanceName(),
-                            item.getVolumeGroupInstanceName(),
-                            aggregatedParamsConverted);
-                    }
-                )
-        ).collect(Collectors.toList());
-    }
-
-    private List<VfModuleMacro> filterInstanceParamsFromVfModuleAndUniqueNames(List<VfModuleMacro> unFilteredVfModules) {
-        return unFilteredVfModules.stream().map(vfModule ->
-                new VfModuleMacro(
-                        vfModule.getModelInfo(),
-                        getUniqueNameIfNeeded(vfModule.getInstanceName(), ResourceType.VF_MODULE),
-                        getUniqueNameIfNeeded(vfModule.getVolumeGroupInstanceName(), ResourceType.VOLUME_GROUP),
-                        removeUnNeededParams(vfModule.getInstanceParams())))
-                .collect(Collectors.toList());
-    }
-
-    private String getUniqueNameIfNeeded(String name, ResourceType resourceType) {
-        return StringUtils.isNotEmpty(name) ? getUniqueName(name, resourceType) : null;
     }
 
     @Override
@@ -599,6 +263,13 @@ public class AsyncInstantiationBusinessLogicImpl implements
                 replaceFirst(SVC_INSTANCE_ID, serviceInstanceId);
     }
 
+    @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);
+    }
+
     @Override
     public String getNetworkInstantiationPath(String serviceInstanceId) {
         return MsoBusinessLogicImpl.validateEndpointPath(MsoProperties.MSO_REST_API_NETWORK_INSTANCE).
@@ -612,6 +283,24 @@ public class AsyncInstantiationBusinessLogicImpl implements
                 .replaceFirst(VNF_INSTANCE_ID, vnfInstanceId);
     }
 
+    @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 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 getVolumeGroupInstantiationPath(String serviceInstanceId, String vnfInstanceId) {
         return MsoBusinessLogicImpl.validateEndpointPath(MsoProperties.MSO_REST_API_VOLUME_GROUP_INSTANCE)
@@ -625,79 +314,64 @@ public class AsyncInstantiationBusinessLogicImpl implements
     }
 
     @Override
-    public String getInstanceGroupDeletePath(String instanceGroupId) {
+    public String getInstanceGroupMemberInstantiationPath(String vnfGroupInstanceId) {
         return MsoBusinessLogicImpl.validateEndpointPath(MsoProperties.MSO_REST_API_INSTANCE_GROUP)
-                + '/' + instanceGroupId;
+                + '/' + vnfGroupInstanceId + "/addMembers";
     }
 
     @Override
-    public String getOrchestrationRequestsPath() {
-        return MsoBusinessLogicImpl.validateEndpointPath(MsoProperties.MSO_REST_API_GET_ORC_REQ);
+    public String getInstanceGroupDeletePath(String instanceGroupId) {
+        return MsoBusinessLogicImpl.validateEndpointPath(MsoProperties.MSO_REST_API_INSTANCE_GROUP)
+                + '/' + instanceGroupId;
     }
 
     @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 getInstanceGroupMemberDeletePath(String vnfGroupInstanceId){
+        return MsoBusinessLogicImpl.validateEndpointPath(MsoProperties.MSO_REST_API_INSTANCE_GROUP)
+                + '/' + vnfGroupInstanceId + "/removeMembers";
     }
 
     @Override
-    public ServiceInfo updateServiceInfoAndAuditStatus(UUID jobUuid, JobStatus jobStatus) {
-        auditVidStatus(jobUuid,jobStatus);
-        return updateServiceInfo(jobUuid, x -> setServiceInfoStatus(x, jobStatus));
-    }
-
-    private void setServiceInfoStatus(ServiceInfo serviceInfo, JobStatus jobStatus) {
-        serviceInfo.setJobStatus(jobStatus);
-        serviceInfo.setStatusModifiedDate(new Date());
-    }
-
-    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);
+    public String getNetworkDeletePath(String serviceInstanceId, String networkInstanceId) {
+        return (MsoBusinessLogicImpl.validateEndpointPath(MsoProperties.MSO_REST_API_NETWORK_INSTANCE)
+                + "/" + networkInstanceId)
+                .replaceFirst(SVC_INSTANCE_ID, serviceInstanceId);
     }
 
-    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);
-    }
-
-    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) {
@@ -708,13 +382,8 @@ public class AsyncInstantiationBusinessLogicImpl implements
 
     @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));
     }
 
@@ -727,16 +396,16 @@ public class AsyncInstantiationBusinessLogicImpl implements
 
     @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",
+            String message = String.format("jobId %s: Service status does not allow hide service, status = %s",
                     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
@@ -818,7 +487,84 @@ public class AsyncInstantiationBusinessLogicImpl implements
             }
         }
 
-        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) {
@@ -835,4 +581,35 @@ public class AsyncInstantiationBusinessLogicImpl implements
         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());
+            }
+        }
+        resource.getChildren().forEach(child -> setResourceStatus(resourceInfoByTrackId, child));
+        return resource;
+    }
+
 }