Commit 56b9c321e04c5631a015dba1f06edfcf35a14560

Authored by 徐烜
1 parent d0dedf6e

排班计划修正

1、将排班计划的主要逻辑封装成DroolsSchedulePlan类
2、在主SchedulePlanServiceImpl中添加ReentrantLock锁,控制相同线路并发生成计划
src/main/java/com/bsth/service/schedule/impl/SchedulePlanServiceImpl.java
1 package com.bsth.service.schedule.impl; 1 package com.bsth.service.schedule.impl;
2 2
3 -import com.bsth.entity.Line;  
4 import com.bsth.entity.schedule.SchedulePlan; 3 import com.bsth.entity.schedule.SchedulePlan;
5 -import com.bsth.entity.schedule.SchedulePlanInfo;  
6 import com.bsth.entity.schedule.TTInfo; 4 import com.bsth.entity.schedule.TTInfo;
7 -import com.bsth.entity.schedule.rule.ScheduleRule1Flat;  
8 import com.bsth.repository.BusinessRepository; 5 import com.bsth.repository.BusinessRepository;
9 import com.bsth.repository.LineRepository; 6 import com.bsth.repository.LineRepository;
10 import com.bsth.repository.schedule.*; 7 import com.bsth.repository.schedule.*;
11 import com.bsth.service.schedule.SchedulePlanService; 8 import com.bsth.service.schedule.SchedulePlanService;
12 import com.bsth.service.schedule.exception.ScheduleException; 9 import com.bsth.service.schedule.exception.ScheduleException;
  10 +import com.bsth.service.schedule.plan.DroolsSchedulePlan;
13 import com.bsth.service.schedule.rules.ScheduleRuleService; 11 import com.bsth.service.schedule.rules.ScheduleRuleService;
14 -import com.bsth.service.schedule.rules.plan.PlanCalcuParam_input;  
15 -import com.bsth.service.schedule.rules.plan.PlanResult;  
16 -import com.bsth.service.schedule.rules.rerun.RerunRule_input;  
17 -import com.bsth.service.schedule.rules.rerun.RerunRule_param;  
18 -import com.bsth.service.schedule.rules.shiftloop.ScheduleCalcuParam_input;  
19 -import com.bsth.service.schedule.rules.shiftloop.ScheduleResults_output;  
20 -import com.bsth.service.schedule.rules.shiftloop.ScheduleRule_input;  
21 -import com.bsth.service.schedule.rules.ttinfo.*;  
22 import com.bsth.service.schedule.rules.ttinfo2.CalcuParam; 12 import com.bsth.service.schedule.rules.ttinfo2.CalcuParam;
23 import com.bsth.service.schedule.rules.ttinfo2.Result; 13 import com.bsth.service.schedule.rules.ttinfo2.Result;
24 -import com.bsth.service.schedule.rules.validate.ValidateParam;  
25 -import com.bsth.service.schedule.rules.validate.ValidateResults_output;  
26 -import org.apache.commons.lang3.StringUtils;  
27 import org.joda.time.DateTime; 14 import org.joda.time.DateTime;
28 import org.kie.api.KieBase; 15 import org.kie.api.KieBase;
29 import org.kie.api.runtime.KieSession; 16 import org.kie.api.runtime.KieSession;
@@ -37,6 +24,9 @@ import org.springframework.transaction.annotation.Propagation; @@ -37,6 +24,9 @@ import org.springframework.transaction.annotation.Propagation;
37 import org.springframework.transaction.annotation.Transactional; 24 import org.springframework.transaction.annotation.Transactional;
38 25
39 import java.util.*; 26 import java.util.*;
  27 +import java.util.concurrent.ConcurrentHashMap;
  28 +import java.util.concurrent.TimeUnit;
  29 +import java.util.concurrent.locks.ReentrantLock;
