EcnManagerImpl.java

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

import com.fa.sesa.exception.Assert;
import com.fa.sesa.exception.Errors;
import com.fa.sesa.exception.SystemIllegalArgumentException;
import com.fa.sesa.threadlocal.LocalContext;
import com.mycim.framework.jdbc.Page;
import com.mycim.framework.utils.lang.StringUtils;
import com.mycim.framework.utils.lang.math.NumberUtils;
import com.mycim.framework.utils.lang.time.DateUtils;
import com.mycim.server.base.manager.NamedObjectManager;
import com.mycim.server.base.manager.TransactionLogManager;
import com.mycim.server.ecn.dao.EcnDAO;
import com.mycim.server.edc.manager.EcnManager;
import com.mycim.valueobject.MessageIdList;
import com.mycim.valueobject.ObjectList;
import com.mycim.valueobject.bas.NamedObject;
import com.mycim.valueobject.bas.TransactionLog;
import com.mycim.valueobject.consts.TransactionNames;
import com.mycim.valueobject.consts.VersionStatus;
import com.mycim.valueobject.prp.Ecn;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.sql.Timestamp;
import java.text.DecimalFormat;
import java.text.SimpleDateFormat;
import java.util.Calendar;
import java.util.Date;

/**
 * ecn
 *
 * @author Johnson.Wang
 * @version 6.0.0
 * @date 2019/8/31
 **/
@Service
@Transactional
public class EcnManagerImpl implements EcnManager {
    private static final String DATE_FORMAT_YYYY_MM_DD = "yyyyMMdd";

    private static final String SUFFIX_PATTERN = "0000";

    private static final String SUFFIX_PLACEHOLDER = "____";

    private static final Integer ECN_ID_LENGTH = 15;

    private static final Integer PREFIX_LENGTH = 11;

    private static final Integer MAX_SEQUENCE = 9999;

    private static final Integer MAX_UPGRADE_COUNT = 99999;

    @Autowired
    private EcnDAO ecnDAO;

    @Autowired
    private NamedObjectManager namedObjectManager;

    @Autowired
    private TransactionLogManager transactionLogManager;

    @Override
    public Ecn generateUnFrozenEcn(Long userRrn, String type) {
        return generateUnFrozenEcn(userRrn, type, type);
    }

    @Override
    public Ecn generateUnFrozenEcn(Long requestBy, String type, String subType) {
        return generateEcn(requestBy, type, subType, VersionStatus.UNFROZEN_KEY);
    }

    @Override
    public Ecn generateActiveEcn(Long requestBy, String type, String subType) {
        return generateEcn(requestBy, type, subType, VersionStatus.ACTIVE_KEY);
    }

    @Override
    public Ecn generateActiveEcn(Long userRrn, String type) {
        return generateActiveEcn(userRrn, type, type);
    }

    @Override
    public Ecn getEcn(String ecnId) {
        return getEcn(namedObjectManager.getNamedObjectRrn(ecnId, LocalContext.getFacilityRrn(), ObjectList.ECN_KEY));
    }

    @Override
    public Ecn getEcn(long ecnRrn) {
        NamedObject namedObject = namedObjectManager.getNamedObject(ecnRrn);
        if (namedObject == null) {
            return null;
        }
        Ecn ecn = ecnDAO.getEcn(ecnRrn);
        ecn.setRequestById(namedObjectManager.getNamedObjectId(ecn.getRequestBy()));
        ecn.copyNamedObject(namedObject);

        if (ecn.getObjectType() == null) {
            ecn.setObjects(ecnDAO.getEcnObjectVersions(ecnRrn));
        } else {
            if (ecn.getObjectType().equalsIgnoreCase(ObjectList.CONTEXT_KEY)) {
                ecn.setObjects(ecnDAO.getEcnContextValues(ecnRrn));
            } else {
                ecn.setObjects(ecnDAO.getEcnObjectVersions(ecnRrn));
            }
        }
        return ecn;
    }

    @Override
    public void updateEcnStatus(String status, long ecnRrn) {
        updateEcnStatus(status, status, ecnRrn);
    }

    @Override
    public void updateEcnStatus(String status, String comments, long ecnRrn) {
        Ecn ecn = getEcn(ecnRrn);
        Assert.state(ecn != null,
                     Errors.create().key(MessageIdList.ECN_MISSING).content("The ECN is not found").build());
        // 1. 更改ecn状态
        ecnDAO.updateEcnStatus(status, comments, ecnRrn);

        // 2. 更改ecn关联对象状态
        if (ObjectList.CONTEXT_KEY.equals(ecn.getObjectType())) {
            ecnDAO.updateStatusForContext(status, ecnRrn);
        } else {
            ecnDAO.updateStatusForObjectVersion(status, ecnRrn);
        }
    }

