SpecManagerImpl.java

package com.mycim.server.spec.manager.impl;

import com.fa.sesa.threadlocal.LocalContext;
import com.mycim.framework.jdbc.Page;
import com.mycim.framework.utils.lang.BooleanUtils;
import com.mycim.framework.utils.lang.ObjectUtils;
import com.mycim.framework.utils.lang.StringUtils;
import com.mycim.framework.utils.lang.collections.CollectionUtils;
import com.mycim.framework.utils.lang.collections.MapUtils;
import com.mycim.framework.utils.lang.math.NumberUtils;
import com.mycim.server.base.manager.NamedObjectManager;
import com.mycim.server.base.manager.TransactionLogManager;
import com.mycim.server.ctx.exec.manager.WflLinkContextValueManager;
import com.mycim.server.ctx.manager.ContextValueManager;
import com.mycim.server.prp.manager.ProcessManager;
import com.mycim.server.prp.manager.ProductProcessManager;
import com.mycim.server.prp.manager.ProductVersionManager;
import com.mycim.server.prp.manager.WorkflowManager;
import com.mycim.server.spec.manager.*;
import com.mycim.utils.WflLinkContextSetupAttributeUtil;
import com.mycim.valueobject.ObjectList;
import com.mycim.valueobject.bas.TransactionLog;
import com.mycim.valueobject.consts.ContextNames;
import com.mycim.valueobject.prp.*;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.lang.Override;
import java.util.*;
import java.util.function.Function;
import java.util.stream.Collectors;

/**
 * @author Qiansheng.Wang
 * @version 1.0
 * @since 2021-07-07
 **/
@Service
@Transactional
public class SpecManagerImpl implements SpecManager {

    @Autowired
    TransactionLogManager transactionLogManager;

    @Autowired
    ProductSpecInfoManager productSpecInfoManager;

    @Autowired
    ProcessSpecInfoManager processSpecInfoManager;

    @Autowired
    ProcessSpecItemManager processSpecItemManager;

    @Autowired
    ProductAttributeInfoManager productAttributeInfoManager;

    @Autowired
    ProductAttributeItemManager productAttributeItemManager;

    @Autowired
    ProductVersionManager productVersionManager;

    @Autowired
    ProductProcessManager productProcessManager;

    @Autowired
    ActivationAttributeManager activationAttributeManager;

    @Autowired
    ProcessManager processManager;

    @Autowired
    NamedObjectManager namedObjectManager;

    @Autowired
    ContextValueManager contextValueManager;

    @Autowired
    WorkflowManager workflowManager;

    @Autowired
    WflLinkContextValueManager wflLinkContextValueManager;

    @Override
    public List<Integer> getProcessVersionsInSpec(Long processRrn) {
        List<Integer> result = new ArrayList<>();
        for (ProcessSpecInfo processSpecInfo : processSpecInfoManager.getProcessSpecItemInfos(processRrn)) {
            result.add(processSpecInfo.getProcessVersion());
        }
        return result;
    }

    @Override
    public Integer getLatestAvailableVersion(Long processRrn) {
        List<Integer> activeVersion = processSpecInfoManager.getAllActivatedProcessVersions(processRrn);
        for (Integer verion : activeVersion) {
            if (CollectionUtils.isEmpty(processSpecItemManager.getProcessSpecItemsWithVariables(processRrn, verion))) {
                return verion;
            }
        }
        return 0;
    }

    @Override
    public ProductSpecInfo getLatestActivatedProductSpecInfo(Long productRrn, Long processRrn) {
        return productSpecInfoManager.getLatestActivatedProductSpecInfo(productRrn, processRrn);
    }

    @Override
    public int getLatestActivatedProcessVersion(Long productRrn, Long processRrn) {
        // 获取流程或流程产品最新可用的流程版本
        ProductSpecInfo productSpecInfo = getLatestActivatedProductSpecInfo(productRrn, processRrn);

        int processVer = 0;
        if (productSpecInfo != null && productSpecInfo.getProcessVersion() > 0) {
            // 如果有数据,表示曾经激活过对应版本的属性信息,返回对应的流程版本
            processVer = productSpecInfo.getProcessVersion();
        } else {
            // 如果没有数据,则获取流程最新的可用版本
            processVer = getLatestAvailableVersion(processRrn);
        }
        return processVer;
    }

