|  |  |  | 
|---|
|  |  |  | import org.springframework.scheduling.annotation.Scheduled; | 
|---|
|  |  |  | import org.springframework.stereotype.Component; | 
|---|
|  |  |  |  | 
|---|
|  |  |  | import javax.annotation.PostConstruct; | 
|---|
|  |  |  | import javax.annotation.PreDestroy; | 
|---|
|  |  |  | import java.util.ArrayList; | 
|---|
|  |  |  | import java.util.List; | 
|---|
|  |  |  | import java.util.Map; | 
|---|
|  |  |  | import java.util.concurrent.ConcurrentHashMap; | 
|---|
|  |  |  | 
|---|
|  |  |  | @Component | 
|---|
|  |  |  | public class FakeProcessor { | 
|---|
|  |  |  |  | 
|---|
|  |  |  |  | 
|---|
|  |  |  | private final RedisSupport redis = RedisSupport.defaultRedisSupport; | 
|---|
|  |  |  |  | 
|---|
|  |  |  | public static final Map<Long, Boolean> AGV_PROCESSING_MAP = new ConcurrentHashMap<>(); | 
|---|
|  |  |  |  | 
|---|
|  |  |  | private ExecutorService executorService; | 
|---|
|  |  |  |  | 
|---|
|  |  |  | private List<Agv> agvList = new ArrayList<>(); | 
|---|
|  |  |  |  | 
|---|
|  |  |  | private Thread heartBeatThread; | 
|---|
|  |  |  |  | 
|---|
|  |  |  | private Thread responseThread; | 
|---|
|  |  |  |  | 
|---|
|  |  |  | private Thread simulatorTread; | 
|---|
|  |  |  |  | 
|---|
|  |  |  | @Autowired | 
|---|
|  |  |  | private AgvService agvService; | 
|---|
|  |  |  | 
|---|
|  |  |  | @Autowired | 
|---|
|  |  |  | private JamService jamService; | 
|---|
|  |  |  |  | 
|---|
|  |  |  | /** | 
|---|
|  |  |  | * 1.AgvDataService.dataProcess [ agvDetail: vol, code, agvAngle, agvStatus ] | 
|---|
|  |  |  | * 2.MainService.upDataSubscribe | 
|---|
|  |  |  | * 3.AgvCmdService.executeRequest {@link com.zy.acs.manager.core.service.AgvCmdService#executeAgvActionCmd} | 
|---|
|  |  |  | * 4.AgvServiceImpl.judgeOnline | 
|---|
|  |  |  | * 5. | 
|---|
|  |  |  | */ | 
|---|
|  |  |  | @Scheduled(cron = "0/1 * * * * ? ") | 
|---|
|  |  |  | public void process() { | 
|---|
|  |  |  | Boolean fakeSign = configService.getVal("fakeSign", Boolean.class); | 
|---|
|  |  |  | if (null == fakeSign || !fakeSign) { | 
|---|
|  |  |  | return; | 
|---|
|  |  |  | } | 
|---|
|  |  |  | @PostConstruct | 
|---|
|  |  |  | public void init() { | 
|---|
|  |  |  | // heartBeat | 
|---|
|  |  |  | this.heartBeatThread = new Thread(() -> { | 
|---|
|  |  |  | while (!Thread.currentThread().isInterrupted()) { | 
|---|
|  |  |  | try { | 
|---|
|  |  |  | Thread.sleep(1000); | 
|---|
|  |  |  |  | 
|---|
|  |  |  | List<Agv> agvList = agvService.list(new LambdaQueryWrapper<Agv>().eq(Agv::getStatus, 1)); | 
|---|
|  |  |  | // init executorService | 
|---|
|  |  |  | if (null == this.executorService) { | 
|---|
|  |  |  | int count = agvList.size(); | 
|---|
|  |  |  | this.executorService = Executors.newFixedThreadPool(count); | 
|---|
|  |  |  | log.info("Initialized ExecutorService with {} threads.", count); | 
|---|
|  |  |  | } | 
|---|
|  |  |  | if (configService.getVal("fakeSign", Boolean.class)) { | 
|---|
|  |  |  | this.processOnline(); | 
|---|
|  |  |  | } | 
|---|
|  |  |  |  | 
|---|
|  |  |  | this.responseTheRequest(); | 
|---|
|  |  |  |  | 
|---|
|  |  |  | for (Agv agv : agvList) { | 
|---|
|  |  |  | AGV_PROCESSING_MAP.putIfAbsent(agv.getId(), false); | 
|---|
|  |  |  |  | 
|---|
|  |  |  | this.processOnline(agv); | 
|---|
|  |  |  |  | 
|---|
|  |  |  | if (!AGV_PROCESSING_MAP.get(agv.getId())) { | 
|---|
|  |  |  | List<Action> actionList = actionService.queryLatestGroup(agv.getId(), ActionStsType.ISSUED); | 
|---|
|  |  |  | if (!Cools.isEmpty(actionList)) { | 
|---|
|  |  |  | AGV_PROCESSING_MAP.put(agv.getId(), true); | 
|---|
|  |  |  | executorService.submit(new AgvSimulatorTask( | 
|---|
|  |  |  | agv | 
|---|
|  |  |  | , redis | 
|---|
|  |  |  | , agvDetailService | 
|---|
|  |  |  | , actionService | 
|---|
|  |  |  | , codeService | 
|---|
|  |  |  | , mapService | 
|---|
|  |  |  | , jamService | 
|---|
|  |  |  | , actionList | 
|---|
|  |  |  | )); | 
|---|
|  |  |  | } catch (Exception e) { | 
|---|
|  |  |  | log.error("FakeProcessor.heartBeatThread fail", e); | 
|---|
|  |  |  | } | 
|---|
|  |  |  | } | 
|---|
|  |  |  | }); | 
|---|
|  |  |  | this.heartBeatThread.start(); | 
|---|
|  |  |  |  | 
|---|
|  |  |  | } | 
|---|
|  |  |  | // response the request | 
|---|
|  |  |  | this.responseThread = new Thread(() -> { | 
|---|
|  |  |  | while (!Thread.currentThread().isInterrupted()) { | 
|---|
|  |  |  | try { | 
|---|
|  |  |  | Thread.sleep(30); | 
|---|
|  |  |  |  | 
|---|
|  |  |  | if (configService.getVal("fakeSign", Boolean.class)) { | 
|---|
|  |  |  | this.responseTheRequest(); | 
|---|
|  |  |  | } | 
|---|
|  |  |  |  | 
|---|
|  |  |  | } catch (Exception e) { | 
|---|
|  |  |  | log.error("FakeProcessor.responseThread fail", e); | 
|---|
|  |  |  | } | 
|---|
|  |  |  | } | 
|---|
|  |  |  | }); | 
|---|
|  |  |  | this.responseThread.start(); | 
|---|
|  |  |  |  | 
|---|
|  |  |  | /** | 
|---|
|  |  |  | * 1.AgvDataService.dataProcess [ agvDetail: vol, code, agvAngle, agvStatus ] | 
|---|
|  |  |  | * 2.MainService.upDataSubscribe | 
|---|
|  |  |  | * 3.AgvCmdService.executeRequest {@link com.zy.acs.manager.core.service.AgvCmdService#executeAgvActionCmd} | 
|---|
|  |  |  | * 4.AgvServiceImpl.judgeOnline | 
|---|
|  |  |  | */ | 
|---|
|  |  |  | // Simulator | 
|---|
|  |  |  | this.simulatorTread = new Thread(() -> { | 
|---|
|  |  |  | while (!Thread.currentThread().isInterrupted()) { | 
|---|
|  |  |  | try { | 
|---|
|  |  |  | Thread.sleep(30); | 
|---|
|  |  |  |  | 
|---|
|  |  |  | if (configService.getVal("fakeSign", Boolean.class)) { | 
|---|
|  |  |  |  | 
|---|
|  |  |  | List<Agv> agvList = this.getAgvList(); | 
|---|
|  |  |  | if (null == this.executorService) { | 
|---|
|  |  |  | int count = agvList.size(); | 
|---|
|  |  |  | this.executorService = Executors.newFixedThreadPool(count); | 
|---|
|  |  |  | } | 
|---|
|  |  |  |  | 
|---|
|  |  |  | for (Agv agv : agvList) { | 
|---|
|  |  |  |  | 
|---|
|  |  |  | if (!AGV_PROCESSING_MAP.get(agv.getId())) { | 
|---|
|  |  |  | List<Action> actionList = actionService.queryLatestGroup(agv.getId(), ActionStsType.ISSUED); | 
|---|
|  |  |  | if (!Cools.isEmpty(actionList)) { | 
|---|
|  |  |  | AGV_PROCESSING_MAP.put(agv.getId(), true); | 
|---|
|  |  |  | executorService.submit(new AgvSimulatorTask( | 
|---|
|  |  |  | agv | 
|---|
|  |  |  | , redis | 
|---|
|  |  |  | , agvDetailService | 
|---|
|  |  |  | , actionService | 
|---|
|  |  |  | , codeService | 
|---|
|  |  |  | , mapService | 
|---|
|  |  |  | , jamService | 
|---|
|  |  |  | , actionList | 
|---|
|  |  |  | )); | 
|---|
|  |  |  | } | 
|---|
|  |  |  | } | 
|---|
|  |  |  |  | 
|---|
|  |  |  | } | 
|---|
|  |  |  |  | 
|---|
|  |  |  | } else { | 
|---|
|  |  |  | this.shutdownFakeThreads(); | 
|---|
|  |  |  | } | 
|---|
|  |  |  |  | 
|---|
|  |  |  | } catch (Exception e) { | 
|---|
|  |  |  | log.error("FakeProcessor.simulatorTread fail", e); | 
|---|
|  |  |  | } | 
|---|
|  |  |  | } | 
|---|
|  |  |  | }); | 
|---|
|  |  |  | this.simulatorTread.start(); | 
|---|
|  |  |  | } | 
|---|
|  |  |  |  | 
|---|
|  |  |  | private void processOnline(Agv agv) { | 
|---|
|  |  |  | redis.setObject(RedisConstant.AGV_ONLINE_FLAG, agv.getUuid(), 1, 30); | 
|---|
|  |  |  | private void processOnline() { | 
|---|
|  |  |  | for (Agv agv : this.getAgvList()) { | 
|---|
|  |  |  | redis.setObject(RedisConstant.AGV_ONLINE_FLAG, agv.getUuid(), 1, 30); | 
|---|
|  |  |  | } | 
|---|
|  |  |  | } | 
|---|
|  |  |  |  | 
|---|
|  |  |  | private void responseTheRequest() { | 
|---|
|  |  |  | AgvProtocol protocol = redis.pop(RedisConstant.AGV_PATH_DOWN_FLAG); | 
|---|
|  |  |  | if (null != protocol) { | 
|---|
|  |  |  | try { | 
|---|
|  |  |  | Thread.sleep(100); | 
|---|
|  |  |  | } catch (InterruptedException ignore) {} | 
|---|
|  |  |  |  | 
|---|
|  |  |  | AGV_01_DOWN agv_01_down = (AGV_01_DOWN) protocol.getMessageBody(); | 
|---|
|  |  |  |  | 
|---|
|  |  |  | AGV_01_UP agv_01_up = new AGV_01_UP(); | 
|---|
|  |  |  | 
|---|
|  |  |  | } | 
|---|
|  |  |  | } | 
|---|
|  |  |  |  | 
|---|
|  |  |  | private void shutdownExecutorService() { | 
|---|
|  |  |  | if (this.executorService != null && !executorService.isShutdown()) { | 
|---|
|  |  |  | log.info("Shutting down ExecutorService."); | 
|---|
|  |  |  | executorService.shutdown(); | 
|---|
|  |  |  | public List<Agv> getAgvList() { | 
|---|
|  |  |  | if (Cools.isEmpty(this.agvList)) { | 
|---|
|  |  |  | this.agvList = agvService.list(new LambdaQueryWrapper<Agv>().eq(Agv::getStatus, 1)); | 
|---|
|  |  |  | this.agvList.forEach(agv -> {AGV_PROCESSING_MAP.putIfAbsent(agv.getId(), false);}); | 
|---|
|  |  |  | } | 
|---|
|  |  |  | return this.agvList; | 
|---|
|  |  |  | } | 
|---|
|  |  |  |  | 
|---|
|  |  |  | public void shutdownFakeThreads() { | 
|---|
|  |  |  | if (this.executorService != null && !this.executorService.isShutdown()) { | 
|---|
|  |  |  | this.executorService.shutdown(); | 
|---|
|  |  |  | try { | 
|---|
|  |  |  | if (!executorService.awaitTermination(60, TimeUnit.SECONDS)) { | 
|---|
|  |  |  | log.warn("ExecutorService did not terminate in the specified time."); | 
|---|
|  |  |  | executorService.shutdownNow(); | 
|---|
|  |  |  | if (!this.executorService.awaitTermination(60, TimeUnit.SECONDS)) { | 
|---|
|  |  |  | this.executorService.shutdownNow(); | 
|---|
|  |  |  | } | 
|---|
|  |  |  | } catch (InterruptedException e) { | 
|---|
|  |  |  | log.error("Interrupted while waiting for ExecutorService to terminate.", e); | 
|---|
|  |  |  | executorService.shutdownNow(); | 
|---|
|  |  |  | this.executorService.shutdownNow(); | 
|---|
|  |  |  | Thread.currentThread().interrupt(); | 
|---|
|  |  |  | } finally { | 
|---|
|  |  |  | this.executorService = null; | 
|---|
|  |  |  | } | 
|---|
|  |  |  | this.executorService = null; // 释放资源 | 
|---|
|  |  |  | } | 
|---|
|  |  |  | if (!Cools.isEmpty(this.agvList)) { | 
|---|
|  |  |  | agvList = new ArrayList<>(); | 
|---|
|  |  |  | } | 
|---|
|  |  |  | if (!AGV_PROCESSING_MAP.isEmpty()) { | 
|---|
|  |  |  | AGV_PROCESSING_MAP.clear(); | 
|---|
|  |  |  | } | 
|---|
|  |  |  | } | 
|---|
|  |  |  |  | 
|---|
|  |  |  | @PreDestroy | 
|---|
|  |  |  | public void shutDown(){ | 
|---|
|  |  |  | if (this.heartBeatThread != null) { | 
|---|
|  |  |  | this.heartBeatThread .interrupt(); | 
|---|
|  |  |  | } | 
|---|
|  |  |  | if (this.responseThread != null) { | 
|---|
|  |  |  | this.responseThread .interrupt(); | 
|---|
|  |  |  | } | 
|---|
|  |  |  | if (this.simulatorTread != null) { | 
|---|
|  |  |  | this.simulatorTread.interrupt(); | 
|---|
|  |  |  | } | 
|---|
|  |  |  | this.shutdownFakeThreads(); | 
|---|
|  |  |  | } | 
|---|
|  |  |  |  | 
|---|
|  |  |  | } | 
|---|