    @Override
    public long insertEcn(Ecn ecn) {
        TransactionLog transactionLog = transactionLogManager
                .startTransactionLog(ecn.getTransPerformedby(), ecn.getTransId());
        long transRrn = transactionLog.getTransRrn();
        long instanceRrn;
        try {
            instanceRrn = namedObjectManager.insertNamedObject(ecn, transRrn);
        } catch (SystemIllegalArgumentException e) {
            throw new SystemIllegalArgumentException(Errors.create().key(MessageIdList.ECN_MAX_UPGRADE_COUNT).content("The maximum number of daily update has been reached. Please try again tomorrow!").build());
        }
        // main or history table handle
        ecn.setInstanceRrn(instanceRrn);

        ecnDAO.insertEcn(ecn);
        ecnDAO.insertEcnHistory(transRrn, 1, transactionLog.getTransId(), ecn.getInstanceRrn(),
                                ecn.getCreatedTimestamp());

        ecnDAO.insertEcnHistoryComment(ecn, transRrn);

        // mark transaction end flag
        transactionLogManager.markTransactionLog(transactionLog);
        return instanceRrn;
    }

    @Override
    public Ecn generateUnFrozenEcnForProcessPlan(long requestBy) {
        return generateUnFrozenEcn(requestBy, "PROCESSPLAN");
    }

    @Override
    public Ecn generateUnFrozenEcnForContext(long requestBy) {
        return generateUnFrozenEcn(requestBy, ObjectList.CONTEXT_KEY);
    }

    @Override
    public long getEcnSignOffRrn(String ecnType, String refNamedSpace, String tNamedSpace) {
        return ecnDAO.getEcnSignOffRrn(ecnType, refNamedSpace, tNamedSpace);
    }

    @Override
    public boolean isEcnControled(String object, String namedSpace) {
        return ecnDAO.isEcnControled(object, namedSpace);
    }

    @Override
    public Ecn generateActiveEcnForContext(long requestBy) {
        return generateActiveEcn(requestBy, ObjectList.CONTEXT_KEY);
    }

    @Override
    public Ecn activateEcn(Long ecnRrn, String userId) {
        Ecn ecn = getEcn(ecnRrn);
        ecn.setEcnStatus(VersionStatus.ACTIVE_KEY);
        ecn.setEffectiveDateFrom(getEffectiveDateFrom());
        ecn.setEffectiveDateTo(getEffectiveDateTo());
        ecn.setComments(TransactionNames.ACTIVE_KEY);
        ecn.setTransId(TransactionNames.ACTIVE_KEY);
        ecn.setTransPerformedby(userId);
        TransactionLog transactionLog = transactionLogManager
                .startTransactionLog(ecn.getTransPerformedby(), ecn.getTransId());
        long transRrn = transactionLog.getTransRrn();

        // update ecn
        updateEcnForStatus(ecn);

        // make ecn transhisory
        ecnDAO.insertEcnHistory(transRrn, 1, transactionLog.getTransId(), ecn.getInstanceRrn(),
                                transactionLog.getTransStartTimestamp());
        ecnDAO.insertEcnHistoryComment(ecn, transRrn);
        transactionLogManager.markTransactionLog(transactionLog);
        return ecn;
    }

    @Override
    public String generateECNID() {
        String ecnId;
        Calendar now = Calendar.getInstance();
        SimpleDateFormat sdf = new SimpleDateFormat("yyyyMMdd");
        String today = sdf.format(now.getTime());

        String maxEcnNum = ecnDAO.getMaxEcnNo(today);
        int nextSeq = 1;
        if (StringUtils.isEmpty(maxEcnNum)) {
            ecnId = "F" + today + ".00001";
        } else {
            String maxStr = StringUtils.substringAfter(maxEcnNum, ".");
            nextSeq += Integer.parseInt(maxStr);
            Assert.isFalse(nextSeq > MAX_UPGRADE_COUNT, Errors.create().key(MessageIdList.ECN_MAX_UPGRADE_COUNT).content(
                    "The maximum number of daily update has been reached. Please try again tomorrow!").build());

            if (!NumberUtils.isParsable(maxStr)) {
                ecnId = "F" + today + ".00001";
            } else {
                int max = NumberUtils.toInt(maxStr) + 1;
                String format = String.format("%05d", max);
                ecnId = "F" + today + "." + format;
            }
        }
        return ecnId;
    }

    @Override
    public Ecn generateUnFrozenECNForRunCard(long requestBy, String type, String idType) {
        String ecnId = generateECNIDFromRunCard(idType);
        Ecn ecn = new Ecn(ecnId, namedObjectManager.getNamedSpace(LocalContext.getFacilityRrn(), ObjectList.ECN_KEY),
                          ObjectList.ECN_KEY);
        ecn.setObject(ObjectList.ECN_KEY);
        ecn.setTransId(TransactionNames.CREATE_KEY);
        ecn.setInstanceDesc("Automatic schema generation for split run card");

        ecn.setEffectiveDateFrom(getEffectiveDateFrom());
        ecn.setEffectiveDateTo(getEffectiveDateTo());
        ecn.setEcnStatus(VersionStatus.DRAFT_KEY);
        ecn.setObject(ObjectList.ECN_KEY);

        ecn.setObjectType(type);
        ecn.setObjectSubtype(type);
        ecn.setRequestBy(requestBy);

        ecn.setTransId(TransactionNames.CREATE_KEY);
        ecn.setTransPerformedby(LocalContext.getUserId());

        ecn.setInstanceRrn(insertEcn(ecn));
        return ecn;
    }