    @Override
    public void addProductAttributeWhenAddProductProcess(TransactionLog transactionLog,
                                                         ProductProcessDto productProcess) {
        List<ProcessSpecInfo> specInfos = getProcessSpecInfosThatNeedsToSaveProductAttributes(
                productProcess.getProcessRrn());
        if (CollectionUtils.isEmpty(specInfos)) {
            return;
        }

        List<ProductVersion> productVersions = getProductVersionsThatNeedsToSaveProductAttributes(
                productProcess.getProductRrn());
        if (CollectionUtils.isEmpty(productVersions)) {
            return;
        }

        for (ProcessSpecInfo processSpecInfo : specInfos) {
            List<ProcessSpecItem> willSaveProcessSpecItems = processSpecItemManager
                    .getProcessSpecItemsWithVariables(processSpecInfo.getProcessRrn(),
                                                      processSpecInfo.getProcessVersion());

            if (CollectionUtils.isEmpty(willSaveProcessSpecItems)) {
                if (BooleanUtils.toBoolean(processSpecInfo.getActiveFlag())) {
                    activateProduct(transactionLog, productVersions, processSpecInfo);
                }
                continue;
            }

            productAttributeItemManager
                    .saveProductAttribute(transactionLog, processSpecInfo, willSaveProcessSpecItems, productVersions);
        }
    }

    @Override
    public void deleteProductAttributeWhenDeleteProductProcess(TransactionLog transactionLog,
                                                               ProductProcessDto productProcess) {
        deleteProductAttributeWhenProductDoDelete(transactionLog, productAttributeInfoManager
                .getProductAttributeInfos(productProcess.getProductRrn(), productProcess.getProcessRrn()));
    }

    @Override
    public void deleteProductAttributeWhenDeleteProduct(TransactionLog transactionLog, Long productRrn) {
        deleteProductAttributeWhenProductDoDelete(transactionLog, productAttributeInfoManager
                .getProductAttributeInfosByProduct(productRrn));
    }

    private void deleteProductAttributeWhenProductDoDelete(TransactionLog transactionLog,
                                                           List<ProductAttributeInfo> productAttributeInfosByProduct) {
        List<ProductAttributeInfo> willDeleteAttributeInfos = new ArrayList<>();
        List<ProductAttributeItem> willDeleteAttributeItems = new ArrayList<>();

        for (ProductAttributeInfo attributeInfo : productAttributeInfosByProduct) {
            //  if (!BooleanUtils.toBoolean(attributeInfo.getActiveFlag())) {
            // 在product 解绑和删除时,需要删除对应product的所有数据 包括active的数据
            willDeleteAttributeInfos.add(attributeInfo);
            willDeleteAttributeItems.addAll(productAttributeItemManager
                                                    .getProductAttributeItems(attributeInfo.getProcessRrn(),
                                                                              attributeInfo.getProcessVersion(),
                                                                              attributeInfo.getProductRrn(),
                                                                              attributeInfo.getProductVersion()));
            //  }
        }

        productAttributeInfoManager.deleteProductAttributeInfos(willDeleteAttributeInfos);
        productAttributeItemManager.deleteProductAttributeItems(transactionLog, willDeleteAttributeItems);
    }

    private void activateProduct(TransactionLog transactionLog, List<ProductVersion> productVersions,
                                 ProcessSpecInfo processSpecInfo) {
        productSpecInfoManager.activateProductSpecInfos(transactionLog, processSpecInfo, productVersions);

        activateProduct(transactionLog, processSpecInfo.getProcessRrn(), processSpecInfo.getProcessVersion());
    }

    @Override
    public void activateProduct(TransactionLog transactionLog, Long processRrn, Integer processVersion) {
        Integer highestAvailableProcessVersion = processSpecInfoManager.getHighestActivatedProcessVersion(processRrn);
        if (highestAvailableProcessVersion == null || highestAvailableProcessVersion <= processVersion) {
            // 更新产品可用的流程版本
            productProcessManager.updateAvailableProcessVersionOfAllProduct(transactionLog, processRrn, processVersion);
        }

        activationAttributeManager.saveActivationAttributes(processRrn, processVersion);
    }

