class WorkflowAction {

    public void selectExecutionList(DelegateExecution execution) throws Exception {
        try {
            final String bpmnRequest = (String) execution.getVariable(BBConstants.G_BPMN_REQUEST);
            ServiceInstancesRequest sIRequest =
                    new ObjectMapper().readValue(bpmnRequest, ServiceInstancesRequest.class);

            final String requestId = (String) execution.getVariable(BBConstants.G_REQUEST_ID);

            String uri = (String) execution.getVariable(BBConstants.G_URI);
            boolean isResume = isUriResume(uri);

            final boolean isALaCarte = (boolean) execution.getVariable(BBConstants.G_ALACARTE);
            Resource resource = getResource(bbInputSetupUtils, isResume, isALaCarte, uri, requestId);

            WorkflowResourceIds workflowResourceIds = populateResourceIdsFromApiHandler(execution);
            RequestDetails requestDetails = sIRequest.getRequestDetails();
            String requestAction = (String) execution.getVariable(BBConstants.G_ACTION);
            String resourceId = getResourceId(resource, requestAction, requestDetails, workflowResourceIds);
            WorkflowType resourceType = resource.getResourceType();

            String serviceInstanceId = getServiceInstanceId(execution, resourceId, resourceType);

            fillExecution(execution, requestDetails.getRequestInfo().getSuppressRollback(), resourceId, resourceType);
            List<ExecuteBuildingBlock> flowsToExecute = new ArrayList<>();

            if (isRequestMacroServiceResume(isALaCarte, resourceType, requestAction, serviceInstanceId)) {
                String errorMessage = "Could not resume Macro flow. Error loading execution path.";
                flowsToExecute = loadExecuteBuildingBlocks(execution, requestId, errorMessage);
            } else if (isALaCarte && isResume) {
                String errorMessage =
                        "Could not resume request with request Id: " + requestId + ". No flowsToExecute was found";
                flowsToExecute = loadExecuteBuildingBlocks(execution, requestId, errorMessage);
            } else {
                String vnfType = (String) execution.getVariable(VNF_TYPE);
                String cloudOwner = getCloudOwner(requestDetails.getCloudConfiguration());
                List<OrchestrationFlow> orchFlows =
                        (List<OrchestrationFlow>) execution.getVariable(BBConstants.G_ORCHESTRATION_FLOW);
                final String apiVersion = (String) execution.getVariable(BBConstants.G_APIVERSION);
                final String serviceType =
                        Optional.ofNullable((String) execution.getVariable(BBConstants.G_SERVICE_TYPE)).orElse("");
                if (isALaCarte) {
                    if (orchFlows == null || orchFlows.isEmpty()) {
                        orchFlows = queryNorthBoundRequestCatalogDb(execution, requestAction, resourceType, true,
                                cloudOwner, serviceType);
                    }
                    Resource resourceKey = getResourceKey(sIRequest, resourceType);

                    ReplaceInstanceRelatedInformation replaceInfo = new ReplaceInstanceRelatedInformation();
                    if ((requestAction.equalsIgnoreCase(REPLACEINSTANCE)
                            || requestAction.equalsIgnoreCase(REPLACEINSTANCERETAINASSIGNMENTS))
                            && resourceType.equals(WorkflowType.VFMODULE)) {
                        logger.debug("Build a BB list for replacing BB modules");
                        ConfigBuildingBlocksDataObject cbbdo = createConfigBuildingBlocksDataObject(execution,
                                sIRequest, requestId, workflowResourceIds, requestDetails, requestAction, resourceId,
                                vnfType, orchFlows, apiVersion, resourceKey, replaceInfo);
                        orchFlows = getVfModuleReplaceBuildingBlocks(cbbdo);

                        createBuildingBlocksForOrchFlows(execution, sIRequest, requestId, workflowResourceIds,
                                requestDetails, requestAction, resourceId, flowsToExecute, vnfType, orchFlows,
                                apiVersion, resourceKey, replaceInfo);
                    } else {
                        if (isConfiguration(orchFlows) && !requestAction.equalsIgnoreCase(CREATEINSTANCE)) {
                            addConfigBuildingBlocksToFlowsToExecuteList(execution, sIRequest, requestId,
                                    workflowResourceIds, requestDetails, requestAction, resourceId, flowsToExecute,
                                    vnfType, apiVersion, resourceKey, replaceInfo, orchFlows);
                        }
                        orchFlows =
                                orchFlows.stream().filter(item -> !item.getFlowName().contains(FABRIC_CONFIGURATION))
                                        .collect(Collectors.toList());

                        for (OrchestrationFlow orchFlow : orchFlows) {
                            ExecuteBuildingBlock ebb = buildExecuteBuildingBlock(orchFlow, requestId, resourceKey,
                                    apiVersion, resourceId, requestAction, true, vnfType, workflowResourceIds,
                                    requestDetails, false, null, null, false, replaceInfo);
                            flowsToExecute.add(ebb);
                        }
                    }
                } else {
                    boolean foundRelated = false;
                    boolean containsService = false;
                    List<Resource> resourceList = new ArrayList<>();
                    List<Pair<WorkflowType, String>> aaiResourceIds = new ArrayList<>();
                    if (resourceType == WorkflowType.SERVICE && requestAction.equalsIgnoreCase(ASSIGNINSTANCE)) {
                        // SERVICE-MACRO-ASSIGN will always get user params with a
                        // service.
                        if (sIRequest.getRequestDetails().getRequestParameters().getUserParams() != null) {
                            containsService = isContainsService(sIRequest);
                            if (containsService) {
                                traverseUserParamsService(execution, resourceList, sIRequest, requestAction);
                            }
                        } else {
                            buildAndThrowException(execution,
                                    "Service-Macro-Assign request details must contain user params with a service");
                        }
                    } else if (resourceType == WorkflowType.SERVICE && requestAction.equalsIgnoreCase(CREATEINSTANCE)) {
                        // SERVICE-MACRO-CREATE will get user params with a service,
                        // a service with a network, a service with a
                        // networkcollection, OR an empty service.
                        // If user params is just a service or null and macro
                        // queries the SI and finds a VNF, macro fails.

                        if (sIRequest.getRequestDetails().getRequestParameters().getUserParams() != null) {
                            containsService = isContainsService(sIRequest);
                        }
                        if (containsService) {
                            foundRelated = traverseUserParamsService(execution, resourceList, sIRequest, requestAction);
                        }
                        if (!foundRelated) {
                            traverseCatalogDbService(execution, sIRequest, resourceList, aaiResourceIds);
                        }
                    } else if (resourceType == WorkflowType.SERVICE
                            && ("activateInstance".equalsIgnoreCase(requestAction)
                                    || "unassignInstance".equalsIgnoreCase(requestAction)
                                    || "deleteInstance".equalsIgnoreCase(requestAction)
                                    || requestAction.equalsIgnoreCase("activate" + FABRIC_CONFIGURATION))) {
                        // SERVICE-MACRO-ACTIVATE, SERVICE-MACRO-UNASSIGN, and
                        // SERVICE-MACRO-DELETE
                        // Will never get user params with service, macro will have
                        // to query the SI in AAI to find related instances.
                        traverseAAIService(execution, resourceList, resourceId, aaiResourceIds);
                    } else if (resourceType == WorkflowType.SERVICE
                            && "deactivateInstance".equalsIgnoreCase(requestAction)) {
                        resourceList.add(new Resource(WorkflowType.SERVICE, "", false));
                    } else if (resourceType == WorkflowType.VNF && (REPLACEINSTANCE.equalsIgnoreCase(requestAction)
                            || ("recreateInstance".equalsIgnoreCase(requestAction)))) {
                        traverseAAIVnf(execution, resourceList, workflowResourceIds.getServiceInstanceId(),
                                workflowResourceIds.getVnfId(), aaiResourceIds);
                    } else if (resourceType == WorkflowType.VNF && "updateInstance".equalsIgnoreCase(requestAction)) {
                        customTraverseAAIVnf(execution, resourceList, workflowResourceIds.getServiceInstanceId(),
                                workflowResourceIds.getVnfId(), aaiResourceIds);
                    } else {
                        buildAndThrowException(execution, "Current Macro Request is not supported");
                    }
                    StringBuilder foundObjects = new StringBuilder();
                    for (WorkflowType type : WorkflowType.values()) {
                        foundObjects.append(type).append(" - ").append(
                                (int) resourceList.stream().filter(x -> type.equals(x.getResourceType())).count())
                                .append("    ");
                    }
                    logger.info("Found {}", foundObjects);

                    if (orchFlows == null || orchFlows.isEmpty()) {
                        orchFlows = queryNorthBoundRequestCatalogDb(execution, requestAction, resourceType, isALaCarte,
                                cloudOwner, serviceType);
                    }
                    boolean vnfReplace = false;
                    if (resourceType.equals(WorkflowType.VNF) && (REPLACEINSTANCE.equalsIgnoreCase(requestAction)
                            || REPLACEINSTANCERETAINASSIGNMENTS.equalsIgnoreCase(requestAction))) {
                        vnfReplace = true;
                    }
                    flowsToExecute = buildExecuteBuildingBlockList(orchFlows, resourceList, requestId, apiVersion,
                            resourceId, requestAction, vnfType, workflowResourceIds, requestDetails, vnfReplace);
                    if (isNetworkCollectionInTheResourceList(resourceList)) {
                        logger.info("Sorting for Vlan Tagging");
                        flowsToExecute = sortExecutionPathByObjectForVlanTagging(flowsToExecute, requestAction);
                    }
                    // By default, enable homing at VNF level for CREATEINSTANCE and ASSIGNINSTANCE
                    if (resourceType == WorkflowType.SERVICE
                            && (requestAction.equals(CREATEINSTANCE) || requestAction.equals(ASSIGNINSTANCE))
                            && resourceList.stream().anyMatch(x -> WorkflowType.VNF.equals(x.getResourceType()))) {
                        execution.setVariable(HOMING, true);
                        execution.setVariable("calledHoming", false);
                    }
                    if (resourceType == WorkflowType.SERVICE && (requestAction.equalsIgnoreCase(ASSIGNINSTANCE)
                            || requestAction.equalsIgnoreCase(CREATEINSTANCE))) {
                        generateResourceIds(flowsToExecute, resourceList, serviceInstanceId);
                    } else {
                        updateResourceIdsFromAAITraversal(flowsToExecute, resourceList, aaiResourceIds,
                                serviceInstanceId);
                    }
                }
            }
            // If the user set "Homing_Solution" to "none", disable homing, else if "Homing_Solution" is specified,
            // enable it.
            if (sIRequest.getRequestDetails().getRequestParameters() != null
                    && sIRequest.getRequestDetails().getRequestParameters().getUserParams() != null) {
                List<Map<String, Object>> userParams = getListOfUserParams(sIRequest);
                for (Map<String, Object> params : userParams) {
                    if (params.containsKey(HOMINGSOLUTION)) {
                        execution.setVariable(HOMING, !"none".equals(params.get(HOMINGSOLUTION)));
                    }
                }
            }

            if (CollectionUtils.isEmpty(flowsToExecute)) {
                throw new IllegalStateException("Macro did not come up with a valid execution path.");
            }

            List<String> flowNames = new ArrayList<>();
            logger.info("List of BuildingBlocks to execute:");

            flowsToExecute.forEach(ebb -> {
                logger.info(ebb.getBuildingBlock().getBpmnFlowName());
                flowNames.add(ebb.getBuildingBlock().getBpmnFlowName());
            });

            if (!isResume) {
                bbInputSetupUtils.persistFlowExecutionPath(requestId, flowsToExecute);
            }
            setExecutionVariables(execution, flowsToExecute, flowNames);

        } catch (Exception ex) {
            if (!(execution.hasVariable("WorkflowException")
                    || execution.hasVariable("WorkflowExceptionExceptionMessage"))) {
                buildAndThrowException(execution, "Exception while setting execution list. ", ex);
            } else {
                throw ex;
            }
        }
    }

}