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

import com.bsth.entity.schedule.SchedulePlan;
import com.bsth.entity.schedule.TTInfo;
import com.bsth.entity.schedule.rule.ScheduleRule1Flat;
import com.bsth.repository.BusinessRepository;
import com.bsth.repository.LineRepository;
import com.bsth.repository.schedule.*;
import com.bsth.service.schedule.SchedulePlanRuleResultService;
import com.bsth.service.schedule.SchedulePlanService;
import com.bsth.service.schedule.exception.ScheduleException;
import com.bsth.service.schedule.rules.ScheduleRuleService;
import com.bsth.service.schedule.rules.plan.PlanCalcuParam_input;
import com.bsth.service.schedule.rules.plan.PlanResult;
import com.bsth.service.schedule.rules.shiftloop.ScheduleCalcuParam_input;
import com.bsth.service.schedule.rules.shiftloop.ScheduleResults_output;
import com.bsth.service.schedule.rules.shiftloop.ScheduleRule_input;
import com.bsth.service.schedule.rules.ttinfo.*;
import com.bsth.service.schedule.rules.ttinfo2.CalcuParam;
import com.bsth.service.schedule.rules.ttinfo2.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.stereotype.Service;

import java.util.*;

/**
 * Created by xu on 16/6/16.
 */
@Service
public class SchedulePlanServiceImpl extends BServiceImpl<SchedulePlan, Long> implements SchedulePlanService {
    @Autowired
    private KieBase kieBase;
    @Autowired
    private SchedulePlanInfoRepository schedulePlanInfoRepository;
    @Autowired
    private ScheduleRule1FlatRepository scheduleRule1FlatRepository;
    @Autowired
    private TTInfoRepository ttInfoRepository;
    @Autowired
    private TTInfoDetailRepository ttInfoDetailRepository;
    @Autowired
    private LineRepository lineRepository;
    @Autowired
    private CarConfigInfoRepository carConfigInfoRepository;
    @Autowired
    private EmployeeConfigInfoRepository employeeConfigInfoRepository;
    @Autowired
    private BusinessRepository businessRepository;
    @Autowired
    private SchedulePlanRuleResultService schedulePlanRuleResultService;
    @Autowired
    private ScheduleRuleService scheduleRuleService;

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

    /**
     * 循环规则输出。
     * @param schedulePlan 排班计划对象
     * @param lpInfoResults_output 时刻表每日路牌的情况
     */
    public ScheduleResults_output loopRuleOutput(
            SchedulePlan schedulePlan,
            LpInfoResults_output lpInfoResults_output) {
        // 1-1、构造drools规则输入数据,输出数据
        // 全局计算参数
        ScheduleCalcuParam_input scheduleCalcuParam_input = new ScheduleCalcuParam_input(schedulePlan);
        // 每个规则对应的输入参数
        List<ScheduleRule_input> scheduleRule_inputs = new ArrayList<>();
        List<ScheduleRule1Flat> scheduleRule1Flats = scheduleRule1FlatRepository.findByXl(schedulePlan.getXl());

        for (ScheduleRule1Flat scheduleRule1Flat: scheduleRule1Flats) {
            ScheduleRule_input scheduleRule_input = new ScheduleRule_input(scheduleRule1Flat);
            scheduleRule_inputs.add(scheduleRule_input);
        }

        // 规则输出数据
        ScheduleResults_output scheduleResults_output = new ScheduleResults_output();

        // 1-2、构造drools session->载入数据->启动规则->计算->销毁session
        // 创建session,内部配置的是stateful
        KieSession session = kieBase.newKieSession();
        // 设置gloable对象,在drl中通过别名使用
        session.setGlobal("scheduleResult", scheduleResults_output);
        session.setGlobal("log", logger); // 设置日志
        session.setGlobal("scheduleRuleService", scheduleRuleService);

        // 载入数据
        session.insert(scheduleCalcuParam_input);
        for (ScheduleRule_input scheduleRule_input : scheduleRule_inputs) {
            session.insert(scheduleRule_input);
        }
        // 每日时刻表路牌数据
        for (LpInfoResult_output lpInfoResult_output: lpInfoResults_output.getLpInfoResult_outputs()) {
            session.insert(lpInfoResult_output);
        }
        // 执行rule
        session.fireAllRules();

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

        logger.info("循环规则输出={}", scheduleResults_output.showGuideboardDesc1());

        return scheduleResults_output;
    }