    @Override
    public Boolean checkMultipath(String processId, Long processRrn, Integer processVersion, List<String> productIds) {
        Boolean multipathSetFlag = Boolean.FALSE;
        List<Item> usedByProducts = new ArrayList<>();
        if (CollectionUtils.isNotEmpty(productIds)) {
            //若productIds不为空则表示536active,只check当前的product
            for (String productId : productIds) {
                Item item = new Item();
                item.setInstanceId(productId);
                item.setInstanceRrn(namedObjectManager.getNamedObjectRrn(productId, LocalContext.getFacilityRrn(),
                                                                         ObjectList.PRODUCT_KEY));
                usedByProducts.add(item);
            }
        } else {
            // 若productIds为空 则表示535active,查询当前process上挂的所有product
            usedByProducts = processManager.getUsedByProducts(processRrn);
        }
        if (CollectionUtils.isEmpty(usedByProducts)) {
            return Boolean.FALSE;
        }

        List<Map<String, Object>> multipathOperation = getMultipath(processRrn, processVersion,
                                                                    WflLinkContextSetupAttributeUtil.OPERATION_FLAG);

        List<Map<String, Object>> multipathRoute = getMultipath(processRrn, processVersion,
                                                                WflLinkContextSetupAttributeUtil.ROUTE_FLAG);

        for (Map<String, Object> map : multipathOperation) {
            Long operationRrn = MapUtils.getLong(map, "operationRrn");
            Long routeRrn = MapUtils.getLong(map, "routeRrn");
            if (operationRrn.longValue() < 0 || routeRrn.longValue() < 0) {
                continue;
            }


            for (Item product : usedByProducts) {
                multipathSetFlag = Boolean.TRUE;
                // 查询对应product上的Multipath设置
                WflLinkContextValue wflLinkContextValue = new WflLinkContextValue();
                wflLinkContextValue.setProductRrn(product.getInstanceRrn());
                wflLinkContextValue.setProcessRrn(processRrn);
                wflLinkContextValue.setProcessVersion(processVersion);
                wflLinkContextValue.setStatus("ACTIVE");
                List<WflLinkContextValue> contextValues = wflLinkContextValueManager
                        .getContextValues(wflLinkContextValue);

                for (WflLinkContextValue ct : contextValues) {
                    if (operationRrn.equals(ct.getOperationRrn()) && routeRrn.equals(ct.getRouteRrn()) &&
                            WflLinkContextSetupAttributeUtil.isByOperationMultipath(ct)) {
                        multipathSetFlag = Boolean.FALSE;
                        break;
                    }
                }
                if (multipathSetFlag) {
                    return multipathSetFlag;
                }
            }

        }
        for (Map<String, Object> map : multipathRoute) {
            String routeId = MapUtils.getString(map, "routeId");
            Long routeRrn = namedObjectManager
                    .getNamedObjectRrn(routeId, LocalContext.getFacilityRrn(), ObjectList.WFL_KEY);

            if (routeRrn.longValue() > 0) {
                for (Item product : usedByProducts) {
                    // 查询对应product上的Multipath设置
                    multipathSetFlag = Boolean.TRUE;
                    WflLinkContextValue wflLinkContextValue = new WflLinkContextValue();
                    wflLinkContextValue.setProductRrn(product.getInstanceRrn());
                    wflLinkContextValue.setProcessRrn(processRrn);
                    wflLinkContextValue.setProcessVersion(processVersion);
                    wflLinkContextValue.setStatus("ACTIVE");
                    List<WflLinkContextValue> contextValues = wflLinkContextValueManager
                            .getContextValues(wflLinkContextValue);

                    for (WflLinkContextValue ct : contextValues) {
                        if (WflLinkContextSetupAttributeUtil.isByRouteMultipath(ct) &&
                                routeRrn.equals(ct.getRouteRrn())) {
                            multipathSetFlag = Boolean.FALSE;
                            break;
                        }
                    }
                    if (multipathSetFlag) {
                        return multipathSetFlag;
                    }
                }

            }
        }

        return Boolean.FALSE;
    }