40 30
41 /** 31 /**
42 * Created by xu on 16/6/16. 32 * Created by xu on 16/6/16.
@@ -44,12 +34,12 @@ import java.util.*; @@ -44,12 +34,12 @@ import java.util.*;
44 @Service 34 @Service
45 public class SchedulePlanServiceImpl extends BServiceImpl<SchedulePlan, Long> implements SchedulePlanService { 35 public class SchedulePlanServiceImpl extends BServiceImpl<SchedulePlan, Long> implements SchedulePlanService {
46 @Autowired 36 @Autowired
47 - @Qualifier("kb1")  
48 - private KieBase kieBase; 37 + @Qualifier("coreKBase")
  38 + private KieBase coreKBase;
49 39
50 @Autowired 40 @Autowired
51 - @Qualifier("kb2")  
52 - private KieBase kieBase2; 41 + @Qualifier("preKBase")
  42 + private KieBase preKBase;
53 43
54 @Autowired 44 @Autowired
55 private ScheduleRule1FlatRepository scheduleRule1FlatRepository; 45 private ScheduleRule1FlatRepository scheduleRule1FlatRepository;
@@ -73,398 +63,62 @@ public class SchedulePlanServiceImpl extends BServiceImpl&lt;SchedulePlan, Long&gt; im @@ -73,398 +63,62 @@ public class SchedulePlanServiceImpl extends BServiceImpl&lt;SchedulePlan, Long&gt; im
73 /** 日志记录器 */ 63 /** 日志记录器 */
74 private Logger logger = LoggerFactory.getLogger(SchedulePlanServiceImpl.class); 64 private Logger logger = LoggerFactory.getLogger(SchedulePlanServiceImpl.class);
75 65
76 - /**  
77 - * 计算规则输入。  
78 - * @param schedulePlan  
79 - * @return  
80 - */  
81 - private List<ScheduleRule_input> calcuSrfList(SchedulePlan schedulePlan) {  
82 - // 1-1、构造drools规则输入数据,输出数据  
83 - // 全局计算参数  
84 - ScheduleCalcuParam_input scheduleCalcuParam_input = new ScheduleCalcuParam_input(schedulePlan);  
85 -  
86 - // 规则输出数据  
87 - List<ScheduleRule_input> scheduleRule_inputs = new ArrayList<>();  
88 -  
89 - // 1-2、构造drools session->载入数据->启动规则->计算->销毁session  
90 - // 创建session,内部配置的是stateful  
91 - KieSession session = kieBase2.newKieSession();  
92 - // 设置gloable对象,在drl中通过别名使用  
93 - session.setGlobal("sriList", scheduleRule_inputs);  
94 - session.setGlobal("log", logger); // 设置日志  
95 -  
96 - session.setGlobal("srf", scheduleRule1FlatRepository);  
97 - session.setGlobal("rrr", rerunRuleRepository);  
98 - session.setGlobal("srservice", scheduleRuleService);  
99 -  
100 - // 载入数据  
101 - session.insert(scheduleCalcuParam_input);  
102 -  
103 - // 执行rule  
104 - session.fireAllRules();  
105 -  
106 - // 执行完毕销毁,有日志的也要关闭  
107 - session.dispose();  
108 -  
109 - return scheduleRule_inputs;  
110 - }  
111 -  
112 - /**  
113 - * 循环规则输出。  
114 - * @param schedulePlan 排班计划对象  
115 - * @param lpInfoResults_output 时刻表每日路牌的情况  
116 - */  
117 - private ScheduleResults_output loopRuleOutput(  
118 - SchedulePlan schedulePlan,  
119 - LpInfoResults_output lpInfoResults_output) {  
120 - // 1-1、构造drools规则输入数据,输出数据  
121 - // 全局计算参数  
122 - ScheduleCalcuParam_input scheduleCalcuParam_input = new ScheduleCalcuParam_input(schedulePlan);  
123 - // 每个规则对应的输入参数  
124 - List<ScheduleRule_input> scheduleRule_inputs = calcuSrfList(schedulePlan);  
125 -  
126 - // 规则输出数据  
127 - ScheduleResults_output scheduleResults_output = new ScheduleResults_output();  
128 -  
129 - // 1-2、构造drools session->载入数据->启动规则->计算->销毁session  
130 - // 创建session,内部配置的是stateful  
131 - KieSession session = kieBase.newKieSession();  
132 - // 设置gloable对象,在drl中通过别名使用  
133 - session.setGlobal("scheduleResult", scheduleResults_output);  
134 - session.setGlobal("log", logger); // 设置日志  
135 - session.setGlobal("scheduleRuleService", scheduleRuleService);  
136 -  
137 - // 载入数据  
138 - session.insert(scheduleCalcuParam_input);  
139 - for (ScheduleRule_input scheduleRule_input : scheduleRule_inputs) {  
140 - session.insert(scheduleRule_input);  
141 - }  
142 - // 每日时刻表路牌数据  
143 - for (LpInfoResult_output lpInfoResult_output: lpInfoResults_output.getLpInfoResult_outputs()) {  
144 - session.insert(lpInfoResult_output);  
145 - }  
146 - // 执行rule  
147 - session.fireAllRules();  
148 -  
149 - // 执行完毕销毁,有日志的也要关闭  
150 - session.dispose();  
151 -  
152 - // 保存循环规则结果数据  
153 - scheduleRuleService.generateRuleResult(scheduleResults_output.getSchedulePlanRuleResults());  
154 -  
155 -// logger.info("循环规则输出={}", scheduleResults_output.showGuideboardDesc1());  
156 -  
157 - return scheduleResults_output;  
158 - }  
159 -  
160 - /**  
161 - * 时刻表选择(判定每天使用的时刻表,以及路牌数据输出)。  
162 - * @param schedulePlan 排班计划对象  
163 - * @return TTInfoResults_output, LpInfoResults_output  
164 - */  
165 - private Object[] ttInfoOutput(SchedulePlan schedulePlan) {  
166 - // 获取线路的所有未作废的时刻表  
167 - List<TTInfo> ttInfos = ttInfoRepository.findInCanceledByXl(schedulePlan.getXl());  
168 -  
169 - // 1-1、构造drools规则输入数据,输出数据  
170 - // 全局计算参数  
171 - TTInfoCalcuParam_input ttInfoCalcuParam_input =  
172 - new TTInfoCalcuParam_input(  
173 - new DateTime(schedulePlan.getScheduleFromTime()),  
174 - new DateTime(schedulePlan.getScheduleToTime()),  
175 - String.valueOf(schedulePlan.getXl().getId())  
176 - );  
177 - // 规则输出数据  
178 - TTInfoResults_output ttInfoResults_output = new TTInfoResults_output();  
179 - LpInfoResults_output lpInfoResults_output = new LpInfoResults_output();  
180 -  
181 - // 1-2、构造drools session->载入数据->启动规则->计算->销毁session  
182 - // 创建session,内部配置的是stateful  
183 - KieSession session = kieBase.newKieSession();  
184 -  
185 - // 设置gloable对象,在drl中通过别名使用  
186 - session.setGlobal("results", ttInfoResults_output);  
187 - session.setGlobal("lpInfoResults_output", lpInfoResults_output);  
188 - session.setGlobal("log", logger); // 设置日志  
189 - session.setGlobal("tTInfoDetailRepository", ttInfoDetailRepository);  
190 -  
191 - // 载入数据  
192 - session.insert(ttInfoCalcuParam_input);  
193 - for (TTInfo ttInfo : ttInfos) {  
194 - TTInfo_input ttInfo_input = new TTInfo_input(ttInfo);  
195 - session.insert(ttInfo_input);  
196 - }  
197 -  
198 - // 载入数据2(计算规则最早启用时间)  
199 - List<ScheduleRule1Flat> scheduleRule1Flats = scheduleRule1FlatRepository.findByXl(schedulePlan.getXl());  
200 -  
201 - for (ScheduleRule1Flat scheduleRule1Flat: scheduleRule1Flats) {  
202 - ScheduleRule_input scheduleRule_input = new ScheduleRule_input(scheduleRule1Flat);  
203 - session.insert(scheduleRule_input);  
204 - }  
205 -  
206 - // 执行rule  
207 - session.fireAllRules();  
208 -  
209 - // 执行完毕销毁,有日志的也要关闭  
210 - session.dispose();  
211 -  
212 - return new Object[] {ttInfoResults_output, lpInfoResults_output};  
213 -  
214 - }  
215 -  
216 - /**  
217 - * 排班生成。  
218 - * @param schedulePlan 排班计划对象  
219 - * @param scheduleResults_output loopRuleOutput方法规则输出  
220 - * @param ttInfoResults_output ttInfoOutput方法规则输出  
221 - * @return PlanResult  
222 - */  
223 - private PlanResult planResultOutput(  
224 - SchedulePlan schedulePlan,  
225 - ScheduleResults_output scheduleResults_output,  
226 - TTInfoResults_output ttInfoResults_output) {  
227 -  
228 - // 1-1、构造drools规则输入数据,输出数据  
229 - PlanCalcuParam_input planCalcuParam_input = new PlanCalcuParam_input(  
230 - schedulePlan,  
231 - scheduleResults_output,  
232 - ttInfoResults_output  
233 - );  
234 - // 规则输出数据  
235 - PlanResult planResult = new PlanResult();  
236 - planResult.setXlId(schedulePlan.getXl().getId().toString());  
237 -  
238 - // 1-2、构造drools session->载入数据->启动规则->计算->销毁session  
239 - // 创建session,内部配置的是stateful  
240 - KieSession session = kieBase.newKieSession();  
241 -  
242 - // 设置gloable对象,在drl中通过别名使用  
243 - session.setGlobal("planResult", planResult);  
244 - session.setGlobal("log", logger); // 设置日志  
245 -  
246 - session.setGlobal("tTInfoDetailRepository", ttInfoDetailRepository);  
247 - session.setGlobal("carConfigInfoRepository", carConfigInfoRepository);  
248 - session.setGlobal("employeeConfigInfoRepository", employeeConfigInfoRepository);  
249 - session.setGlobal("lineRepository", lineRepository);  
250 - session.setGlobal("businessRepository", businessRepository);  
251 -  
252 - // 载入数据  
253 - session.insert(planCalcuParam_input);  
254 -  
255 - // 执行rule  
256 - session.fireAllRules();  
257 -  
258 - // 执行完毕销毁,有日志的也要关闭  
259 - session.dispose();  
260 -  
261 - return planResult;  
262 -  
263 - }  
264 -  
265 - /**  
266 - * 生成线路排班(不含套跑规则)。  
267 - * @param schedulePlan  
268 - * @return  
269 - */  
270 - private PlanResult schedulePlanWithOutRerun(SchedulePlan schedulePlan) {  
271 - // 1、时刻表数据及每日路牌数据计算  
272 - Date start1 = new Date();  
273 - Object[] ttInfoRets = ttInfoOutput(schedulePlan);  
274 - TTInfoResults_output ttInfoResults_output = (TTInfoResults_output) ttInfoRets[0];  
275 - LpInfoResults_output lpInfoResults_output = (LpInfoResults_output) ttInfoRets[1];  
276 - Date end1 = new Date();  
277 - // 2、循环规则计算输出  
278 - Date start2 = new Date();  
279 - ScheduleResults_output scheduleResults_output = loopRuleOutput(schedulePlan, lpInfoResults_output);  
280 - Date end2 = new Date();  
281 -  
282 - logger.info("规则计算结果={}", scheduleResults_output.showGuideboardDesc1());  
283 -  
284 - // 3、计划输出  
285 - Date start3 = new Date();  
286 - PlanResult planResult = planResultOutput(schedulePlan, scheduleResults_output, ttInfoResults_output);  
287 - Date end3 = new Date();  
288 -  
289 - logger.info("drool时刻表每日路牌计算 {} ms,drool循环规则计算 {} ms,drool计划数据 {} ms",  
290 - end1.getTime() - start1.getTime(),  
291 - end2.getTime() - start2.getTime(),  
292 - end3.getTime() - start3.getTime());  
293 -  
294 - // TODO:将lpInfoResults_output 也要返回  
295 -  
296 - return planResult;  
297 - }  
298 -  
299 - /**  
300 - * 套跑计划排班数据。  
301 - * @param planResult  
302 - */  
303 - private void rerunPlanResult(PlanResult planResult, SchedulePlan schedulePlan) {  
304 - List<RerunRule_input> rerunRule_inputs = scheduleRuleService.findRerunrule(Integer.parseInt(planResult.getXlId()));  
305 - logger.info("套跑数量 {} 组", rerunRule_inputs.size());  
306 -  
307 - // 主线路id  
308 - Integer mainXlId = schedulePlan.getXl().getId();  
309 -  
310 - if (rerunRule_inputs.size() > 0) {  
311 - // 找出是对应路牌类型的线路,计算循环规则输出  
312 - Set<String> xlids = new HashSet<>();  
313 - for (RerunRule_input rerunRule_input: rerunRule_inputs) {  
314 - if ("dylp".equals(rerunRule_input.getType())) {  
315 - xlids.add(rerunRule_input.getS_xl()); // 参与套跑的线路  
316 - }  
317 - }  
318 -  
319 - List<ScheduleResults_output> scheduleResults_outputs = new ArrayList<>();  
320 - Date start1 = new Date();  
321 - for (String xlid: xlids) {  
322 - schedulePlan.getXl().setId(Integer.parseInt(xlid)); // 套跑的线路默认跟着主线路设定走  
323 - // 获取套跑线路的循环规则计算输出  
324 - Object[] ttInfoRets = ttInfoOutput(schedulePlan);  
325 - LpInfoResults_output lpInfoResults_output = (LpInfoResults_output) ttInfoRets[1];  
326 - ScheduleResults_output scheduleResults_output = loopRuleOutput(schedulePlan, lpInfoResults_output);  
327 - scheduleResults_outputs.add(scheduleResults_output);  
328 - }  
329 -  
330 - // 1-2、构造drools session->载入数据->启动规则->计算->销毁session  
331 - // 创建session,内部配置的是stateful  
332 - KieSession session = kieBase.newKieSession();  
333 -  
334 - // 设置gloable对象,在drl中通过别名使用  
335 - session.setGlobal("planResult", planResult);  
336 - session.setGlobal("log", logger); // 设置日志  
337 -  
338 - session.setGlobal("carConfigInfoRepository", carConfigInfoRepository);  
339 - session.setGlobal("employeeConfigInfoRepository", employeeConfigInfoRepository);  
340 -  
341 - // 载入数据  
342 - RerunRule_param rerunRule_param = new RerunRule_param();  
343 - rerunRule_param.setMxlid(planResult.getXlId());  
344 - rerunRule_param.setXlIds_dylp(xlids);  
345 - session.insert(rerunRule_param);  
346 - for (RerunRule_input rri: rerunRule_inputs) {  
347 - session.insert(rri);  
348 - }  
349 - for (SchedulePlanInfo spi: planResult.getSchedulePlanInfos()) {  
350 - session.insert(spi); 66 + /** 线路独占锁 */
  67 + private ConcurrentHashMap<Integer, ReentrantLock> lineXLatchMaps = new ConcurrentHashMap<>();
  68 + private ReentrantLock getLineXLatch(Integer xlid) {
  69 + ReentrantLock lineXLatch = lineXLatchMaps.get(xlid);
  70 + if (lineXLatch == null) {
  71 + lineXLatch = new ReentrantLock();
  72 + ReentrantLock pre = lineXLatchMaps.putIfAbsent(xlid, lineXLatch);
  73 + if (pre != null) {
  74 + lineXLatch = pre;
351 } 75 }
352 - for (ScheduleResults_output sro: scheduleResults_outputs) {  
353 - session.insert(sro);  
354 - }  
355 -  
356 - // 执行rule  
357 - session.fireAllRules();  
358 -  
359 - // 执行完毕销毁,有日志的也要关闭  
360 - session.dispose();  
361 -  
362 - Date end1 = new Date();  
363 - logger.info("套跑规则计算,耗时 {} ms", end1.getTime() - start1.getTime());  
364 -  
365 - schedulePlan.getXl().setId(mainXlId);  
366 -  
367 - }  
368 -  
369 - }  
370 -  
371 - /**  
372 - * 验证排班结果。  
373 - * @param planResult  
374 - * @param schedulePlan  
375 - */  
376 - public void validPlanResult(PlanResult planResult, SchedulePlan schedulePlan) {  
377 - // 1-1、构造drools规则输入数据,输出数据  
378 - ValidateParam validateParam = new ValidateParam(  
379 - new DateTime(schedulePlan.getScheduleFromTime()),  
380 - new DateTime(schedulePlan.getScheduleToTime())  
381 - );  
382 - // 规则输出数据  
383 - ValidateResults_output result = new ValidateResults_output();  
384 -  
385 - // 1-2、构造drools session->载入数据->启动规则->计算->销毁session  
386 - // 创建session,内部配置的是stateful  
387 - KieSession session = kieBase.newKieSession();  
388 -  
389 - // 设置gloable对象,在drl中通过别名使用  
390 - session.setGlobal("validResult", result);  
391 - session.setGlobal("log", logger); // 设置日志  
392 -  
393 - // 载入数据  
394 - session.insert(validateParam);  
395 - for (SchedulePlanInfo schedulePlanInfo: planResult.getSchedulePlanInfos()) {  
396 - session.insert(schedulePlanInfo);  
397 - }  
398 -  
399 - // 执行rule  
400 - session.fireAllRules();  
401 -  
402 - // 执行完毕销毁,有日志的也要关闭  
403 - session.dispose();  
404 -  
405 -// logger.info("错误总数={}", result.getInfos().size());  
406 -// for (ValidateResults_output.ValidInfo validInfo: result.getInfos()) {  
407 -// logger.info(validInfo.getDesc());  
408 -// }  
409 -  
410 - // 取10条错误  
411 - int size = result.getInfos().size() > 10 ? 10: result.getInfos().size();  
412 - List<String> desclist = new ArrayList<>();  
413 - for (int i = 0; i < size; i++) {  
414 - desclist.add(result.getInfos().get(i).getDesc());  
415 - }  
416 - if (desclist.size() > 0) {  
417 - schedulePlan.setPlanResult(StringUtils.join(desclist, "</br>"));  
418 - } else {  
419 - schedulePlan.setPlanResult("ok");  
420 } 76 }
421 -  
422 - // TODO:设定错误信息 77 + return lineXLatch;
423 } 78 }
424 79
425 @Transactional(propagation = Propagation.REQUIRED, isolation = Isolation.READ_COMMITTED) 80 @Transactional(propagation = Propagation.REQUIRED, isolation = Isolation.READ_COMMITTED)
426 public SchedulePlan save(SchedulePlan schedulePlan) { 81 public SchedulePlan save(SchedulePlan schedulePlan) {
427 - // pre、如果排班的数据之前已经有了,删除之前的数据  
428 - Date startpre = new Date();  
429 - scheduleRuleService.deleteSchedulePlanInfo(  
430 - schedulePlan.getXl().getLineCode(),  
431 - schedulePlan.getScheduleFromTime(),  
432 - schedulePlan.getScheduleToTime());  
433 - Date endpre = new Date();  
434 -  
435 - // 1、查找线路,这是主线路  
436 - Line xl = lineRepository.findOne(schedulePlan.getXl().getId());  
437 - logger.info("<--- 排班master线路 id={}, name={}, 开始排班", xl.getId(), xl.getName());  
438 -  
439 - // 2、确定主线路排班(包含完全套跑路牌规则,所谓完全套跑路牌规则指整个路牌的班次都是套跑规则指定的)  
440 - PlanResult planResult = schedulePlanWithOutRerun(schedulePlan);  
441 -  
442 - // 3、确定套跑规则  
443 - rerunPlanResult(planResult, schedulePlan);  
444 -  
445 - // TODO:3-1、验证排班结果  
446 - validPlanResult(planResult, schedulePlan); 82 + ReentrantLock lineXLatch = getLineXLatch(schedulePlan.getXl().getId());
  83 + try {
  84 + if (lineXLatch.tryLock(1, TimeUnit.SECONDS)) {
  85 + // pre、如果排班的数据之前已经有了,删除之前的数据
  86 + Date startPre = new Date();
  87 + scheduleRuleService.deleteSchedulePlanInfo(
  88 + schedulePlan.getXl().getLineCode(),
  89 + schedulePlan.getScheduleFromTime(),
  90 + schedulePlan.getScheduleToTime());
  91 + Date endPre = new Date();
  92 + logger.info("删除数据 {} ms --->", endPre.getTime() - startPre.getTime());
  93 +
  94 + // core、生成排班计划
  95 + DroolsSchedulePlan droolsSchedulePlan = new DroolsSchedulePlan(
  96 + schedulePlan,
  97 + lineRepository, scheduleRule1FlatRepository,
  98 + ttInfoRepository, ttInfoDetailRepository,
  99 + carConfigInfoRepository, employeeConfigInfoRepository,
  100 + rerunRuleRepository, businessRepository,
  101 + scheduleRuleService,
  102 + preKBase, coreKBase,
  103 + logger
  104 + );
  105 + droolsSchedulePlan.generatePlan();
447 106
448 - // TODO:3-2、去除完全套跑遗漏班次(以后放到规则中执行)  
449 - Iterator<SchedulePlanInfo> infoIterator = planResult.getSchedulePlanInfos().iterator();  
450 - while (infoIterator.hasNext()) {  
451 - SchedulePlanInfo schedulePlanInfo = infoIterator.next();  
452 - if (schedulePlanInfo.getCl() == null) {  
453 - infoIterator.remove(); 107 + return new SchedulePlan();
  108 + } else {
  109 + throw new ScheduleException("当前线路正在排班,请稍后再操作...");
454 } 110 }
455 - } 111 + } catch (Exception exp) {
  112 + throw new RuntimeException(exp);
  113 + } finally {
  114 + try {
  115 + lineXLatch.unlock();
  116 + } catch (Exception exp2) {
456 117
457 - // 4、保存数据(jdbcTemplate 批量插入)  
458 - Date start4 = new Date();  
459 - scheduleRuleService.generateSchedulePlan(schedulePlan, planResult.getSchedulePlanInfos());  
460 - Date end4 = new Date(); 118 + }
461 119
462 - logger.info("删除数据 {} ms,保存主线路数据 {} 条 耗时 {} ms --->",  
463 - endpre.getTime() - startpre.getTime(),  
464 - planResult.getSchedulePlanInfos().size(),  
465 - end4.getTime() - start4.getTime()); 120 + }
466 121
467 - return new SchedulePlan();  
468 } 122 }
469 123
470 @Override 124 @Override
@@ -475,10 +129,12 @@ public class SchedulePlanServiceImpl extends BServiceImpl&lt;SchedulePlan, Long&gt; im @@ -475,10 +129,12 @@ public class SchedulePlanServiceImpl extends BServiceImpl&lt;SchedulePlan, Long&gt; im
475 @Override 129 @Override
476 public SchedulePlan findSchedulePlanTommorw() { 130 public SchedulePlan findSchedulePlanTommorw() {
477 DateTime today = new DateTime(new Date()); 131 DateTime today = new DateTime(new Date());
478 - DateTime tommorw = new DateTime(today.getYear(), today.getMonthOfYear(), today.getDayOfMonth(), 0, 0).plusDays(1); 132 + DateTime tommorw = new DateTime(
  133 + today.getYear(), today.getMonthOfYear(),
  134 + today.getDayOfMonth(), 0, 0).plusDays(1);
479 Map<String, Object> param = new HashMap<>(); 135 Map<String, Object> param = new HashMap<>();
480 param.put("scheduleFromTime_le", tommorw.toDate()); 136 param.put("scheduleFromTime_le", tommorw.toDate());
481 - param.put("scheduleToTime_ge", tommorw.toDate() ); 137 + param.put("scheduleToTime_ge", tommorw.toDate());
482 Iterator<SchedulePlan> schedulePlanIterator = this.list(param).iterator(); 138 Iterator<SchedulePlan> schedulePlanIterator = this.list(param).iterator();
483 if (schedulePlanIterator.hasNext()) { 139 if (schedulePlanIterator.hasNext()) {
484 return schedulePlanIterator.next(); 140 return schedulePlanIterator.next();
@@ -490,7 +146,7 @@ public class SchedulePlanServiceImpl extends BServiceImpl&lt;SchedulePlan, Long&gt; im @@ -490,7 +146,7 @@ public class SchedulePlanServiceImpl extends BServiceImpl&lt;SchedulePlan, Long&gt; im
490 public Result validateTTInfo(Integer xlid, Date from, Date to) { 146 public Result validateTTInfo(Integer xlid, Date from, Date to) {
491 // 构造drools session->载入数据->启动规则->计算->销毁session 147 // 构造drools session->载入数据->启动规则->计算->销毁session
492 // 创建session,内部配置的是stateful 148 // 创建session,内部配置的是stateful
493 - KieSession session = kieBase.newKieSession(); 149 + KieSession session = coreKBase.newKieSession();
494 // 设置gloable对象,在drl中通过别名使用 150 // 设置gloable对象,在drl中通过别名使用
495 session.setGlobal("log", logger); 151 session.setGlobal("log", logger);
496 session.setGlobal("lineRepository", lineRepository); 152 session.setGlobal("lineRepository", lineRepository);
@@ -513,7 +169,6 @@ public class SchedulePlanServiceImpl extends BServiceImpl&lt;SchedulePlan, Long&gt; im @@ -513,7 +169,6 @@ public class SchedulePlanServiceImpl extends BServiceImpl&lt;SchedulePlan, Long&gt; im
513 // 执行完毕销毁,有日志的也要关闭 169 // 执行完毕销毁,有日志的也要关闭
514 session.dispose(); 170 session.dispose();
515 171
516 -  
517 return rs; 172 return rs;
518 } 173 }
519 } 174 }
src/main/java/com/bsth/service/schedule/plan/DroolsSchedulePlan.java 0 → 100644
  1 +package com.bsth.service.schedule.plan;
  2 +
  3 +import com.bsth.entity.Line;
  4 +import com.bsth.entity.schedule.SchedulePlan;
  5 +import com.bsth.entity.schedule.SchedulePlanInfo;
  6 +import com.bsth.entity.schedule.TTInfo;
  7 +import com.bsth.entity.schedule.rule.ScheduleRule1Flat;
  8 +import com.bsth.repository.BusinessRepository;
  9 +import com.bsth.repository.LineRepository;
  10 +import com.bsth.repository.schedule.*;
  11 +import com.bsth.service.schedule.rules.ScheduleRuleService;
  12 +import com.bsth.service.schedule.rules.plan.PlanCalcuParam_input;
  13 +import com.bsth.service.schedule.rules.plan.PlanResult;
  14 +import com.bsth.service.schedule.rules.rerun.RerunRule_input;
  15 +import com.bsth.service.schedule.rules.rerun.RerunRule_param;
  16 +import com.bsth.service.schedule.rules.shiftloop.ScheduleCalcuParam_input;
  17 +import com.bsth.service.schedule.rules.shiftloop.ScheduleResults_output;
  18 +import com.bsth.service.schedule.rules.shiftloop.ScheduleRule_input;
  19 +import com.bsth.service.schedule.rules.ttinfo.*;
  20 +import com.bsth.service.schedule.rules.validate.ValidateParam;
  21 +import com.bsth.service.schedule.rules.validate.ValidateResults_output;
  22 +import org.apache.commons.lang3.StringUtils;
  23 +import org.joda.time.DateTime;
  24 +import org.kie.api.KieBase;
  25 +import org.kie.api.runtime.KieSession;
  26 +import org.slf4j.Logger;
  27 +
  28 +import java.util.*;
  29 +
  30 +/**
  31 + * 排班计划(使用Drools)。
  32 + */
  33 +public class DroolsSchedulePlan {
  34 + /** 主线路 */
  35 + private Line mainLine;
  36 + /** 套跑辅线路规则 */
  37 + private List<RerunRule_input> rerunRule_inputs;
  38 +
  39 + /** 开始排班时间 */
  40 + private Date from;
  41 + /** 结束排班时间 */
  42 + private Date to;
  43 + /** 排班计划entity */
  44 + private SchedulePlan schedulePlan;
  45 +
  46 + //-------------------- 相关的Repo,service服务 --------------------//
  47 + /** 线路Repo */
  48 + private LineRepository lineRepository;
  49 + /** 排班规则Repo */
  50 + private ScheduleRule1FlatRepository scheduleRule1FlatRepository;
  51 + /** 时刻表Repo */
  52 + private TTInfoRepository ttInfoRepository;
  53 + /** 时刻表明细Repo */
  54 + private TTInfoDetailRepository ttInfoDetailRepository;
  55 + /** 车辆配置Repo */
  56 + private CarConfigInfoRepository carConfigInfoRepository;
  57 + /** 人员配置Repo */
  58 + private EmployeeConfigInfoRepository employeeConfigInfoRepository;
  59 + /** 套跑规则Repo */
  60 + private RerunRuleRepository rerunRuleRepository;
  61 + /** 营运状态Repo */
  62 + private BusinessRepository businessRepository;
  63 +
  64 + /** 排班规则service */
  65 + private ScheduleRuleService scheduleRuleService;
  66 +
  67 + //-------------------- Drools KBase实例 ------------------//
  68 + /** 排班预处理KBase */
  69 + private KieBase preKBase;
  70 + /** 排班核心KBase */
  71 + private KieBase coreKBase;
  72 +
  73 + //-------------------- 日志记录器 ---------------------//
  74 + private Logger logger;
  75 +
  76 + public DroolsSchedulePlan(
  77 + SchedulePlan schedulePlan,
  78 + LineRepository lineRepository, ScheduleRule1FlatRepository scheduleRule1FlatRepository,
  79 + TTInfoRepository ttInfoRepository, TTInfoDetailRepository ttInfoDetailRepository,
  80 + CarConfigInfoRepository carConfigInfoRepository,
  81 + EmployeeConfigInfoRepository employeeConfigInfoRepository,
  82 + RerunRuleRepository rerunRuleRepository,
  83 + BusinessRepository businessRepository,
  84 + ScheduleRuleService scheduleRuleService,
  85 + KieBase preKBase, KieBase coreKBase,
  86 + Logger logger) {
  87 +
  88 + // 验证SchedulePlan实体
  89 + if (schedulePlan == null) {
  90 + throw new RuntimeException("排班用SchedulePlan为空!");
  91 + }
  92 + if (schedulePlan.getXl() == null) {
  93 + throw new RuntimeException("排班线路为空!");
  94 + } else {
  95 + // 获取主线路
  96 + this.mainLine = lineRepository.findOne(schedulePlan.getXl().getId());
  97 + if (this.mainLine == null) {
  98 + throw new RuntimeException("线路id=" + schedulePlan.getXl().getId() + "不存在!");
  99 + }
  100 + // 获取主线路套跑信息
  101 + this.rerunRule_inputs = scheduleRuleService.findRerunrule(this.mainLine.getId());
  102 + }
  103 + if (schedulePlan.getScheduleFromTime() == null) {
  104 + throw new RuntimeException("排班开始时间为空!");
  105 + }
  106 + if (schedulePlan.getScheduleToTime() == null) {
  107 + throw new RuntimeException("排班结束时间为空!");
  108 + }
  109 + this.from = schedulePlan.getScheduleFromTime();
  110 + this.to = schedulePlan.getScheduleToTime();
  111 + if (schedulePlan.getTtInfoIds() == null) {
  112 + throw new RuntimeException("排班关联的时刻表ids为空!");
  113 + }
  114 + if (schedulePlan.getTtInfoNames() == null) {
  115 + throw new RuntimeException("排班关联的时刻表名字s为空!");
  116 + }
  117 + this.schedulePlan = schedulePlan;
  118 +
  119 + this.lineRepository = lineRepository;
  120 + this.scheduleRule1FlatRepository = scheduleRule1FlatRepository;
  121 + this.ttInfoRepository = ttInfoRepository;
  122 + this.ttInfoDetailRepository = ttInfoDetailRepository;
  123 + this.carConfigInfoRepository = carConfigInfoRepository;
  124 + this.employeeConfigInfoRepository = employeeConfigInfoRepository;
  125 + this.rerunRuleRepository = rerunRuleRepository;
  126 + this.businessRepository = businessRepository;
  127 + this.scheduleRuleService = scheduleRuleService;
  128 + this.preKBase = preKBase;
  129 + this.coreKBase = coreKBase;
  130 +
  131 + this.logger = logger;
  132 +
  133 + }
  134 +
  135 + public void generatePlan() {
  136 + logger.info("<--- 排班master线路 id={}, name={}, 开始排班",
  137 + this.mainLine.getId(), this.mainLine.getName());
  138 +
  139 + // 1、确定主线路排班(包含完全套跑路牌规则,所谓完全套跑路牌规则指整个路牌的班次都是套跑规则指定的)
  140 + PlanResult planResult = this.schedulePlanWithOutRerun();
  141 +
  142 + // 2、确定套跑规则
  143 + this.rerunPlanResult(planResult);
  144 +
  145 + // TODO:3-1、验证排班结果
  146 + this.validPlanResult(planResult);
  147 +
  148 + // TODO:3-2、去除完全套跑遗漏班次(以后放到规则中执行)
  149 + Iterator<SchedulePlanInfo> infoIterator = planResult.getSchedulePlanInfos().iterator();
  150 + while (infoIterator.hasNext()) {
  151 + SchedulePlanInfo schedulePlanInfo = infoIterator.next();
  152 + if (schedulePlanInfo.getCl() == null) {
  153 + infoIterator.remove();
  154 + }
  155 + }
  156 +
  157 + // 4、保存数据(jdbcTemplate 批量插入)
  158 + Date start4 = new Date();
  159 + this.scheduleRuleService.generateSchedulePlan(
  160 + this.schedulePlan, planResult.getSchedulePlanInfos());
  161 + Date end4 = new Date();
  162 +
  163 + this.logger.info("保存主线路数据 {} 条 耗时 {} ms --->",
  164 + planResult.getSchedulePlanInfos().size(),
  165 + end4.getTime() - start4.getTime());
  166 + }
  167 +
  168 + /**
  169 + * 计算规则输入。
  170 + * @return
  171 + */
  172 + private List<ScheduleRule_input> calcuSrfList(Line line) {
  173 + // 1-1、构造drools规则输入数据,输出数据
  174 + // 全局计算参数
  175 + SchedulePlan schedulePlan = new SchedulePlan();
  176 + schedulePlan.setXl(line);
  177 + schedulePlan.setScheduleFromTime(this.from);
  178 + schedulePlan.setScheduleToTime(this.to);
  179 + ScheduleCalcuParam_input scheduleCalcuParam_input = new ScheduleCalcuParam_input(schedulePlan);
  180 +
  181 + // 规则输出数据
  182 + List<ScheduleRule_input> scheduleRule_inputs = new ArrayList<>();
  183 +
  184 + // 1-2、构造drools session->载入数据->启动规则->计算->销毁session
  185 + // 创建session,内部配置的是stateful
  186 + KieSession session = preKBase.newKieSession();
  187 + // 设置gloable对象,在drl中通过别名使用
  188 + session.setGlobal("sriList", scheduleRule_inputs);
  189 + session.setGlobal("log", logger); // 设置日志
  190 +
  191 + session.setGlobal("srf", scheduleRule1FlatRepository);
  192 + session.setGlobal("rrr", rerunRuleRepository);
  193 + session.setGlobal("srservice", scheduleRuleService);
  194 +
  195 + // 载入数据
  196 + session.insert(scheduleCalcuParam_input);
  197 +
  198 + // 执行rule
  199 + session.fireAllRules();
  200 +
  201 + // 执行完毕销毁,有日志的也要关闭
  202 + session.dispose();
  203 +
  204 + return scheduleRule_inputs;
  205 + }
  206 +
  207 + /**
  208 + * 时刻表选择(判定每天使用的时刻表,以及路牌数据输出)。
  209 + * @return [TTInfoResults_output, LpInfoResults_output]
  210 + */
  211 + private Object[] ttInfoOutput(Line line) {
  212 + // 获取线路的所有未作废的时刻表
  213 + List<TTInfo> ttInfos = ttInfoRepository.findInCanceledByXl(line);
  214 +
  215 + // 1-1、构造drools规则输入数据,输出数据
  216 + // 全局计算参数
  217 + TTInfoCalcuParam_input ttInfoCalcuParam_input =
  218 + new TTInfoCalcuParam_input(
  219 + new DateTime(this.from),
  220 + new DateTime(this.to),
  221 + String.valueOf(line.getId())
  222 + );
  223 + // 规则输出数据
  224 + TTInfoResults_output ttInfoResults_output = new TTInfoResults_output();
  225 + LpInfoResults_output lpInfoResults_output = new LpInfoResults_output();
  226 +
  227 + // 1-2、构造drools session->载入数据->启动规则->计算->销毁session
  228 + // 创建session,内部配置的是stateful
  229 + KieSession session = coreKBase.newKieSession();
  230 +
  231 + // 设置gloable对象,在drl中通过别名使用
  232 + session.setGlobal("results", ttInfoResults_output);
  233 + session.setGlobal("lpInfoResults_output", lpInfoResults_output);
  234 + session.setGlobal("log", logger); // 设置日志
  235 + session.setGlobal("tTInfoDetailRepository", ttInfoDetailRepository);
  236 +
  237 + // 载入数据
  238 + session.insert(ttInfoCalcuParam_input);
  239 + for (TTInfo ttInfo : ttInfos) {
  240 + TTInfo_input ttInfo_input = new TTInfo_input(ttInfo);
  241 + session.insert(ttInfo_input);
  242 + }
  243 +
  244 + // 载入数据2(计算规则最早启用时间)
  245 + List<ScheduleRule1Flat> scheduleRule1Flats = scheduleRule1FlatRepository.findByXl(line);
  246 +
  247 + for (ScheduleRule1Flat scheduleRule1Flat: scheduleRule1Flats) {
  248 + ScheduleRule_input scheduleRule_input = new ScheduleRule_input(scheduleRule1Flat);
  249 + session.insert(scheduleRule_input);
  250 + }
  251 +
  252 + // 执行rule
  253 + session.fireAllRules();
  254 +
  255 + // 执行完毕销毁,有日志的也要关闭
  256 + session.dispose();
  257 +
  258 + return new Object[] {ttInfoResults_output, lpInfoResults_output};
  259 +
  260 + }
  261 +
  262 + /**
  263 + * 循环规则输出。
  264 + * @param lpInfoResults_output 时刻表每日路牌的情况
  265 + */
  266 + private ScheduleResults_output loopRuleOutput(Line line, LpInfoResults_output lpInfoResults_output) {
  267 + // 1-1、构造drools规则输入数据,输出数据
  268 + // 全局计算参数
  269 + SchedulePlan schedulePlan = new SchedulePlan();
  270 + schedulePlan.setXl(line);
  271 + schedulePlan.setScheduleFromTime(this.from);
  272 + schedulePlan.setScheduleToTime(this.to);
  273 + schedulePlan.setIsHistoryPlanFirst(this.schedulePlan.getIsHistoryPlanFirst());
  274 + schedulePlan.setCreateBy(this.schedulePlan.getCreateBy());
  275 + ScheduleCalcuParam_input scheduleCalcuParam_input = new ScheduleCalcuParam_input(schedulePlan);
  276 + // 每个规则对应的输入参数
  277 + List<ScheduleRule_input> scheduleRule_inputs = this.calcuSrfList(line);
  278 +
  279 + // 规则输出数据
  280 + ScheduleResults_output scheduleResults_output = new ScheduleResults_output();
  281 +
  282 + // 1-2、构造drools session->载入数据->启动规则->计算->销毁session
  283 + // 创建session,内部配置的是stateful
  284 + KieSession session = coreKBase.newKieSession();
  285 + // 设置gloable对象,在drl中通过别名使用
  286 + session.setGlobal("scheduleResult", scheduleResults_output);
  287 + session.setGlobal("log", logger); // 设置日志
  288 + session.setGlobal("scheduleRuleService", scheduleRuleService);
  289 +
  290 + // 载入数据
  291 + session.insert(scheduleCalcuParam_input);
  292 + for (ScheduleRule_input scheduleRule_input : scheduleRule_inputs) {
  293 + session.insert(scheduleRule_input);
  294 + }
  295 + // 每日时刻表路牌数据
  296 + for (LpInfoResult_output lpInfoResult_output: lpInfoResults_output.getLpInfoResult_outputs()) {
  297 + session.insert(lpInfoResult_output);
  298 + }
  299 + // 执行rule
  300 + session.fireAllRules();
  301 +
  302 + // 执行完毕销毁,有日志的也要关闭
  303 + session.dispose();
  304 +
  305 + // 保存循环规则结果数据
  306 + scheduleRuleService.generateRuleResult(scheduleResults_output.getSchedulePlanRuleResults());
  307 +
  308 +// logger.info("循环规则输出={}", scheduleResults_output.showGuideboardDesc1());
  309 +
  310 + return scheduleResults_output;
  311 + }
  312 +
  313 + /**
  314 + * 排班生成。
  315 + * @param scheduleResults_output loopRuleOutput方法规则输出
  316 + * @param ttInfoResults_output ttInfoOutput方法规则输出
  317 + * @return PlanResult
  318 + */
  319 + private PlanResult planResultOutput(
  320 + Line line,
  321 + ScheduleResults_output scheduleResults_output,
  322 + TTInfoResults_output ttInfoResults_output) {
  323 +
  324 + SchedulePlan schedulePlan = new SchedulePlan();
  325 + schedulePlan.setXl(line);
  326 + schedulePlan.setScheduleFromTime(this.from);
  327 + schedulePlan.setScheduleToTime(this.to);
  328 + schedulePlan.setCreateBy(this.schedulePlan.getCreateBy());
  329 + schedulePlan.setUpdateBy(this.schedulePlan.getUpdateBy());
  330 +
  331 + // 1-1、构造drools规则输入数据,输出数据
  332 + PlanCalcuParam_input planCalcuParam_input = new PlanCalcuParam_input(
  333 + schedulePlan,
  334 + scheduleResults_output,
  335 + ttInfoResults_output
  336 + );
  337 + // 规则输出数据
  338 + PlanResult planResult = new PlanResult();
  339 + planResult.setXlId(schedulePlan.getXl().getId().toString());
  340 +
  341 + // 1-2、构造drools session->载入数据->启动规则->计算->销毁session
  342 + // 创建session,内部配置的是stateful
  343 + KieSession session = this.coreKBase.newKieSession();
  344 +
  345 + // 设置gloable对象,在drl中通过别名使用
  346 + session.setGlobal("planResult", planResult);
  347 + session.setGlobal("log", this.logger); // 设置日志
  348 +
  349 + session.setGlobal("tTInfoDetailRepository", this.ttInfoDetailRepository);
  350 + session.setGlobal("carConfigInfoRepository", this.carConfigInfoRepository);
  351 + session.setGlobal("employeeConfigInfoRepository", this.employeeConfigInfoRepository);
  352 + session.setGlobal("lineRepository", this.lineRepository);
  353 + session.setGlobal("businessRepository", this.businessRepository);
  354 +
  355 + // 载入数据
  356 + session.insert(planCalcuParam_input);
  357 +
  358 + // 执行rule
  359 + session.fireAllRules();
  360 +
  361 + // 执行完毕销毁,有日志的也要关闭
  362 + session.dispose();
  363 +
  364 + return planResult;
  365 +
  366 + }
  367 +
  368 + /**
  369 + * 生成线路排班(不含套跑规则)。
  370 + * @param schedulePlan
  371 + * @return
  372 + */
  373 + private PlanResult schedulePlanWithOutRerun() {
  374 + // 1、时刻表数据及每日路牌数据计算
  375 + Date start1 = new Date();
  376 + Object[] ttInfoRets = this.ttInfoOutput(this.mainLine);
  377 + TTInfoResults_output ttInfoResults_output = (TTInfoResults_output) ttInfoRets[0];
  378 + LpInfoResults_output lpInfoResults_output = (LpInfoResults_output) ttInfoRets[1];
  379 + Date end1 = new Date();
  380 + // 2、循环规则计算输出
  381 + Date start2 = new Date();
  382 + ScheduleResults_output scheduleResults_output = this.loopRuleOutput(
  383 + this.mainLine, lpInfoResults_output);
  384 + Date end2 = new Date();
  385 +
  386 + logger.info("规则计算结果={}", scheduleResults_output.showGuideboardDesc1());
  387 +
  388 + // 3、计划输出
  389 + Date start3 = new Date();
  390 + PlanResult planResult = planResultOutput(
  391 + this.mainLine, scheduleResults_output, ttInfoResults_output);
  392 + Date end3 = new Date();
  393 +
  394 + logger.info("drool时刻表每日路牌计算 {} ms,drool循环规则计算 {} ms,drool计划数据 {} ms",
  395 + end1.getTime() - start1.getTime(),
  396 + end2.getTime() - start2.getTime(),
  397 + end3.getTime() - start3.getTime());
  398 +
  399 + // TODO:将lpInfoResults_output 也要返回
  400 +
  401 + return planResult;
  402 + }
  403 +
  404 + /**
  405 + * 套跑计划排班数据。
  406 + * @param planResult
  407 + */
  408 + private void rerunPlanResult(PlanResult planResult) {
  409 + logger.info("套跑数量 {} 组", this.rerunRule_inputs.size());
  410 +
  411 + if (this.rerunRule_inputs.size() > 0) {
  412 + // 找出是对应路牌类型的线路,计算循环规则输出
  413 + Set<String> dylpxlids = new HashSet<>();
  414 + for (RerunRule_input rerunRule_input: rerunRule_inputs) {
  415 + if ("dylp".equals(rerunRule_input.getType())) {
  416 + dylpxlids.add(rerunRule_input.getS_xl()); // 参与套跑的线路
  417 + }
  418 + }
  419 +
  420 + List<ScheduleResults_output> scheduleResults_outputs = new ArrayList<>();
  421 + Date start1 = new Date();
  422 + for (String xlid: dylpxlids) {
  423 + Line dylpline = new Line(); // 套跑的线路默认跟着主线路设定走
  424 + dylpline.setId(Integer.parseInt(xlid));
  425 + // 获取套跑线路的循环规则计算输出
  426 + Object[] ttInfoRets = this.ttInfoOutput(dylpline);
  427 + LpInfoResults_output lpInfoResults_output = (LpInfoResults_output) ttInfoRets[1];
  428 + ScheduleResults_output scheduleResults_output = this.loopRuleOutput(
  429 + dylpline, lpInfoResults_output);
  430 + scheduleResults_outputs.add(scheduleResults_output);
  431 + }
  432 +
  433 + // 1-2、构造drools session->载入数据->启动规则->计算->销毁session
  434 + // 创建session,内部配置的是stateful
  435 + KieSession session = this.coreKBase.newKieSession();
  436 +
  437 + // 设置gloable对象,在drl中通过别名使用
  438 + session.setGlobal("planResult", planResult);
  439 + session.setGlobal("log", this.logger); // 设置日志
  440 +
  441 + session.setGlobal("carConfigInfoRepository", this.carConfigInfoRepository);
  442 + session.setGlobal("employeeConfigInfoRepository", this.employeeConfigInfoRepository);
  443 +
  444 + // 载入数据
  445 + RerunRule_param rerunRule_param = new RerunRule_param();
  446 + rerunRule_param.setMxlid(planResult.getXlId());
  447 + rerunRule_param.setXlIds_dylp(dylpxlids);
  448 + session.insert(rerunRule_param);
  449 + for (RerunRule_input rri: this.rerunRule_inputs) {
  450 + session.insert(rri);
  451 + }
  452 + for (SchedulePlanInfo spi: planResult.getSchedulePlanInfos()) {
  453 + session.insert(spi);
  454 + }
  455 + for (ScheduleResults_output sro: scheduleResults_outputs) {
  456 + session.insert(sro);
  457 + }
  458 +
  459 + // 执行rule
  460 + session.fireAllRules();
  461 +
  462 + // 执行完毕销毁,有日志的也要关闭
  463 + session.dispose();
  464 +
  465 + Date end1 = new Date();
  466 + logger.info("套跑规则计算,耗时 {} ms", end1.getTime() - start1.getTime());
  467 +
  468 + }
  469 +
  470 + }
  471 +
  472 + /**
  473 + * 验证排班结果。
  474 + * @param planResult
  475 + * @param schedulePlan
  476 + */
  477 + public void validPlanResult(PlanResult planResult) {
  478 + // 1-1、构造drools规则输入数据,输出数据
  479 + ValidateParam validateParam = new ValidateParam(
  480 + new DateTime(this.from), new DateTime(this.to));
  481 + // 规则输出数据
  482 + ValidateResults_output result = new ValidateResults_output();
  483 +
  484 + // 1-2、构造drools session->载入数据->启动规则->计算->销毁session
  485 + // 创建session,内部配置的是stateful
  486 + KieSession session = this.coreKBase.newKieSession();
  487 +
  488 + // 设置gloable对象,在drl中通过别名使用
  489 + session.setGlobal("validResult", result);
  490 + session.setGlobal("log", this.logger); // 设置日志
  491 +
  492 + // 载入数据
  493 + session.insert(validateParam);
  494 + for (SchedulePlanInfo schedulePlanInfo: planResult.getSchedulePlanInfos()) {
  495 + session.insert(schedulePlanInfo);
  496 + }
  497 +
  498 + // 执行rule
  499 + session.fireAllRules();
  500 +
  501 + // 执行完毕销毁,有日志的也要关闭
  502 + session.dispose();
  503 +
  504 +// logger.info("错误总数={}", result.getInfos().size());
  505 +// for (ValidateResults_output.ValidInfo validInfo: result.getInfos()) {
  506 +// logger.info(validInfo.getDesc());
  507 +// }
  508 +
  509 + // 取10条错误
  510 + int size = result.getInfos().size() > 10 ? 10: result.getInfos().size();
  511 + List<String> desclist = new ArrayList<>();
  512 + for (int i = 0; i < size; i++) {
  513 + desclist.add(result.getInfos().get(i).getDesc());
  514 + }
  515 + if (desclist.size() > 0) {
  516 + this.schedulePlan.setPlanResult(StringUtils.join(desclist, "</br>"));
  517 + } else {
  518 + this.schedulePlan.setPlanResult("ok");
  519 + }
  520 +
  521 + // TODO:设定错误信息
  522 + }
  523 +
  524 +}
src/main/java/com/bsth/service/schedule/rules/MyDroolsConfiguration.java
@@ -28,7 +28,7 @@ public class MyDroolsConfiguration { @@ -28,7 +28,7 @@ public class MyDroolsConfiguration {
28 * 返回一个kiebase知识库,直接冲文件系统读入drl规则文件, 28 * 返回一个kiebase知识库,直接冲文件系统读入drl规则文件,
29 * TODO:以后需要从数据库读入规则文件,并重新创建kbase知识库。 29 * TODO:以后需要从数据库读入规则文件,并重新创建kbase知识库。
30 */ 30 */
31 - @Bean(name = "kb1") 31 + @Bean(name = "coreKBase")
32 public KieBase myKieBase() { 32 public KieBase myKieBase() {
33 // Drools 6开始引入kie统一接口(jboss的jbpm工作流也使用kie接口了),整个定义方式和5差别很大 33 // Drools 6开始引入kie统一接口(jboss的jbpm工作流也使用kie接口了),整个定义方式和5差别很大
34 // 这里使用全api方式创建知识库对象,不使用xml的方式,提供最大的灵活性 34 // 这里使用全api方式创建知识库对象,不使用xml的方式,提供最大的灵活性
@@ -105,7 +105,7 @@ public class MyDroolsConfiguration { @@ -105,7 +105,7 @@ public class MyDroolsConfiguration {
105 * 返回一个kiebase知识库,直接冲文件系统读入drl规则文件, 105 * 返回一个kiebase知识库,直接冲文件系统读入drl规则文件,
106 * TODO:以后需要从数据库读入规则文件,并重新创建kbase知识库。 106 * TODO:以后需要从数据库读入规则文件,并重新创建kbase知识库。
107 */ 107 */
108 - @Bean(name = "kb2") 108 + @Bean(name = "preKBase")
109 public KieBase myKieBase2() { 109 public KieBase myKieBase2() {
110 // Drools 6开始引入kie统一接口(jboss的jbpm工作流也使用kie接口了),整个定义方式和5差别很大 110 // Drools 6开始引入kie统一接口(jboss的jbpm工作流也使用kie接口了),整个定义方式和5差别很大
111 // 这里使用全api方式创建知识库对象,不使用xml的方式,提供最大的灵活性 111 // 这里使用全api方式创建知识库对象,不使用xml的方式,提供最大的灵活性