package com.shkpr.service.alambizplugin.components; import com.fasterxml.jackson.core.type.TypeReference; import com.global.base.log.LogLevelFlag; import com.global.base.log.LogPrintMgr; import com.shkpr.service.alambizplugin.apiparam.GisSurveyCheckParams; import com.shkpr.service.alambizplugin.components.checker.*; import com.shkpr.service.alambizplugin.constants.CommAsyncStatusEnum; import com.shkpr.service.alambizplugin.constants.GisSurveyCheckTypeEnum; import com.shkpr.service.alambizplugin.constants.GisSurveySystemCheckKeys; import com.shkpr.service.alambizplugin.constants.LogFlagBusiType; import com.shkpr.service.alambizplugin.dbdao.services.intef.GisSurveyLayerApplyService; import com.shkpr.service.alambizplugin.dbdao.services.intef.TypeDefineService; import com.shkpr.service.alambizplugin.dto.*; import lombok.extern.slf4j.Slf4j; import org.springframework.scheduling.annotation.Async; import org.springframework.scheduling.annotation.AsyncResult; import org.springframework.stereotype.Component; import org.springframework.util.concurrent.ListenableFuture; import java.nio.file.Files; import java.nio.file.Path; import java.time.Duration; import java.time.LocalDateTime; import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.Objects; import java.util.concurrent.ExecutionException; import java.util.function.Consumer; /** * 系统检查执行器 * * @author 欧阳劲驰 * @since 1.0.0 */ @Component @Slf4j public class GisSurveySystemChecker { /** * log */ private final String mStrClassName; private final String mBizType; private final AsyncResultManager asyncResultManager; private final GisSurveyLayerApplyService gisSurveyLayerApplyService; private final TypeDefineService typeDefineService; private final InvalidPointsFinder invalidPointsFinder; private final IsolatedPointsFinder isolatedPointsFinder; private final IsolatedLinesFinder isolatedLinesFinder; private final DuplicatePointsFinder duplicatePointsFinder; private final InvalidLinesFinder invalidLinesFinder; private final OverlapLinesFinder overlapLinesFinder; private final CrossLinesFinder crossLinesFinder; private final ElevationDiffFinder elevationDiffFinder; public GisSurveySystemChecker(AsyncResultManager asyncResultManager , GisSurveyLayerApplyService gisSurveyLayerApplyService, TypeDefineService typeDefineService , InvalidPointsFinder invalidPointsFinder, IsolatedPointsFinder isolatedPointsFinder , IsolatedLinesFinder isolatedLinesFinder, DuplicatePointsFinder duplicatePointsFinder , InvalidLinesFinder invalidLinesFinder, OverlapLinesFinder overlapLinesFinder , CrossLinesFinder crossLinesFinder, ElevationDiffFinder elevationDiffFinder) { mStrClassName = "GisSurveySystemChecker"; mBizType = LogFlagBusiType.BUSI_GIS_SURVEY.toStrValue(); this.asyncResultManager = asyncResultManager; this.gisSurveyLayerApplyService = gisSurveyLayerApplyService; this.typeDefineService = typeDefineService; this.invalidPointsFinder = invalidPointsFinder; this.isolatedPointsFinder = isolatedPointsFinder; this.isolatedLinesFinder = isolatedLinesFinder; this.duplicatePointsFinder = duplicatePointsFinder; this.invalidLinesFinder = invalidLinesFinder; this.overlapLinesFinder = overlapLinesFinder; this.crossLinesFinder = crossLinesFinder; this.elevationDiffFinder = elevationDiffFinder; } /** * 系统检查任务 * * @param params 系统检查参数 * @param systemCheckDefines 系统检查定义 * @param onStartSubtask 启动子任务 * @param onDeprecatedSubtask 弃用子任务(完成数据收集/取消) * @return 系统检查返回 */ @Async public ListenableFuture>> systemCheckTask( GisSurveyCheckParams params, List systemCheckDefines , Consumer>> onStartSubtask , Consumer onDeprecatedSubtask) { //系统检查id GisSurveySystemCheckId systemCheckId = GisSurveySystemCheckId.generateId(params); if (systemCheckId == null) return new AsyncResult<>(CommAsyncResult.fail(null)); //构建返回 CommAsyncResult> result = CommAsyncResult.fail(systemCheckId.toString()); result.setOperator(params.getOperator()); //无效点任务 ListenableFuture invalidPointsFuture = null; //孤立点任务 ListenableFuture isolatedPointsFuture = null; //孤立线任务 ListenableFuture isolatedLinesFuture = null; //重复点任务 ListenableFuture duplicatePointsFuture = null; //无效线任务 ListenableFuture invalidLinesFuture = null; //重叠线任务 ListenableFuture overlapLinesFuture = null; //交叉线任务 ListenableFuture crossLinesFuture = null; //高程差任务 ListenableFuture elevationDiffFuture = null; //点集合 List points = null; //线集合 List lines = null; LogPrintMgr.getInstance().printLogMsg(LogLevelFlag.LOG_INFO, mBizType, mStrClassName , String.format( "开始执行系统检查;检查类型 检查类型:%s code:%s" , systemCheckId.getCheckType().getFlag() , systemCheckId.getCode() ) ); try { //根据项目查询点线信息 if (GisSurveyCheckTypeEnum.PROJECT == systemCheckId.getCheckType()) { points = gisSurveyLayerApplyService.findAddPointByProjId(systemCheckId.getCode()); lines = gisSurveyLayerApplyService.findAddLineByProjId(systemCheckId.getCode()); } //根据任务查询点线信息 else if (GisSurveyCheckTypeEnum.JOB == systemCheckId.getCheckType()) { points = gisSurveyLayerApplyService.findAddPointByJobId(systemCheckId.getCode()); lines = gisSurveyLayerApplyService.findAddLineByJobId(systemCheckId.getCode()); } //查询经纬度类型定义 List typeDefines = typeDefineService.findLatLng(); //孤立点定义 GisSurveySystemCheckDefine isolatedPointsDefine = systemCheckDefines.stream(). filter(it -> Objects.equals(GisSurveySystemCheckKeys.ISOLATED_POINTS, it.getKey())) .findFirst().orElse(null); //无效线定义 GisSurveySystemCheckDefine invalidLinesDefine = systemCheckDefines.stream(). filter(it -> Objects.equals(GisSurveySystemCheckKeys.INVALID_LINES, it.getKey())) .findFirst().orElse(null); //重复点定义 GisSurveySystemCheckDefine duplicatePointsDefine = systemCheckDefines.stream(). filter(it -> Objects.equals(GisSurveySystemCheckKeys.DUPLICATE_POINTS, it.getKey())) .findFirst().orElse(null); //结果flag final String FLAG = systemCheckId.getFlag(); //创建临时文件夹 if (!asyncResultManager.createTempDirectory(FLAG)) return new AsyncResult<>(result); //子任务 HashMap> subtask = new HashMap<>(); //无效点检查 if (points != null) { if (params.getStartSubitemKeys().contains(GisSurveySystemCheckKeys.INVALID_POINTS)) { invalidPointsFuture = invalidPointsFinder.finderInvalidPoints(points, systemCheckId); subtask.put(GisSurveySystemCheckKeys.INVALID_POINTS, invalidPointsFuture); } } //孤立点检查 if (points != null && lines != null) { if (params.getStartSubitemKeys().contains(GisSurveySystemCheckKeys.ISOLATED_POINTS)) { isolatedPointsFuture = isolatedPointsFinder.findIsolatedPoints(points, lines, isolatedPointsDefine, systemCheckId); subtask.put(GisSurveySystemCheckKeys.ISOLATED_POINTS, isolatedPointsFuture); } } //无效线检查 if (points != null && lines != null) { if (params.getStartSubitemKeys().contains(GisSurveySystemCheckKeys.INVALID_LINES)) { invalidLinesFuture = invalidLinesFinder.finderInvalidLines(points, lines, invalidLinesDefine, systemCheckId); subtask.put(GisSurveySystemCheckKeys.INVALID_LINES, invalidLinesFuture); } } //重复点检查 if (points != null) { if (params.getStartSubitemKeys().contains(GisSurveySystemCheckKeys.DUPLICATE_POINTS)) { duplicatePointsFuture = duplicatePointsFinder.findDuplicatePoints(points, typeDefines, duplicatePointsDefine, systemCheckId); subtask.put(GisSurveySystemCheckKeys.DUPLICATE_POINTS, duplicatePointsFuture); } } if (lines != null) { //孤立线检查 if (params.getStartSubitemKeys().contains(GisSurveySystemCheckKeys.ISOLATED_LINES)) { isolatedLinesFuture = isolatedLinesFinder.findIsolatedLines(lines, systemCheckId); subtask.put(GisSurveySystemCheckKeys.ISOLATED_LINES, isolatedLinesFuture); } //重叠线检查 if (params.getStartSubitemKeys().contains(GisSurveySystemCheckKeys.OVERLAP_LINES)) { overlapLinesFuture = overlapLinesFinder.findOverlapLines(lines, systemCheckId); subtask.put(GisSurveySystemCheckKeys.OVERLAP_LINES, overlapLinesFuture); } //交叉线检查 if (params.getStartSubitemKeys().contains(GisSurveySystemCheckKeys.CROSS_LINES)) { crossLinesFuture = crossLinesFinder.findCrossLines(lines, systemCheckId); subtask.put(GisSurveySystemCheckKeys.CROSS_LINES, crossLinesFuture); } //高程差异常检查 if (params.getStartSubitemKeys().contains(GisSurveySystemCheckKeys.ELEVATION_DIFF)) { elevationDiffFuture = elevationDiffFinder.findElevationDiff(lines, systemCheckId); subtask.put(GisSurveySystemCheckKeys.ELEVATION_DIFF, elevationDiffFuture); } } //返回子任务 onStartSubtask.accept(subtask); //获取上次结果 CommAsyncResult> lastResult = asyncResultManager.getResult(FLAG, new TypeReference>>() { }); //设置数据 Map data = new HashMap<>(); if (lastResult != null && lastResult.getData() != null) data = lastResult.getData(); //设置数据时间 Map refreshTimes = new HashMap<>(); if (lastResult != null && lastResult.getRefreshTimes() != null) refreshTimes = lastResult.getRefreshTimes(); //等待结果,并存入返回,优先监听点相关(执行速度快且只需要点集合,优先释放点集合内存) if (invalidPointsFuture != null) { //监听无效点 final GisSurveySystemCheckResultDetail invalidPointsResult = invalidPointsFuture.get(); data.put(GisSurveySystemCheckKeys.INVALID_POINTS, invalidPointsResult); refreshTimes.put(GisSurveySystemCheckKeys.INVALID_POINTS, params.getRefreshTime()); //释放点缓存 clearPoints(points, invalidPointsFuture, isolatedPointsFuture, duplicatePointsFuture, invalidLinesFuture); } if (isolatedPointsFuture != null) { //监听孤立点 final GisSurveySystemCheckResultDetail isolatedPointsResult = isolatedPointsFuture.get(); data.put(GisSurveySystemCheckKeys.ISOLATED_POINTS, isolatedPointsResult); refreshTimes.put(GisSurveySystemCheckKeys.ISOLATED_POINTS, params.getRefreshTime()); //释放点缓存 clearPoints(points, invalidPointsFuture, isolatedPointsFuture, duplicatePointsFuture, invalidLinesFuture); } if (duplicatePointsFuture != null) { //监听重复点 final GisSurveySystemCheckResultDetail duplicatePointsResult = duplicatePointsFuture.get(); data.put(GisSurveySystemCheckKeys.DUPLICATE_POINTS, duplicatePointsResult); refreshTimes.put(GisSurveySystemCheckKeys.DUPLICATE_POINTS, params.getRefreshTime()); //释放点缓存 clearPoints(points, invalidPointsFuture, isolatedPointsFuture, duplicatePointsFuture, invalidLinesFuture); } if (isolatedLinesFuture != null) { //监听孤立线 final GisSurveySystemCheckResultDetail isolatedLinesResult = isolatedLinesFuture.get(); data.put(GisSurveySystemCheckKeys.ISOLATED_LINES, isolatedLinesResult); refreshTimes.put(GisSurveySystemCheckKeys.ISOLATED_LINES, params.getRefreshTime()); } if (invalidLinesFuture != null) { //监听无效线 final GisSurveySystemCheckResultDetail invalidLinesResult = invalidLinesFuture.get(); data.put(GisSurveySystemCheckKeys.INVALID_LINES, invalidLinesResult); refreshTimes.put(GisSurveySystemCheckKeys.INVALID_LINES, params.getRefreshTime()); //释放点缓存 clearPoints(points, invalidPointsFuture, isolatedPointsFuture, duplicatePointsFuture, invalidLinesFuture); } if (overlapLinesFuture != null) { //监听重叠线 final GisSurveySystemCheckResultDetail overlapLinesResult = overlapLinesFuture.get(); data.put(GisSurveySystemCheckKeys.OVERLAP_LINES, overlapLinesResult); refreshTimes.put(GisSurveySystemCheckKeys.OVERLAP_LINES, params.getRefreshTime()); } if (crossLinesFuture != null) { //监听交叉线 final GisSurveySystemCheckResultDetail crossLinesResult = crossLinesFuture.get(); data.put(GisSurveySystemCheckKeys.CROSS_LINES, crossLinesResult); refreshTimes.put(GisSurveySystemCheckKeys.CROSS_LINES, params.getRefreshTime()); } if (elevationDiffFuture != null) { //监听高程差异常 final GisSurveySystemCheckResultDetail elevationDiffResult = elevationDiffFuture.get(); data.put(GisSurveySystemCheckKeys.ELEVATION_DIFF, elevationDiffResult); refreshTimes.put(GisSurveySystemCheckKeys.ELEVATION_DIFF, params.getRefreshTime()); } //完成检查 result.setStatus(CommAsyncStatusEnum.SUCCESS.getCode()); result.setCompleteTime(LocalDateTime.now()); result.setData(data); result.setRefreshTimes(refreshTimes); result.setSubitemKeys(params.getSubitemKeys()); //写入结果 Path resultPath = asyncResultManager.writeJson(result, FLAG, AsyncResultManager.RESULT_FILE_NAME); if (resultPath == null || !Files.exists(resultPath)) { //弃用子任务 onDeprecatedSubtask.accept(systemCheckId); //打印报错信息 LogPrintMgr.getInstance().printLogMsg(LogLevelFlag.LOG_ERROR, mBizType, mStrClassName , String.format("第三方导出文件写入失败, 任务id:%s", systemCheckId) ); return new AsyncResult<>(CommAsyncResult.fail(systemCheckId.toString())); } //替换结果 if (!asyncResultManager.replaceResult(FLAG)) { //弃用子任务 onDeprecatedSubtask.accept(systemCheckId); return new AsyncResult<>(CommAsyncResult.fail(systemCheckId.toString())); } //弃用子任务 onDeprecatedSubtask.accept(systemCheckId); LogPrintMgr.getInstance().printLogMsg(LogLevelFlag.LOG_INFO, mBizType, mStrClassName , String.format( "结束执行系统检查;检查类型: %s, code:%s , 用时(毫秒):%d", systemCheckId.getCheckType().getFlag(), systemCheckId.getCode(), Duration.between(result.getRequestTime(), result.getCompleteTime()).toMillis() ) ); return new AsyncResult<>(result); } catch (InterruptedException | ExecutionException e) { LogPrintMgr.getInstance().printLogMsg(LogLevelFlag.LOG_ERROR, mBizType, mStrClassName , String.format( "监测到中断或执行异常,开始清除子任务 检查类型:%s, code:%s ,error:%s", systemCheckId.getCheckType().getFlag(), systemCheckId.getCode(), e ) ); log.error("StackTrac:", e); //清除子任务 if (invalidPointsFuture != null) invalidPointsFuture.cancel(true); if (isolatedPointsFuture != null) isolatedPointsFuture.cancel(true); if (isolatedLinesFuture != null) isolatedLinesFuture.cancel(true); if (duplicatePointsFuture != null) duplicatePointsFuture.cancel(true); if (invalidLinesFuture != null) invalidLinesFuture.cancel(true); if (overlapLinesFuture != null) overlapLinesFuture.cancel(true); if (crossLinesFuture != null) crossLinesFuture.cancel(true); if (elevationDiffFuture != null) elevationDiffFuture.cancel(true); //失败信息 result.setStatus(CommAsyncStatusEnum.FAIL.getCode()); result.setCompleteTime(LocalDateTime.now()); //弃用子任务 onDeprecatedSubtask.accept(systemCheckId); return new AsyncResult<>(result); } } /** * 清除点缓存 * * @param points 点集合 * @param invalidPointsFuture 无效点任务 * @param isolatedPointsFuture 孤立点任务 * @param duplicatePointsFuture 重复点任务 * @param invalidLinesFuture 无效线任务 */ public void clearPoints(List points , ListenableFuture invalidPointsFuture, ListenableFuture isolatedPointsFuture , ListenableFuture duplicatePointsFuture , ListenableFuture invalidLinesFuture) { //点相关任务都完成,则清除缓存 if (invalidPointsFuture != null && invalidPointsFuture.isDone() && isolatedPointsFuture != null && isolatedPointsFuture.isDone() && duplicatePointsFuture != null && duplicatePointsFuture.isDone() && invalidLinesFuture != null && invalidLinesFuture.isDone()) points.clear(); } }