    private List<ProductVersion> getProductVersionsThatNeedsToSaveProductAttributes(Long productVersion) {
        List<ProductVersion> productVersions = new ArrayList<>();

        List<ProductVersion> allProductVersion = productVersionManager.getAllVersions(productVersion);

        allProductVersion.sort((o1, o2) -> o2.getInstanceVersion() - o1.getInstanceVersion());

        productVersions.add(allProductVersion.iterator().next());

        return productVersions;
    }

    private List<ProcessSpecInfo> getProcessSpecInfosThatNeedsToSaveProductAttributes(Long processRrn) {
        List<ProcessSpecInfo> processSpecInfos = processSpecInfoManager.getProcessSpecItemInfos(processRrn);

        processSpecInfos.sort((o1, o2) -> o2.getProcessVersion() - o1.getProcessVersion());

        List<ProcessSpecInfo> specInfos = new ArrayList<>();
        for (ProcessSpecInfo processSpecInfo : processSpecInfos) {
            specInfos.add(processSpecInfo);
            if (BooleanUtils.toBoolean(processSpecInfo.getActiveFlag())) {
                break;
            }
        }
        return specInfos;
    }

    private List<Map<String, Object>> getMultipath(Long processRrn, Integer processVersion, String type) {
        List<Map<String, Object>> workFlowByProcess = new ArrayList<>();
        Boolean ruleFlag = Boolean.FALSE;
        if (StringUtils.equalsIgnoreCase(WflLinkContextSetupAttributeUtil.OPERATION_FLAG, type)) {
            workFlowByProcess = workflowManager.getWflOperationByProcess(processRrn, processVersion);
            ruleFlag = Boolean.TRUE;
        } else if (StringUtils.equalsIgnoreCase(WflLinkContextSetupAttributeUtil.ROUTE_FLAG, type)) {
            workFlowByProcess = workflowManager.getWflRouteByProcess(processRrn, processVersion);
            ruleFlag = Boolean.FALSE;
        } else {
            return null;
        }
        List<Map<String, Object>> buildWorkFlow = new ArrayList<>();
        Map<String, Integer> map = new HashMap<>();
        for (Map<String, Object> flowByProcess : workFlowByProcess) {
            String rule = StringUtils.EMPTY;
            if (ruleFlag) {
                rule = MapUtils.getString(flowByProcess, "routeRrn") + StringUtils.COMMA_SIGN +
                        MapUtils.getString(flowByProcess, "routeVersion") + StringUtils.COMMA_SIGN +
                        MapUtils.getString(flowByProcess, "operationId") + StringUtils.COMMA_SIGN;
            } else {
                rule = MapUtils.getString(flowByProcess, "processRrn") + StringUtils.COMMA_SIGN +
                        MapUtils.getString(flowByProcess, "processVersion") + StringUtils.COMMA_SIGN +
                        MapUtils.getString(flowByProcess, "routeId") + StringUtils.COMMA_SIGN;
            }

            //1 检测key是否重复
            if (map.containsKey(rule)) {
                Integer num = map.get(rule);
                if (NumberUtils.INTEGER_ONE.equals(num)) {
                    String operationId = MapUtils.getString(flowByProcess, "operationId");
                    Long instanceRrn = namedObjectManager
                            .getNamedObjectRrn(operationId, LocalContext.getFacilityRrn(), ObjectList.OPERATION_KEY);
                    flowByProcess.put("operationRrn", instanceRrn);
                    buildWorkFlow.add(flowByProcess);//获取重复元素
                }
                map.put(rule, num + 1);
            } else {
                map.put(rule, 1);
            }
        }

        return buildWorkFlow;

    }