    /**
     * 时刻表选择(判定每天使用的时刻表,以及路牌数据输出)。
     * @param schedulePlan 排班计划对象
     * @return TTInfoResults_output, LpInfoResults_output
     */
    public Object[] ttInfoOutput(SchedulePlan schedulePlan) {
        // 获取线路的所有未作废的时刻表
        List<TTInfo> ttInfos = ttInfoRepository.findInCanceledByXl(schedulePlan.getXl());

        // 1-1、构造drools规则输入数据,输出数据
        // 全局计算参数
        TTInfoCalcuParam_input ttInfoCalcuParam_input =
                new TTInfoCalcuParam_input(
                        new DateTime(schedulePlan.getScheduleFromTime()),
                        new DateTime(schedulePlan.getScheduleToTime()),
                        String.valueOf(schedulePlan.getXl().getId())
                );
        // 规则输出数据
        TTInfoResults_output ttInfoResults_output = new TTInfoResults_output();
        LpInfoResults_output lpInfoResults_output = new LpInfoResults_output();

        // 1-2、构造drools session->载入数据->启动规则->计算->销毁session
        // 创建session,内部配置的是stateful
        KieSession session = kieBase.newKieSession();

        // 设置gloable对象,在drl中通过别名使用
        session.setGlobal("results", ttInfoResults_output);
        session.setGlobal("lpInfoResults_output", lpInfoResults_output);
        session.setGlobal("log", logger); // 设置日志
        session.setGlobal("tTInfoDetailRepository", ttInfoDetailRepository);

        // 载入数据
        session.insert(ttInfoCalcuParam_input);
        for (TTInfo ttInfo : ttInfos) {
            TTInfo_input ttInfo_input = new TTInfo_input(ttInfo);
            session.insert(ttInfo_input);
        }

        // 载入数据2(计算规则最早启用时间)
        List<ScheduleRule1Flat> scheduleRule1Flats = scheduleRule1FlatRepository.findByXl(schedulePlan.getXl());

        for (ScheduleRule1Flat scheduleRule1Flat: scheduleRule1Flats) {
            ScheduleRule_input scheduleRule_input = new ScheduleRule_input(scheduleRule1Flat);
            session.insert(scheduleRule_input);
        }

        // 执行rule
        session.fireAllRules();

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

        return new Object[] {ttInfoResults_output, lpInfoResults_output};

    }

    /**
     * 排班生成。
     * @param schedulePlan 排班计划对象
     * @param scheduleResults_output loopRuleOutput方法规则输出
     * @param ttInfoResults_output ttInfoOutput方法规则输出
     * @return PlanResult
     */
    public PlanResult planResultOutput(
            SchedulePlan schedulePlan,
            ScheduleResults_output scheduleResults_output,
            TTInfoResults_output ttInfoResults_output) {

        // 1-1、构造drools规则输入数据,输出数据
        PlanCalcuParam_input planCalcuParam_input = new PlanCalcuParam_input(
                schedulePlan,
                scheduleResults_output,
                ttInfoResults_output
        );
        // 规则输出数据
        PlanResult planResult = new PlanResult();

        // 1-2、构造drools session->载入数据->启动规则->计算->销毁session
        // 创建session,内部配置的是stateful
        KieSession session = kieBase.newKieSession();

        // 设置gloable对象,在drl中通过别名使用
        session.setGlobal("planResult", planResult);
        session.setGlobal("log", logger); // 设置日志

        session.setGlobal("tTInfoDetailRepository", ttInfoDetailRepository);
        session.setGlobal("carConfigInfoRepository", carConfigInfoRepository);
        session.setGlobal("employeeConfigInfoRepository", employeeConfigInfoRepository);
        session.setGlobal("lineRepository", lineRepository);
        session.setGlobal("businessRepository", businessRepository);

        // 载入数据
        session.insert(planCalcuParam_input);

        // 执行rule
        session.fireAllRules();

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

        return planResult;

    }

    public SchedulePlan save(SchedulePlan schedulePlan) {
        // pre、如果排班的数据之前已经有了,删除之前的数据
        Date startpre = new Date();
        scheduleRuleService.deelteSchedulePlanInfo(
                schedulePlan.getXl().getId(),
                schedulePlan.getScheduleFromTime(),
                schedulePlan.getScheduleToTime());
        Date endpre = new Date();

        // 1、时刻表数据及每日路牌数据计算
        Date start1 = new Date();
        Object[] ttInfoRets = ttInfoOutput(schedulePlan);
        TTInfoResults_output ttInfoResults_output = (TTInfoResults_output) ttInfoRets[0];
        LpInfoResults_output lpInfoResults_output = (LpInfoResults_output) ttInfoRets[1];
        Date end1 = new Date();
        // 2、循环规则计算输出
        Date start2 = new Date();
        ScheduleResults_output scheduleResults_output = loopRuleOutput(schedulePlan, lpInfoResults_output);
        Date end2 = new Date();
        // 3、计划输出
        Date start3 = new Date();
        PlanResult planResult = planResultOutput(schedulePlan, scheduleResults_output, ttInfoResults_output);
        Date end3 = new Date();

        // 4、保存数据(jdbcTemplate 批量插入)
        Date start4 = new Date();
        scheduleRuleService.generateSchedulePlan(schedulePlan, planResult.getSchedulePlanInfos());
        Date end4 = new Date();


        logger.info("删除数据 {} ms,drool时刻表每日路牌计算 {} ms,drool循环规则计算 {} ms,drool计划数据 {} ms,插入数据 {} 条 耗时 {} ms",
                endpre.getTime() - startpre.getTime(),
                end1.getTime() - start1.getTime(),
                end2.getTime() - start2.getTime(),
                end3.getTime() - start3.getTime(),
                planResult.getSchedulePlanInfos().size(),
                end4.getTime() - start4.getTime());


        return new SchedulePlan();
    }

    @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 = kieBase.newKieSession();
        // 设置gloable对象,在drl中通过别名使用
        session.setGlobal("log", logger);
        session.setGlobal("lineRepository", lineRepository);
        session.setGlobal("tTInfoDetailRepository", ttInfoDetailRepository);

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

        // 载入数据
        CalcuParam calcuParam = new CalcuParam(
                new DateTime(from), new DateTime(to), xlid);
        session.insert(calcuParam);
        List<TTInfo> ttInfos = (List<TTInfo>) ttInfoRepository.findAll();
        for (TTInfo ttInfo: ttInfos)
                session.insert(ttInfo);

        // 执行rule
        session.fireAllRules();

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


        return rs;
    }
}