SchedulePlanServiceImpl.java 7.98 KB
package com.bsth.service.schedule.impl;

import com.bsth.entity.Line;
import com.bsth.entity.schedule.SchedulePlan;
import com.bsth.entity.schedule.TTInfo;
import com.bsth.repository.BusinessRepository;
import com.bsth.repository.LineRepository;
import com.bsth.repository.schedule.*;
import com.bsth.service.schedule.SchedulePlanService;
import com.bsth.service.schedule.exception.ScheduleException;
import com.bsth.service.schedule.impl.plan.DroolsSchedulePlan;
import com.bsth.service.schedule.impl.plan.ScheduleRuleService;
import com.bsth.service.schedule.impl.plan.kBase3.validate.rule.ValidateRuleResult;
import com.bsth.service.schedule.impl.plan.kBase3.validate.timetable.CalcuParam;
import com.bsth.service.schedule.impl.plan.kBase3.validate.timetable.Result;
import org.joda.time.DateTime;
import org.kie.api.KieBase;
import org.kie.api.runtime.KieSession;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Isolation;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;

import java.util.*;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.locks.ReentrantLock;

/**
 * Created by xu on 16/6/16.
 */
@Service
public class SchedulePlanServiceImpl extends BServiceImpl<SchedulePlan, Long> implements SchedulePlanService {
    @Autowired
    @Qualifier("coreKBase")
    private KieBase coreKBase;

    @Autowired
    @Qualifier("preKBase")
    private KieBase preKBase;

    @Autowired
    @Qualifier("KBase3")
    private KieBase validateKBase;

    @Autowired
    private ScheduleRule1FlatRepository scheduleRule1FlatRepository;
    @Autowired
    private TTInfoRepository ttInfoRepository;
    @Autowired
    private TTInfoDetailRepository ttInfoDetailRepository;
    @Autowired
    private LineRepository lineRepository;
    @Autowired
    private CarConfigInfoRepository carConfigInfoRepository;
    @Autowired
    private GuideboardInfoRepository guideboardInfoRepository;
    @Autowired
    private EmployeeConfigInfoRepository employeeConfigInfoRepository;
    @Autowired
    private BusinessRepository businessRepository;
    @Autowired
    private ScheduleRuleService scheduleRuleService;
    @Autowired
    private RerunRuleRepository rerunRuleRepository;

    /** 日志记录器 */
    private Logger logger = LoggerFactory.getLogger(SchedulePlanServiceImpl.class);

    /** 线路独占锁 */
    private ConcurrentHashMap<Integer, ReentrantLock> lineXLatchMaps = new ConcurrentHashMap<>();
    private ReentrantLock getLineXLatch(Integer xlid) {
        ReentrantLock lineXLatch = lineXLatchMaps.get(xlid);
        if (lineXLatch == null) {
            lineXLatch = new ReentrantLock();
            ReentrantLock pre = lineXLatchMaps.putIfAbsent(xlid, lineXLatch);
            if (pre != null) {
                lineXLatch = pre;
            }
        }
        return lineXLatch;
    }

    @Transactional(propagation = Propagation.REQUIRED, isolation = Isolation.READ_COMMITTED)
    public SchedulePlan save(SchedulePlan schedulePlan) {
        ReentrantLock lineXLatch = getLineXLatch(schedulePlan.getXl().getId());
        try {
            if (lineXLatch.tryLock(1, TimeUnit.SECONDS)) {
                // pre、如果排班的数据之前已经有了,删除之前的数据
                Date startPre = new Date();
                scheduleRuleService.deleteSchedulePlanInfo(
                        schedulePlan.getXl().getLineCode(),
                        schedulePlan.getScheduleFromTime(),
                        schedulePlan.getScheduleToTime());
                Date endPre = new Date();
                logger.info("删除数据 {} ms --->", endPre.getTime() - startPre.getTime());

                // core、生成排班计划
                DroolsSchedulePlan droolsSchedulePlan = new DroolsSchedulePlan(
                        schedulePlan,
                        lineRepository, scheduleRule1FlatRepository,
                        ttInfoRepository, ttInfoDetailRepository,
                        carConfigInfoRepository, employeeConfigInfoRepository,
                        rerunRuleRepository, businessRepository,
                        scheduleRuleService,
                        preKBase, coreKBase,
                        logger
                );
                droolsSchedulePlan.generatePlan();

                return new SchedulePlan();
            } else {
                throw new ScheduleException("当前线路正在排班,请稍后再操作...");
            }
        } catch (Exception exp) {
            throw new RuntimeException(exp);
        } finally {
            try {
                lineXLatch.unlock();
            } catch (Exception exp2) {

            }

        }

    }

    @Override
    public void delete(Long aLong) throws ScheduleException {
        scheduleRuleService.deleteSchedulePlanAll(aLong);
    }

    @Override
    public SchedulePlan findSchedulePlanTommorw() {
        DateTime today = new DateTime(new Date());
        DateTime tommorw = new DateTime(
                today.getYear(), today.getMonthOfYear(),
                today.getDayOfMonth(), 0, 0).plusDays(1);
        Map<String, Object> param = new HashMap<>();
        param.put("scheduleFromTime_le", tommorw.toDate());
        param.put("scheduleToTime_ge", tommorw.toDate());
        Iterator<SchedulePlan> schedulePlanIterator = this.list(param).iterator();
        if (schedulePlanIterator.hasNext()) {
            return schedulePlanIterator.next();
        }
        return null;
    }

    @Override
    public Result validateTTInfo(Integer xlid, Date from, Date to) {
        // 构造drools session->载入数据->启动规则->计算->销毁session
        // 创建session,内部配置的是stateful
        KieSession session = validateKBase.newKieSession();
        // 设置gloable对象,在drl中通过别名使用
        session.setGlobal("log", logger);
        session.setGlobal("tTInfoDetailRepository", ttInfoDetailRepository);

        Result rs = new Result(); // 输出gloable对象
        session.setGlobal("rs", rs);

        // 载入数据
        Line line = lineRepository.findOne(xlid);
        session.insert(line);

        CalcuParam calcuParam = new CalcuParam(
                new DateTime(from), new DateTime(to), xlid);
        session.insert(calcuParam);
        List<TTInfo> ttInfos = ttInfoRepository.findByXlId(xlid);
        for (TTInfo ttInfo: ttInfos) {
            session.insert(ttInfo);
        }

        // 执行rule
        session.fireAllRules();

        // 执行完毕销毁,有日志的也要关闭
        session.dispose();

        return rs;
    }

    @Override
    public ValidateRuleResult validateRule(Integer xlId, Date from, Date to) {
        KieSession session = validateKBase.newKieSession();
        session.setGlobal("LOG", logger);
        session.setGlobal("ccRepo", carConfigInfoRepository);
        session.setGlobal("lpRepo", guideboardInfoRepository);
        session.setGlobal("ecRepo", employeeConfigInfoRepository);
        session.setGlobal("ruleRepo", scheduleRule1FlatRepository);

        ValidateRuleResult result = new ValidateRuleResult();
        session.setGlobal("result", result);

        com.bsth.service.schedule.impl.plan.kBase3.validate.rule.CalcuParam calcuParam =
                new com.bsth.service.schedule.impl.plan.kBase3.validate.rule.CalcuParam();
        calcuParam.setXlId(xlId);
        calcuParam.setFromDate(new DateTime(from));
        calcuParam.setToDate(new DateTime(to));
        session.insert(calcuParam);

        session.fireAllRules();

        session.dispose();;

        return result;
    }
}