    @Override
    public Boolean checkMultiPathHasManualForContextValue(WflLinkContextValue contextValue) {

        Long routeRrn = contextValue.getRouteRrn();
        Long operationRrn = contextValue.getOperationRrn();
        Long processRrn = contextValue.getProcessRrn();
        Integer processVersion = contextValue.getProcessVersion();
        if (WflLinkContextSetupAttributeUtil.isByManualOperationMultipath(contextValue)) {
            Integer routeVersion = workflowManager.getWFLVersionByProcess(processRrn, processVersion, routeRrn);
            Collection operationPath = workflowManager
                    .getWflPath(routeRrn, routeVersion, namedObjectManager.getInstanceId(operationRrn));
            if (operationPath.size() < 2) {
                return Boolean.FALSE;
            }
        } else if (WflLinkContextSetupAttributeUtil.isByManualRouteMultipath(contextValue)) {
            Collection routePath = workflowManager
                    .getWflPath(processRrn, processVersion, namedObjectManager.getInstanceId(routeRrn));
            if (routePath.size() < 2) {
                return Boolean.FALSE;
            }
        }

        return Boolean.TRUE;


    }

    @Override
    public List<Map<String,Object>> getMultipathAndDefaultSteps(Long processRrn, Integer processVersion,String type) {
        //根据processRrn processVersion取到对应的所有operation节点信息
        List<Map<String, Object>> allWflList = workflowManager.getallWflByProcess(processRrn,processVersion);
        //operation multipath
        if (StringUtils.equalsIgnoreCase(WflLinkContextSetupAttributeUtil.OPERATION_FLAG, type)) {
            Set<Long> wflStepRrns = new HashSet<>();
            List<Map<String,Object>> wflList = new ArrayList<>();
            for(Map<String, Object> operation : allWflList){
                if(StringUtils.isNotBlank(MapUtils.getString(operation,"operationLinkId"))){
                    wflStepRrns.add(MapUtils.getLong(operation, "operationStepRrn"));
                }
            }
            //若operation存在multipath的节点(可能存在多个)
            if(CollectionUtils.isNotEmpty(wflStepRrns)){
                for(Long wflStepRrn : wflStepRrns){
                    List<Long> multiParentAndChildrenNodesList = new ArrayList<>();
                    List<Long> multiParentAndChildrenNodesListNoEnd = new ArrayList<>();
                    //拿到multipath节点的默认子节点和multipath子节点(可能存在多个)
                    Set<Long> multiStepRrns = new LinkedHashSet<>();
                    for(Map<String, Object> operation : allWflList){
                        if(wflStepRrn.equals(MapUtils.getLong(operation, "operationStepRrn"))){
                            multiStepRrns.add(MapUtils.getLong(operation, "wflNextStepRrn"));
                        }
                    }

                    if(CollectionUtils.isNotEmpty(multiStepRrns)){
                        //递归查询multipath节点作为父节点对应路径下的所有节点
                        for(Long wflNode : multiStepRrns){
                            List<Map<String, Object>> childrenNodes = getChildrenNodes(allWflList,wflNode,"wflNextStepRrn","operationStepRrn",new ArrayList<>());
                            for(Map<String, Object> childNode : childrenNodes){
                                multiParentAndChildrenNodesList.add(MapUtils.getLong(childNode, "operationStepRrn"));
                            }
                        }
                        if(CollectionUtils.isNotEmpty(multiParentAndChildrenNodesList)) {
                            //拿到对应的multipath和default路径节点(即个数不等于分支长度的节点)
                            multiParentAndChildrenNodesListNoEnd = multiParentAndChildrenNodesList.stream().collect(
                                                       Collectors.toMap(Function.identity(), s -> 1, Integer::sum)).entrySet().stream()
                                                       .filter(entry -> !entry.getValue().equals(multiStepRrns.size()))
                                                       .map(Map.Entry::getKey).collect(Collectors.toList());
                        }
                    }

                    //取multipath和default路径节点的operationRrn
                    if(CollectionUtils.isNotEmpty(multiParentAndChildrenNodesListNoEnd)){
                        for(Map<String,Object> wflInfo : allWflList){
                            for(Long operationStepRrn : multiParentAndChildrenNodesListNoEnd){
                                if(MapUtils.getLong(wflInfo,"operationStepRrn").equals(operationStepRrn)){
                                    wflList.add(wflInfo);
                                }
                            }
                        }
                    }
                }
            }
            return wflList;
        }

        //route multipath
        else if (StringUtils.equalsIgnoreCase(WflLinkContextSetupAttributeUtil.ROUTE_FLAG, type)) {
            List<Map<String,Object>> routeWflList = new ArrayList<>();
            List<Long> routeStepRrnList = new ArrayList<>();
            //获取到对应的所有route节点信息
            for(Map<String, Object> wflInfo : allWflList){
                if(!routeStepRrnList.contains(MapUtils.getLong(wflInfo,"routeStepRrn"))){
                    routeStepRrnList.add(MapUtils.getLong(wflInfo,"routeStepRrn"));
                    routeWflList.add(wflInfo);
                }
            }
            List<Map<String,Object>> wflList = new ArrayList<>();
            Set<Long> wflStepRrns = new HashSet<>();
            for(Map<String, Object> route : routeWflList){
                if(StringUtils.isNotBlank(MapUtils.getString(route,"routeLinkId"))){
                    wflStepRrns.add(MapUtils.getLong(route, "routeStepRrn"));
                }
            }
            //若route存在multipath的节点(可能存在多个)
            if(CollectionUtils.isNotEmpty(wflStepRrns)){
                for(Long wflStepRrn : wflStepRrns){
                    List<Long> multiParentAndChildrenNodesList = new ArrayList<>();
                    List<Long> multiParentAndChildrenNodesListNoEnd = new ArrayList<>();
                    //拿到multipath节点的默认子节点和multipath子节点(可能存在多个)
                    Set<Long> multiStepRrns = new LinkedHashSet<>();
                    for(Map<String, Object> operation : allWflList){
                        if(wflStepRrn.equals(MapUtils.getLong(operation, "routeStepRrn"))){
                            multiStepRrns.add(MapUtils.getLong(operation, "routeWflNextStepRrn"));
                        }
                    }

                    if(CollectionUtils.isNotEmpty(multiStepRrns)){
                        //递归查询multipath节点作为父节点对应路径下的所有节点
                        for(Long wflNode : multiStepRrns){
                            List<Map<String, Object>> childrenNodes = getChildrenNodes(routeWflList,wflNode,"routeWflNextStepRrn","routeStepRrn",new ArrayList<>());
                            for(Map<String, Object> childNode : childrenNodes){
                                multiParentAndChildrenNodesList.add(MapUtils.getLong(childNode, "routeStepRrn"));
                            }
                        }

                        if(CollectionUtils.isNotEmpty(multiParentAndChildrenNodesList)) {
                            //拿到对应的end节点(个数和multipath节点个数相同的第一个节点即为end节点)
                            multiParentAndChildrenNodesListNoEnd = multiParentAndChildrenNodesList.stream().collect(
                                                                                                     Collectors.toMap(Function.identity(), s -> 1, Integer::sum)).entrySet().stream()
                                                                                             .filter(entry -> !entry.getValue().equals(multiStepRrns.size()))
                                                                                             .map(Map.Entry::getKey).collect(Collectors.toList());
                        }
                    }

                    //取multipath和default路径节点的operationRrn
                    if(CollectionUtils.isNotEmpty(multiParentAndChildrenNodesListNoEnd)){
                        for(Map<String,Object> wflInfo : allWflList){
                            for(Long routeStepRrn : multiParentAndChildrenNodesListNoEnd){
                                if(MapUtils.getLong(wflInfo,"routeStepRrn").equals(routeStepRrn)){
                                    wflList.add(wflInfo);
                                }
                            }
                        }
                    }
                }
            }
            return wflList;
        } else {
            return null;
        }
    }

    //递归查找父节点的所有子节点
    public List<Map<String,Object>> getChildrenNodes(List<Map<String,Object>> nodesList, Long nodeRrn, String wflNextStepRrnString,String stepRrnString,List<Map<String,Object>> childNodes) {
        for (Map<String,Object> node : nodesList) {
            //遍历出wflNextStepRrn等于operationStepRrn,add进子节点集合
            if (nodeRrn.equals(MapUtils.getLong(node,stepRrnString))) {
                //递归遍历下一级
                childNodes.add(node);
                getChildrenNodes(nodesList,MapUtils.getLong(node,wflNextStepRrnString),wflNextStepRrnString,stepRrnString,childNodes);
            }
        }
        return childNodes;
    }
}