    @Override
    public Ecn generateUnFrozenEcnForProduct(long requestBy) {
        return generateUnFrozenEcn(requestBy, "PRODUCT");
    }

    @Override
    public void updateRunCardStatus(Long runCardRrn, Timestamp effectiveDateFrom, Timestamp effectiveDateTo,
                                    String status) {
        ecnDAO.updateRunCardStatus(runCardRrn, effectiveDateFrom, effectiveDateTo, status);
    }

    @Override
    public void insertEcnHistory(Long transRrn, Integer transSequence, String transId, Long ecnRrn) {
        ecnDAO.insertEcnHistory(transRrn, transSequence, transId, ecnRrn, new Timestamp(System.currentTimeMillis()));
    }

    @Override
    public Page getEcnHistoryPage(int pageNo, int pageSize, Long ecnRrn) {
        return ecnDAO.getEcnHistoryPage(pageNo, pageSize, ecnRrn);
    }

    public void updateEcnForStatus(Ecn ecn) {
        ecnDAO.updateEcnForStatus(ecn);
        if (ObjectList.CONTEXT_KEY.equals(ecn.getObjectType())) {
            ecnDAO.updateContextValueForEcn(ecn);
        } else {
            ecnDAO.updateObjectVersionForEcn(ecn);
        }
    }

    private Ecn generateEcn(Long requestBy, String type, String subType, String ecnStatus) {
        Ecn ecn = buildBaseEcnInfo();
        ecn.setObjectType(type);
        ecn.setObjectSubtype(subType);
        ecn.setRequestBy(requestBy);
        String userId = namedObjectManager.getInstanceId(requestBy);
        userId = StringUtils.isEmpty(userId) ? "SYSTEM" : userId;
        ecn.setTransPerformedby(userId);
        ecn.setEffectiveDateFrom(DateUtils.formatDate(new Date()));
        ecn.setEffectiveDateTo(getEffectiveDateTo());
        ecn.setEcnStatus(ecnStatus);
        ecn.setObject(ObjectList.ECN_KEY);
        ecn.setTransId(TransactionNames.CREATE_KEY);
        ecn.setInstanceRrn(insertEcn(ecn));
        return ecn;
    }

    private String generateECNIDFromRunCard(String idType) {
        StringBuilder prefix = buildPrefix(idType);

        String maxEcnId = ecnDAO.getMaxEcnIdFromHistory(prefix.toString() + SUFFIX_PLACEHOLDER);
        int nextSeq = 1;
        if (StringUtils.isNotEmpty(maxEcnId)) {
            nextSeq += substringForSeq(maxEcnId);
            Assert.isFalse(nextSeq > MAX_SEQUENCE, Errors.create().content(
                    "The generated serial number has reached the " + "maximum serial number of the day. Please " +
                            "apply again tomorrow.").build());
        }
        return prefix.append(new DecimalFormat(SUFFIX_PATTERN).format(nextSeq)).toString();
    }

    private int substringForSeq(String maxEcnId) {
        return Integer.parseInt(maxEcnId.substring(PREFIX_LENGTH, ECN_ID_LENGTH));
    }


    private StringBuilder buildPrefix(String idType) {
        Calendar now = Calendar.getInstance();
        String today = new SimpleDateFormat(DATE_FORMAT_YYYY_MM_DD).format(now.getTime());

        return new StringBuilder(ECN_ID_LENGTH).append(idType).append(today);
    }

    /**
     * 设置新ECN的基本信息
     */
    private Ecn buildBaseEcnInfo() {
        String ecnId = generateECNID();
        Ecn ecn = new Ecn(ecnId, namedObjectManager.getNamedSpace(LocalContext.getFacilityRrn(), ObjectList.ECN_KEY),
                          ObjectList.ECN_KEY);

        ecn.setInstanceDesc("Automatic schema generation");
        ecn.setObject(ObjectList.ECN_KEY);
        ecn.setTransId(TransactionNames.CREATE_KEY);

        return ecn;
    }

    /**
     * 生效时间: 当前时间
     *
     * @return
     */
    private String getEffectiveDateFrom() {
        return DateUtils.formatDate(new Date());
    }

    /**
     * 失效时间: 100年后时间
     *
     * @return
     */
    private String getEffectiveDateTo() {
        Calendar cal = Calendar.getInstance();
        cal.set(Calendar.YEAR, cal.get(Calendar.YEAR) + 100);
        return DateUtils.formatDate(cal.getTime());
    }

}