Jelajahi Sumber

delete process package

HANTE 2 bulan lalu
induk
melakukan
10af2cb142
19 mengubah file dengan 796 tambahan dan 419 penghapusan
  1. 4 4
      utic-ptis-server/src/main/java/com/utic/ptis/server/UticPtisServerApplication.java
  2. 16 11
      utic-ptis-server/src/main/java/com/utic/ptis/server/controller/LinkTrafPrcsController.java
  3. 2 2
      utic-ptis-server/src/main/java/com/utic/ptis/server/controller/LinkTrafPrcsPrepareController.java
  4. 11 0
      utic-ptis-server/src/main/java/com/utic/ptis/server/dao/mapper/utic/DeleteMapper.java
  5. 65 32
      utic-ptis-server/src/main/java/com/utic/ptis/server/dto/LinkTrafFusionInfo.java
  6. 7 0
      utic-ptis-server/src/main/java/com/utic/ptis/server/dto/LinkTrafVal.java
  7. 0 107
      utic-ptis-server/src/main/java/com/utic/ptis/server/repository/ApplicationRepository.java
  8. 6 33
      utic-ptis-server/src/main/java/com/utic/ptis/server/repository/eTrafPrcsJob.java
  9. 3 0
      utic-ptis-server/src/main/java/com/utic/ptis/server/service/LinkRepositoryService.java
  10. 7 8
      utic-ptis-server/src/main/java/com/utic/ptis/server/service/LinkTrafCollectService.java
  11. 10 9
      utic-ptis-server/src/main/java/com/utic/ptis/server/service/LinkTrafCollectSetupService.java
  12. 87 0
      utic-ptis-server/src/main/java/com/utic/ptis/server/service/LinkTrafDeleteService.java
  13. 31 175
      utic-ptis-server/src/main/java/com/utic/ptis/server/service/LinkTrafFusionService.java
  14. 391 0
      utic-ptis-server/src/main/java/com/utic/ptis/server/service/LinkTrafMissingService.java
  15. 2 2
      utic-ptis-server/src/main/java/com/utic/ptis/server/service/LinkTrafPatternService.java
  16. 2 2
      utic-ptis-server/src/main/java/com/utic/ptis/server/service/LinkTrafPrcsTime.java
  17. 116 0
      utic-ptis-server/src/main/java/com/utic/ptis/server/service/worker/LinkTrafCollectWorker.java
  18. 18 34
      utic-ptis-server/src/main/java/com/utic/ptis/server/service/worker/LinkTrafDeleteWorker.java
  19. 18 0
      utic-ptis-server/src/main/resources/mybatis/mapper/utic/DeleteMapper.xml

+ 4 - 4
utic-ptis-server/src/main/java/com/utic/ptis/server/UticPtisServerApplication.java

@@ -3,10 +3,7 @@ package com.utic.ptis.server;
 import com.utic.common.spring.SpringUtils;
 import com.utic.ptis.server.config.ApplicationConfig;
 import com.utic.ptis.server.process.dbms.DbmsDataProcess;
-import com.utic.ptis.server.service.LinkRepositoryService;
-import com.utic.ptis.server.service.LinkTrafCollectService;
-import com.utic.ptis.server.service.LinkTrafFusionService;
-import com.utic.ptis.server.service.ProcessStateService;
+import com.utic.ptis.server.service.*;
 import lombok.extern.slf4j.Slf4j;
 import org.springframework.beans.factory.DisposableBean;
 import org.springframework.beans.factory.InitializingBean;
@@ -73,6 +70,9 @@ public class UticPtisServerApplication implements CommandLineRunner, Application
         LinkTrafFusionService linkTrafFusionService = SpringUtils.getBean(LinkTrafFusionService.class);
         linkTrafFusionService.processing();
 
+        LinkTrafMissingService linkTrafMissingervice = SpringUtils.getBean(LinkTrafMissingService.class);
+        linkTrafMissingervice.processing();
+
         applicationConfig.setStartSchedule(true);
 
         Runtime.getRuntime().addShutdownHook(new Thread(() -> {

+ 16 - 11
utic-ptis-server/src/main/java/com/utic/ptis/server/controller/LinkTrafPrcsController.java

@@ -1,9 +1,7 @@
 package com.utic.ptis.server.controller;
 
 import com.utic.common.utils.TimeUtils;
-import com.utic.ptis.server.service.LinkTrafCollectService;
-import com.utic.ptis.server.service.LinkTrafFusionService;
-import com.utic.ptis.server.service.TrafPrcsTime;
+import com.utic.ptis.server.service.*;
 import lombok.RequiredArgsConstructor;
 import lombok.extern.slf4j.Slf4j;
 import org.springframework.stereotype.Controller;
@@ -14,9 +12,11 @@ import org.springframework.util.StopWatch;
 @RequiredArgsConstructor
 public class LinkTrafPrcsController implements AbstractProcessController {
 
-    private final TrafPrcsTime prcsTime;
+    private final LinkTrafPrcsTime prcsTime;
+    private final LinkRepositoryService linkRepositoryService;
     private final LinkTrafCollectService trafCollectService;
-    private final LinkTrafFusionService trafProcessingService;
+    private final LinkTrafFusionService trafFusionService;
+    private final LinkTrafMissingService trafMissingService;
 
     private String statTime;
     private String fromTime;
@@ -29,7 +29,7 @@ public class LinkTrafPrcsController implements AbstractProcessController {
         this.fromTime = this.statTime;
         this.toTime = TimeUtils.getToTime(this.fromTime, TimeUtils.TYPE_PRCS_15MIN);
 
-        String funcName = String.format("%45s", "TrafPrcs05MController.initialize");
+        String funcName = String.format("%45s", "LinkTrafPrcsController.initialize");
         log.info("[SCHEDULING] {}: ..05M, {}, {}, {}, {}", funcName, currTime, this.statTime, this.fromTime, this.toTime);
 
         /*
@@ -38,6 +38,8 @@ public class LinkTrafPrcsController implements AbstractProcessController {
          */
         this.prcsTime.init();
 
+        this.linkRepositoryService.getFusionInfo().init();
+
         log.info("[PROCESSING]Current/Current_5M/Current_5M_Prcs: {}/{}/{}",    this.prcsTime.getCurrTime(),      this.prcsTime.getCurrFiveMin(),     this.prcsTime.getPrcsFiveMin());
         log.info("[PROCESSING]         Current_5M_Prcs/Start/End: {}/{}/{}",    this.prcsTime.getPrcsFiveMin(),   this.prcsTime.getPrcsFiveMinFrom(), this.prcsTime.getPrcsFiveMinTo());
         log.info("[PROCESSING]      Current_5M_Prcs/Week/Quarter: {}/{}/{}/{}", this.prcsTime.getPrcsFiveMin(),   this.prcsTime.getPrcsDayWeek(),     this.prcsTime.getPrcsDayQuater(),      this.prcsTime.getPrcsDayWeekCd());
@@ -55,8 +57,8 @@ public class LinkTrafPrcsController implements AbstractProcessController {
         }
 
         StopWatch stopWatch = new StopWatch();
-        stopWatch.start("TrafPrcs05MController");
-        log.info("[TRAFFIC---]                         TrafPrcs05MController: START.");
+        stopWatch.start("LinkTrafPrcsController");
+        log.info("[TRAFFIC---]                         LinkTrafPrcsController: START.");
 
         // 가공 시작
         this.prcsTime.setProcessing(true);
@@ -67,8 +69,11 @@ public class LinkTrafPrcsController implements AbstractProcessController {
         // 1. 수집원별 링크 원시 교통정보 조회
         this.trafCollectService.processing();
 
-        // 가공방식에 따른 퓨전 소통정보 생서
-        this.trafProcessingService.processing();
+        // 2. 가공방식에 따른 퓨전 소통정보 생서
+        this.trafFusionService.processing();
+
+        // 3. 결측처리
+        this.trafMissingService.processing();
 
 //        // 돌발발생구간 정보 로딩.
 //        this.incdOcrrService.load();
@@ -104,7 +109,7 @@ public class LinkTrafPrcsController implements AbstractProcessController {
 //        AppRepository.getInstance().endPrcsJob(eTrafPrcsJob.PRCS_05M_ALL, 0, true);
 
         stopWatch.stop();
-        log.info("[TRAFFIC---]                         TrafPrcs05MController: ..END. {} ms", stopWatch.getTotalTimeMillis());
+        log.info("[TRAFFIC---]                         LinkTrafPrcsController: ..END. {} ms", stopWatch.getTotalTimeMillis());
 
     }
 }

+ 2 - 2
utic-ptis-server/src/main/java/com/utic/ptis/server/controller/LinkTrafPrcsPrepareController.java

@@ -2,7 +2,7 @@ package com.utic.ptis.server.controller;
 
 import com.utic.ptis.server.service.LinkTrafParamService;
 import com.utic.ptis.server.service.LinkTrafPatternService;
-import com.utic.ptis.server.service.TrafPrcsTime;
+import com.utic.ptis.server.service.LinkTrafPrcsTime;
 import lombok.RequiredArgsConstructor;
 import lombok.extern.slf4j.Slf4j;
 import org.springframework.stereotype.Controller;
@@ -13,7 +13,7 @@ import org.springframework.util.StopWatch;
 @RequiredArgsConstructor
 public class LinkTrafPrcsPrepareController implements AbstractProcessController {
 
-    private final TrafPrcsTime prcsTime;
+    private final LinkTrafPrcsTime prcsTime;
     private final LinkTrafParamService linkTrafParamService;
     private final LinkTrafPatternService linkTrafPatternService;
 

+ 11 - 0
utic-ptis-server/src/main/java/com/utic/ptis/server/dao/mapper/utic/DeleteMapper.java

@@ -0,0 +1,11 @@
+package com.utic.ptis.server.dao.mapper.utic;
+
+import org.apache.ibatis.annotations.Mapper;
+
+@Mapper
+public interface DeleteMapper {
+
+    int deleteTrafficCenter();
+    int deleteTrafficCenterExt();
+
+}

+ 65 - 32
utic-ptis-server/src/main/java/com/utic/ptis/server/dto/LinkTrafFusionInfo.java

@@ -1,51 +1,84 @@
 package com.utic.ptis.server.dto;
 
-import lombok.AllArgsConstructor;
-import lombok.Builder;
 import lombok.Data;
-import lombok.NoArgsConstructor;
 
 import java.io.Serializable;
 
 @Data
-@Builder
-@NoArgsConstructor//(access = AccessLevel.PROTECTED)
-@AllArgsConstructor
 public class LinkTrafFusionInfo implements Serializable {
     private static final long serialVersionUID = 1L;
 
-    private int     prcsType;           /* 정보가공 유형(0:우선순위,1:가중치) */
-    private int     linkCnt;            /* 레벨1 링크 전체 갯수 */
+    private int prcsType;           /* 정보가공 유형(0:우선순위,1:가중치) */
+    private int linkCnt;            /* 레벨1 링크 전체 갯수 */
 
-    private int     colPtnCnt;          /* 패턴 갯수 */
+    private int colPtnCnt;          /* 패턴 갯수 */
 
-    private int     colOprCnt;          /* 운영자 입력 갯수 */
-    private int     colMoctCnt;         /* 민간정보 수집 갯수 */
-    private int     colGpsCnt;          /* GPS 수집 갯수 */
-    private int     colUtisCnt;         /* UTIS 수집 갯수 */
-    private int     colPriCnt;          /* 우선순위 수집 갯수 */
-    private int     colPriEtcCnt;       /* 우선순위 기타 수집 갯수 */
-    private int     colDongbuCnt;       /* 동부NTS 수집 갯수 */
+    private int colOprCnt;          /* 운영자 입력 갯수 */
+    private int colMoctCnt;         /* 민간정보 수집 갯수 */
+    private int colGpsCnt;          /* GPS 수집 갯수 */
+    private int colUtisCnt;         /* UTIS 수집 갯수 */
+    private int colPriCnt;          /* 우선순위 수집 갯수 */
+    private int colPriEtcCnt;       /* 우선순위 기타 수집 갯수 */
+    private int colDongbuCnt;       /* 동부NTS 수집 갯수 */
 
-    private int     fsnOprCnt;          /* 운영자 입력 퓨전 갯수 */
-    private int     fsnPriCnt;          /* 우선순위 퓨전 갯수 */
-    private int     fsnWgtCnt;          /* 가중치 퓨전 갯수 */
+    private int fsnOprCnt;          /* 운영자 입력 퓨전 갯수 */
+    private int fsnPriCnt;          /* 우선순위 퓨전 갯수 */
+    private int fsnWgtCnt;          /* 가중치 퓨전 갯수 */
 
-    private int     fltSpdCnt;          /* 속도상한값 보정 갯수 */
+    private int fltSpdCnt;          /* 속도상한값 보정 갯수 */
 
-    private int     psdUpCnt;           /* PSD 상류부 결측 */
-    private int     psdDnCnt;           /* PSD 하류부 결측 */
-    private int     psdUpDnCnt;         /* PSD 상하류부 결측 */
-    private int     psdLv4Cnt;          /* PSD 상위4레벨 이용한 결측 */
+    private int psdUpCnt;           /* PSD 상류부 결측 */
+    private int psdDnCnt;           /* PSD 하류부 결측 */
+    private int psdUpDnCnt;         /* PSD 상하류부 결측 */
+    private int psdLv4Cnt;          /* PSD 상위4레벨 이용한 결측 */
 
-    private int     knnCnt;             /* KNN 결측 갯수 */
+    private int knnCnt;             /* KNN 결측 갯수 */
 
-    private int     realFsnCnt;         /* 수집/운영자 퓨전 - fsnOprCnt+fsnPriCnt+fsnWgtCnt */
-    private int     missPsdCnt;         /* PSD 결측 퓨전 */
-    private int     missKnnCnt;         /* KNN 결측 퓨전 */
-    private int     missPtnCnt;         /* 패턴 결측 퓨전 */
-    private int     missGgCnt;          /* 경기도 구간 결측 퓨전 */
-    private int     missMoctCnt;        /* 국토부 민간정보 결측 퓨전 */
-    private int     zeroSpdCnt;         /* 최종 속도정보가 0인 갯수 */
+    private int realFsnCnt;         /* 수집/운영자 퓨전 - fsnOprCnt+fsnPriCnt+fsnWgtCnt */
+    private int missPsdCnt;         /* PSD 결측 퓨전 */
+    private int missKnnCnt;         /* KNN 결측 퓨전 */
+    private int missPtnCnt;         /* 패턴 결측 퓨전 */
+    private int missGgCnt;          /* 경기도 구간 결측 퓨전 */
+    private int missMoctCnt;        /* 국토부 민간정보 결측 퓨전 */
+    private int zeroSpdCnt;         /* 최종 속도정보가 0인 갯수 */
 
+    public LinkTrafFusionInfo() {
+        init();
+    }
+
+    public void init() {
+        this.prcsType = 0;
+        this.linkCnt = 0;
+
+        this.colPtnCnt = 0;
+
+        this.colOprCnt = 0;
+        this.colMoctCnt = 0;
+        this.colGpsCnt = 0;
+        this.colUtisCnt = 0;
+        this.colPriCnt = 0;
+        this.colPriEtcCnt = 0;
+        this.colDongbuCnt = 0;
+
+        this.fsnOprCnt = 0;
+        this.fsnPriCnt = 0;
+        this.fsnWgtCnt = 0;
+
+        this.fltSpdCnt = 0;
+
+        this.psdUpCnt = 0;
+        this.psdDnCnt = 0;
+        this.psdUpDnCnt = 0;
+        this.psdLv4Cnt = 0;
+
+        this.knnCnt = 0;
+
+        this.realFsnCnt = 0;
+        this.missPsdCnt = 0;
+        this.missKnnCnt = 0;
+        this.missPtnCnt = 0;
+        this.missGgCnt = 0;
+        this.missMoctCnt = 0;
+        this.zeroSpdCnt = 0;
+    }
 }

+ 7 - 0
utic-ptis-server/src/main/java/com/utic/ptis/server/dto/LinkTrafVal.java

@@ -28,6 +28,13 @@ public class LinkTrafVal implements Serializable {
         this.travelTime = 0;
     }
 
+    public void copy(LinkTrafVal val) {
+        this.state.copy(val.getState());
+        this.centerId = val.getCenterId();
+        this.speed = val.getSpeed();
+        this.travelTime = val.getTravelTime();
+    }
+
     public void setTraffic(LinkCollectDto traffic) {
         this.centerId = traffic.getCenterId();
         this.speed = traffic.getSpeed();

+ 0 - 107
utic-ptis-server/src/main/java/com/utic/ptis/server/repository/ApplicationRepository.java

@@ -1,8 +1,6 @@
 package com.utic.ptis.server.repository;
 
 import com.utic.common.dto.ProcessStateDto;
-import com.utic.common.utils.Elapsed;
-import com.utic.ptis.server.process.dbms.DbmsDataProcess;
 import lombok.Getter;
 import lombok.RequiredArgsConstructor;
 import lombok.extern.slf4j.Slf4j;
@@ -30,121 +28,16 @@ public class ApplicationRepository {
             .errTimeGap(120)
             .build();
 
-    private final DbmsDataProcess dbmsDataProcess;
-
     @PostConstruct
     private void init() {
         log.info("ApplicationRepository.init: Start.");
         log.info("ApplicationRepository.init: ..End.");
     }
 
-    private void initCenterMap() {
-//        try {
-//            for (Map.Entry<String, RegionCenter> e : this.centerMap.entrySet()) {
-//                RegionCenter obj = e.getValue();
-//                obj.setDeleted(true);
-//            }
-//        }
-//        catch (Exception e) {
-//            log.error("ApplicationRepository.initCenterMap: Exception: {}.", e.toString());
-//        }
-    }
-    private void initIntMap() {
-//        try {
-//            for (Map.Entry<String, RegionCenter> e : this.centerMap.entrySet()) {
-//                for (Map.Entry<Integer, IntDto> ee : e.getValue().getIntMap().entrySet()) {
-//                    IntDto intDto = ee.getValue();
-//                    intDto.setDeleted(true);
-//                }
-//            }
-//        }
-//        catch (Exception e) {
-//            log.error("ApplicationRepository.initIntMap: Exception: {}.", e.toString());
-//        }
-    }
-    private void loadCenterInfo() {
-        Elapsed elapsed = new Elapsed();
-        initCenterMap();
-
-        try {
-//            List<TbRegionCenter> lists  = this.mapper.selectAll();
-//            log.info("ApplicationRepository.loadCenterInfo: {} EA", lists.size());
-//            for (TbRegionCenter entity : lists) {
-//                log.info("ApplicationRepository.loadCenterInfo: {}.", entity);
-//                RegionCenter dto = entity.toDto();
-//                RegionCenter center = this.centerMap.get(dto.getRegionCd());
-//                if (center != null) {
-//                    String oldIpAddress = center.getIpAddress();
-//                    center.setDeleted(false);
-//                    center.update(dto);
-//                    if (!center.getIpAddress().equals(oldIpAddress)) {
-//                        this.ipAddrMap.remove(oldIpAddress);
-//                        this.ipAddrMap.put(center.getIpAddress(), center);
-//                    }
-//                }
-//                else {
-//                    this.centerMap.put(dto.getRegionCd(), dto);
-//                    this.ipAddrMap.put(dto.getIpAddress(), dto);
-//                }
-//            }
-        }
-        catch (Exception e) {
-            log.error("ApplicationRepository.loadCenterInfo: {}.", e.toString());
-        }
-        log.info("ApplicationRepository.loadCenterInfo: {} ms.", elapsed.milliSeconds());
-    }
-    private void loadIntInfo() {
-        Elapsed elapsed = new Elapsed();
-        initIntMap();
-
-
-        log.info("ApplicationRepository.loadIntInfo: {} ms.", elapsed.milliSeconds());
-    }
-//    public void updateRegionCenterStts(RegionCenter AObj, boolean isRun) {
-//        if (isRun) {
-//            TbRegionCenterComm stts = TbRegionCenterComm.builder()
-//                    .regionCd(AObj.getRegionCd())
-//                    .commState(TbRegionCenterComm.CENTER_COMM_START)
-//                    .build();
-//            this.mapper.updateCommStateConnect(stts);
-//        }
-//        else {
-//            TbRegionCenterComm stts = TbRegionCenterComm.builder()
-//                    .regionCd(AObj.getRegionCd())
-//                    .commState(TbRegionCenterComm.CENTER_COMM_STOP)
-//                    .build();
-//            this.mapper.updateCommStateDisconnect(stts);
-//        }
-//    }
-
     @PreDestroy
     public void destroyService() {
         log.error("ApplicationRepository.destroy. system terminated.......");
 
     }
 
-    public void reportChannelSessions() {
-        log.info("++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++");
-        //log.info("Report Region Center Channel Sessions Information.");
-        log.info("Center Name       IpAddress       Connect_Count   Connect_Time          Disconnect_Time       Remote_Address");
-        log.info("----------------------------------------------------------------------------------------------------------------");
-//        List<String> keySet = new ArrayList<>(this.centerMap.keySet());
-//        Collections.sort(keySet);
-        //this.centerMap.forEach((key, center) -> {
-//        for (String key : keySet) {
-//            RegionCenter center = this.centerMap.get(key);
-//            String channelIpAddress = center.getNetState().isActive() ? NettyUtils.getRemoteAddress(center.getNetState().getChannel()) : "---";
-//            log.info("{}", String.format("%-6s %-9s %-15s %-7s %5d   %s   %s   %s",
-//                    center.getRegionCd(),
-//                    center.getRegionNm(),
-//                    center.getIpAddress(),
-//                    center.getNetState().isActive(),
-//                    center.getNetState().getConnectCount(),
-//                    center.getNetState().getConnectTimeString(),
-//                    center.getNetState().getDisconnectTimeString(),
-//                    channelIpAddress));
-//        }
-        log.info("++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++");
-    }
-
 }

+ 6 - 33
utic-ptis-server/src/main/java/com/utic/ptis/server/repository/eTrafPrcsJob.java

@@ -1,43 +1,16 @@
 package com.utic.ptis.server.repository;
 
 public enum eTrafPrcsJob {
-    PRCS_05M_ALL("교통정보가공", "ALL"),
-
-    LOAD_PARAMETER("기초정보로딩-파리미터", "CLCT_SYST_STUP,HLDY_INFR,SECT_GRAD,VMS_IFSC_CMTR_GRAD,LINK_PARA_STUP"),
-    LOAD_BASEDATA("기초정보로딩-기본정보", "LINK,IFSC,ROAD,VMS_IFSC,EQTY_SECT,INCD_RSTR_SECT"),
-    LOAD_PATTERN("기초정보로딩-패턴정보", "LINK05,IFSC05,ROAD05,LINK15,IFSC15,ROAD15"),
-    LOAD_ALL("기초정보로딩", "ALL"),
-
-    PRCS_LOAD_INCD("소통정보수집-돌발", "INCD_OCRR,INCD_RSTR_SECT"),
-
     ///////////////////////////////////////////////////////////////////////////////////////////
 
-    PRCS_LOAD_RAW_OPER("소통정보수집-운영자", "LINK_SYOP_TRAF,IFSC_RLTN_LINK"),
-    PRCS_LOAD_RAW_UTIS("소통정보수집-UTIS", "VDS_DTCT_CLCT,VDS_DTCT_RLTN_LINK,VDS_DTCT"),
-    PRCS_LOAD_RAW_PRIO("소통정보수집-우선순위", "RSE_SECT_RLTN_LINK,RSE_SECT_TRAF"),
-    PRCS_LOAD_RAW_PRIOETC("소통정보수집-우선순위(ETC)", "EI_LINK_CUR,LINK"),
-    PRCS_LOAD_RAW_DONGBU("소통정보수집-동부NTS", "TRAFFIC_MOCT,LINK"),
-    PRCS_LOAD_RAW_MOCT("소통정보수집-국토부민간", "TRAFFIC_MOCT,LINK"),
-    PRCS_LOAD_RAW_ALL("소통정보수집", "ALL"),
+    PRCS_LOAD_RAW_OPER("소통정보수집-운영자", "소통정보수집-운영자"),
+    PRCS_LOAD_RAW_UTIS("소통정보수집-UTIS", "소통정보수집-UTIS"),
+    PRCS_LOAD_RAW_PRIO("소통정보수집-우선순위", "소통정보수집-우선순위"),
+    PRCS_LOAD_RAW_PRIOETC("소통정보수집-우선순위(ETC)", "소통정보수집-우선순위(ETC)"),
+    PRCS_LOAD_RAW_DONGBU("소통정보수집-동부NTS", "소통정보수집-동부NTS"),
+    PRCS_LOAD_RAW_MOCT("소통정보수집-국토부민간", "소통정보수집-국토부민간");
     ///////////////////////////////////////////////////////////////////////////////////////////
 
-    PRCS_LINK_TRAF("소통정보가공-LINK-TRAF", "LINK_TRAF"),
-    PRCS_LINK_TRAF_HS("소통정보가공-LINK-TRAF-HS", "LINK_TRAF_HS"),
-    PRCS_IFSC_TRAF("소통정보가공-IFSC-TRAF", "IFSC_TRAF"),
-    PRCS_IFSC_TRAF_HS("소통정보가공-IFSC-TRAF-HS", "IFSC_TRAF_HS"),
-    PRCS_ROAD_TRAF("소통정보가공-ROAD-TRAF", "ROAD_TRAF"),
-    PRCS_ROAD_TRAF_HS("소통정보가공-ROAD-TRAF-HS", "ROAD_TRAF_HS"),
-    PRCS_VMS_TRAF("소통정보가공-VMS-TRAF", "VMS_TRAF"),
-    PRCS_VMS_TRAF_HS("소통정보가공-VMS-TRAF-HS", "VMS_TRAF_HS"),
-
-    PRCS_PTRN_LINK_05M("패턴정보생성-LINK-05M", "LINK_PTRN_5M"),
-    PRCS_PTRN_IFSC_05M("패턴정보생성-IFSC-05M", "IFSC_PTRN_5M"),
-    PRCS_PTRN_ROAD_05M("패턴정보생성-ROAD-05M", "ROAD_PTRN_5M"),
-
-    PRCS_PTRN_LINK_15M("패턴정보생성-LINK-15M", "LINK_PTRN_15M"),
-    PRCS_PTRN_IFSC_15M("패턴정보생성-IFSC-15M", "IFSC_PTRN_15M"),
-    PRCS_PTRN_ROAD_15M("패턴정보생성-ROAD-15M", "ROAD_PTRN_15M");
-
     private String name;
     private String desc;
 

+ 3 - 0
utic-ptis-server/src/main/java/com/utic/ptis/server/service/LinkRepositoryService.java

@@ -6,6 +6,7 @@ import com.utic.ptis.server.dao.mapper.dwdb.DwdbParamMapper;
 import com.utic.ptis.server.dao.mapper.utic.LinkMapper;
 import com.utic.ptis.server.dto.LinkCountDto;
 import com.utic.ptis.server.dto.LinkDto;
+import com.utic.ptis.server.dto.LinkTrafFusionInfo;
 import com.utic.ptis.server.dto.LogicalLinkDto;
 import com.utic.ptis.server.repository.ApplicationRepository;
 import lombok.Getter;
@@ -41,6 +42,8 @@ public class LinkRepositoryService implements AbstractProcessService {
     private final ConcurrentHashMap<String, LinkDto> level3Map = new ConcurrentHashMap<>();
     private final ConcurrentHashMap<String, LinkDto> level4Map = new ConcurrentHashMap<>();
 
+    private final LinkTrafFusionInfo fusionInfo = new LinkTrafFusionInfo();
+
     public LinkDto getLink(String linkId) {
         return this.linkMap.get(linkId);
     }

+ 7 - 8
utic-ptis-server/src/main/java/com/utic/ptis/server/service/LinkTrafCollectService.java

@@ -4,8 +4,7 @@ import com.utic.common.utils.Elapsed;
 import com.utic.ptis.server.dto.LinkCollectParam;
 import com.utic.ptis.server.dto.LinkCollectResultDto;
 import com.utic.ptis.server.dto.LinkCollectSetupDto;
-import com.utic.ptis.server.service.collect.LinkCollectSetupService;
-import com.utic.ptis.server.service.collect.LinkCollectWorker;
+import com.utic.ptis.server.service.worker.LinkTrafCollectWorker;
 import lombok.Data;
 import lombok.RequiredArgsConstructor;
 import lombok.ToString;
@@ -24,8 +23,9 @@ import java.util.concurrent.TimeUnit;
 @Service
 public class LinkTrafCollectService implements AbstractProcessService {
 
-    private final TrafPrcsTime prcsTime;
-    private final LinkCollectSetupService collectSetupService;
+    private final LinkTrafPrcsTime prcsTime;
+    private final LinkRepositoryService linkRepositoryService;
+    private final LinkTrafCollectSetupService collectSetupService;
 
     private ConcurrentHashMap<String, LinkCollectResultDto> mapData = new ConcurrentHashMap<>();
 
@@ -51,14 +51,13 @@ public class LinkTrafCollectService implements AbstractProcessService {
             return 0;
         }
 
-        this.prcsTime.setCurrFiveMin("20250429150000");
         LinkCollectParam collectParam = LinkCollectParam.builder()
                 .ansTime(this.prcsTime.getCurrFiveMin())
                 .build();
 
         ExecutorService executorService = Executors.newFixedThreadPool(clctSystCnt);
         for (String clctSystCode: this.collectSetupService.keySet()) {
-            executorService.execute(new LinkCollectWorker(clctSystCode, collectParam, this.mapData));
+            executorService.execute(new LinkTrafCollectWorker(clctSystCode, collectParam, this.mapData, this.collectSetupService));
         }
 
         try {
@@ -67,7 +66,7 @@ public class LinkTrafCollectService implements AbstractProcessService {
                 executorService.shutdownNow();
             }
         } catch (InterruptedException e) {
-            log.error("[COLLECT] LinkTrafCollectService.LinkCollectService: LinkCollectWorker InterruptedException, {}", e.getMessage());
+            log.error("[COLLECT] LinkTrafCollectService.processing: LinkCollectWorker InterruptedException, {}", e.getMessage());
             executorService.shutdownNow();
         }
 
@@ -79,7 +78,7 @@ public class LinkTrafCollectService implements AbstractProcessService {
             if (collect != null) {
                 systStup.setClctNum(collect.getLists().size());
             }
-            log.info("[COLLECT] LinkTrafCollectService.LinkCollectService:collect: [{}] {}, [{}] EA.", clctSystCode, systStup.getClctSystNm(), systStup.getClctNum());
+            log.info("[COLLECT] LinkTrafCollectService.processing: [{}] {}, [{}] EA.", clctSystCode, systStup.getClctSystNm(), systStup.getClctNum());
         }
         log.info("[COLLECT] LinkTrafCollectService.processing: end. {}", Elapsed.elapsedStr(elapsed.nanoSeconds()));
         return this.mapData.size();

+ 10 - 9
utic-ptis-server/src/main/java/com/utic/ptis/server/service/collect/LinkCollectSetupService.java → utic-ptis-server/src/main/java/com/utic/ptis/server/service/LinkTrafCollectSetupService.java

@@ -1,4 +1,4 @@
-package com.utic.ptis.server.service.collect;
+package com.utic.ptis.server.service;
 
 import com.utic.ptis.server.dto.LinkCollectSetupDto;
 import lombok.RequiredArgsConstructor;
@@ -12,7 +12,7 @@ import java.util.concurrent.ConcurrentHashMap;
 @Slf4j
 @RequiredArgsConstructor
 @Service
-public class LinkCollectSetupService {
+public class LinkTrafCollectSetupService {
 
     public static final String OPER = "OPER";
     public static final String UTIS = "UTIS";
@@ -26,7 +26,7 @@ public class LinkCollectSetupService {
     @PostConstruct
     private void init() {
         load();
-        log.info("[LinkCollectSetupService] init: {}", mapData);
+        log.info("[LinkTrafCollectSetupService] init: {}", mapData);
     }
 
     public int count() {
@@ -41,12 +41,12 @@ public class LinkCollectSetupService {
     }
 
     public int load() {
-        LinkCollectSetupDto oper = LinkCollectSetupDto.builder().clctSystCd(OPER).clctSystNm("운영자 소통정보").build();
-        LinkCollectSetupDto utis = LinkCollectSetupDto.builder().clctSystCd(UTIS).clctSystNm("UTIS 소통정보").build();
-        LinkCollectSetupDto prio = LinkCollectSetupDto.builder().clctSystCd(PRIO).clctSystNm("우선순위 소통정보").build();
-        LinkCollectSetupDto prioEtc = LinkCollectSetupDto.builder().clctSystCd(PRIOETC).clctSystNm("(ETC)우선순위 소통정보").build();
-        LinkCollectSetupDto dongbu = LinkCollectSetupDto.builder().clctSystCd(DONGBU).clctSystNm("동부NTS 소통정보").build();
-        LinkCollectSetupDto moct = LinkCollectSetupDto.builder().clctSystCd(MOCT).clctSystNm("국토부민간 소통정보").build();
+        LinkCollectSetupDto oper    =    LinkCollectSetupDto.builder().clctSystCd(OPER).clctSystNm(" (SEL)           운영자입력 소통정보").build();
+        LinkCollectSetupDto utis    =    LinkCollectSetupDto.builder().clctSystCd(UTIS).clctSystNm(" (SEL)                 UTIS 소통정보").build();
+        LinkCollectSetupDto prio    =    LinkCollectSetupDto.builder().clctSystCd(PRIO).clctSystNm(" (SEL)             우선순위 소통정보").build();
+        LinkCollectSetupDto prioEtc = LinkCollectSetupDto.builder().clctSystCd(PRIOETC).clctSystNm(" (SEL)        (ETC)우선순위 소통정보").build();
+        LinkCollectSetupDto dongbu  =  LinkCollectSetupDto.builder().clctSystCd(DONGBU).clctSystNm(" (SEL)              동부NTS 소통정보").build();
+        LinkCollectSetupDto moct    =    LinkCollectSetupDto.builder().clctSystCd(MOCT).clctSystNm(" (SEL)           국토부민간 소통정보").build();
 
         oper.init();
         utis.init();
@@ -54,6 +54,7 @@ public class LinkCollectSetupService {
         prioEtc.init();
         dongbu.init();
         moct.init();
+
         mapData.put(oper.getClctSystCd(), oper);
         mapData.put(utis.getClctSystCd(), utis);
         mapData.put(prio.getClctSystCd(), prio);

+ 87 - 0
utic-ptis-server/src/main/java/com/utic/ptis/server/service/LinkTrafDeleteService.java

@@ -0,0 +1,87 @@
+package com.utic.ptis.server.service;
+
+import com.utic.common.utils.Elapsed;
+import com.utic.ptis.server.dto.LinkCollectParam;
+import com.utic.ptis.server.dto.LinkCollectResultDto;
+import com.utic.ptis.server.dto.LinkCollectSetupDto;
+import com.utic.ptis.server.service.worker.LinkTrafCollectWorker;
+import lombok.Data;
+import lombok.RequiredArgsConstructor;
+import lombok.ToString;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.stereotype.Service;
+
+import java.util.concurrent.ConcurrentHashMap;
+import java.util.concurrent.ExecutorService;
+import java.util.concurrent.Executors;
+import java.util.concurrent.TimeUnit;
+
+@Slf4j
+@Data
+@ToString
+@RequiredArgsConstructor
+@Service
+public class LinkTrafDeleteService implements AbstractProcessService {
+
+    private final LinkTrafPrcsTime prcsTime;
+    private final LinkTrafCollectSetupService collectSetupService;
+
+    private ConcurrentHashMap<String, LinkCollectResultDto> mapData = new ConcurrentHashMap<>();
+
+    public LinkCollectResultDto get(String key) {
+        return this.mapData.get(key);
+    }
+
+    public void init() {
+        for (String id: this.mapData.keySet()) {
+            this.mapData.get(id).getLists().clear();
+        }
+        this.mapData.clear();
+    }
+
+    public int processing() {
+        log.info("[DELETE.] LinkTrafDeleteService.processing: start.");
+        Elapsed elapsed = new Elapsed();
+        init();
+
+        int clctSystCnt = this.collectSetupService.count();
+        if (clctSystCnt <= 0) {
+            log.error("[DELETE.] LinkTrafDeleteService.processing: system no collect bean.");
+            return 0;
+        }
+
+        this.prcsTime.setCurrFiveMin("20250429150000");
+        LinkCollectParam collectParam = LinkCollectParam.builder()
+                .ansTime(this.prcsTime.getCurrFiveMin())
+                .build();
+
+        ExecutorService executorService = Executors.newFixedThreadPool(clctSystCnt);
+        for (String clctSystCode: this.collectSetupService.keySet()) {
+            executorService.execute(new LinkTrafCollectWorker(clctSystCode, collectParam, this.mapData, this.collectSetupService));
+        }
+
+        try {
+            executorService.shutdown();
+            if (!executorService.awaitTermination(100, TimeUnit.SECONDS)) {
+                executorService.shutdownNow();
+            }
+        } catch (InterruptedException e) {
+            log.error("[DELETE.] LinkTrafDeleteService.processing: LinkCollectWorker InterruptedException, {}", e.getMessage());
+            executorService.shutdownNow();
+        }
+
+        // 수집원 별 수집 데이터 건수 설정
+        for (String clctSystCode: this.collectSetupService.keySet()) {
+            LinkCollectSetupDto systStup = this.collectSetupService.get(clctSystCode);
+            systStup.setClctNum(0);
+            LinkCollectResultDto collect = this.mapData.get(clctSystCode);
+            if (collect != null) {
+                systStup.setClctNum(collect.getLists().size());
+            }
+            log.info("[DELETE.] LinkTrafDeleteService.processing: [{}] {}, [{}] EA.", clctSystCode, systStup.getClctSystNm(), systStup.getClctNum());
+        }
+        log.info("[DELETE.] LinkTrafDeleteService.processing: end. {}", Elapsed.elapsedStr(elapsed.nanoSeconds()));
+        return this.mapData.size();
+    }
+
+}

+ 31 - 175
utic-ptis-server/src/main/java/com/utic/ptis/server/service/LinkTrafFusionService.java

@@ -7,7 +7,6 @@ import com.utic.ptis.server.dto.LinkDto;
 import com.utic.ptis.server.dto.dwdb.ParamAnalysisType;
 import com.utic.ptis.server.dto.utic.TrafficGrade;
 import com.utic.ptis.server.dto.utic.TrafficWeight;
-import com.utic.ptis.server.service.collect.LinkCollectSetupService;
 import lombok.Getter;
 import lombok.RequiredArgsConstructor;
 import lombok.extern.slf4j.Slf4j;
@@ -26,7 +25,7 @@ import java.util.stream.Collectors;
 @Service
 public class LinkTrafFusionService implements AbstractProcessService {
 
-    private final LinkRepositoryService linkRepo;
+    private final LinkRepositoryService linkRepositoryService;
     private final LinkTrafParamService trafParamService;
     private final LinkTrafCollectService collectService;
 
@@ -42,24 +41,25 @@ public class LinkTrafFusionService implements AbstractProcessService {
         Elapsed elapsed = new Elapsed();
 
         // 0. 링크 소통정보를 초기화 한다.
-        this.linkRepo.initLinkTraf(true);
+        this.linkRepositoryService.initLinkTraf(true);
 
         // 1. 수집된 소통정보를 객체로 초기화 한다.
-        this.collectOPER = Optional.ofNullable(this.collectService.get(LinkCollectSetupService.OPER))
-                .orElseGet(() -> LinkCollectResultDto.builder().clctSystCd(LinkCollectSetupService.OPER).lists(new ArrayList<>()).build());
-        this.collectUTIS = Optional.ofNullable(this.collectService.get(LinkCollectSetupService.UTIS))
-                .orElseGet(() -> LinkCollectResultDto.builder().clctSystCd(LinkCollectSetupService.UTIS).lists(new ArrayList<>()).build());
-        this.collectPRIO = Optional.ofNullable(this.collectService.get(LinkCollectSetupService.PRIO))
-                .orElseGet(() -> LinkCollectResultDto.builder().clctSystCd(LinkCollectSetupService.PRIO).lists(new ArrayList<>()).build());
-        this.collectPRIOETC = Optional.ofNullable(this.collectService.get(LinkCollectSetupService.PRIOETC))
-                .orElseGet(() -> LinkCollectResultDto.builder().clctSystCd(LinkCollectSetupService.PRIOETC).lists(new ArrayList<>()).build());
-        this.collectDONGBU = Optional.ofNullable(this.collectService.get(LinkCollectSetupService.DONGBU))
-                .orElseGet(() -> LinkCollectResultDto.builder().clctSystCd(LinkCollectSetupService.DONGBU).lists(new ArrayList<>()).build());
-        this.collectMOCT = Optional.ofNullable(this.collectService.get(LinkCollectSetupService.MOCT))
-                .orElseGet(() -> LinkCollectResultDto.builder().clctSystCd(LinkCollectSetupService.MOCT).lists(new ArrayList<>()).build());
+        this.collectOPER = Optional.ofNullable(this.collectService.get(LinkTrafCollectSetupService.OPER))
+                .orElseGet(() -> LinkCollectResultDto.builder().clctSystCd(LinkTrafCollectSetupService.OPER).lists(new ArrayList<>()).build());
+        this.collectUTIS = Optional.ofNullable(this.collectService.get(LinkTrafCollectSetupService.UTIS))
+                .orElseGet(() -> LinkCollectResultDto.builder().clctSystCd(LinkTrafCollectSetupService.UTIS).lists(new ArrayList<>()).build());
+        this.collectPRIO = Optional.ofNullable(this.collectService.get(LinkTrafCollectSetupService.PRIO))
+                .orElseGet(() -> LinkCollectResultDto.builder().clctSystCd(LinkTrafCollectSetupService.PRIO).lists(new ArrayList<>()).build());
+        this.collectPRIOETC = Optional.ofNullable(this.collectService.get(LinkTrafCollectSetupService.PRIOETC))
+                .orElseGet(() -> LinkCollectResultDto.builder().clctSystCd(LinkTrafCollectSetupService.PRIOETC).lists(new ArrayList<>()).build());
+        this.collectDONGBU = Optional.ofNullable(this.collectService.get(LinkTrafCollectSetupService.DONGBU))
+                .orElseGet(() -> LinkCollectResultDto.builder().clctSystCd(LinkTrafCollectSetupService.DONGBU).lists(new ArrayList<>()).build());
+        this.collectMOCT = Optional.ofNullable(this.collectService.get(LinkTrafCollectSetupService.MOCT))
+                .orElseGet(() -> LinkCollectResultDto.builder().clctSystCd(LinkTrafCollectSetupService.MOCT).lists(new ArrayList<>()).build());
 
         log.info("[FUSION.] LinkTrafFusionService.initialize: ..end. {}", Elapsed.elapsedStr(elapsed.nanoSeconds()));
     }
+
     public int processing() {
         log.info("[FUSION.] LinkTrafFusionService.processing: start.");
         Elapsed elapsed = new Elapsed();
@@ -86,160 +86,16 @@ public class LinkTrafFusionService implements AbstractProcessService {
         // 4. 소통정보 보정(속도, 통행시간 계산)
         trafficCorrect();
 
-        // 4. 결측정보 처리를 통한 가공정보 생성
-        missingDataCorrect();
-
         log.info("[FUSION.] LinkTrafFusionService.processing: ..end. {}", Elapsed.elapsedStr(elapsed.nanoSeconds()));
         return 0;
     }
 
-    private int missingDataCorrectPSD() {
-        log.info("[FUSION.] LinkTrafFusionService.missingDataCorrectPSD: start.");
-        Elapsed elapsed = new Elapsed();
-
-        /* PSD 알고리즘 결측정보 처리
-         *  1. 레벨1 구간에 대한 처리
-         *  2. 결측된 링크의 현재 패턴정보가 존재해야 처리할 수 있음.
-         *  3. 상/하류 구간의 현재/패턴 정보가 존재해야함.
-         *    3.1 상/하류 구간 정보가 모두 존재하는 경우
-         *        결측속도 = 결측구간 패턴속도 * { [AVG(상류부현재속도+하류부현재속도)] / [AVG(상류부패턴속도+하류부패턴속도)]  }
-         *    3.2 상/하류 구간 중 하나의 구간 정보 만 존해하는 경우
-         *        결측속도 = 결측구간 패턴속도 * { 상/하류구간현재속도 / 상/하류구간패턴속도 }
-         *  4. 3항에서 결측한 결측 속도를 포함한 레벨4 구간의 속도정보를 계산
-         *  5. 결측이 발생한 레벨1 구간에 대해
-         *        결측속도 = 결측구간 패턴속도 * { 레벨4현재속도 / 레벨4패턴속도 }
-         */
-        AtomicInteger nCalCnt = new AtomicInteger();
-        this.linkRepo.getLinkMap().values().parallelStream()
-                .filter(link -> link.getLinkLevel() == 1)
-                .forEach(link -> {
-                    // 구간의 패턴정보가 존재하지 않는 다면 결측 처리 못함
-                    if (!link.getTrafPtrn().getState().isState()) {
-                        return;
-                    }
-                    LinkDto upLink = this.linkRepo.getLink(link.getUpLinkId());
-                    LinkDto dnLink = this.linkRepo.getLink(link.getDnLinkId());
-
-
-                    int step, speed;
-                    float cSpeed, pSpeed, ptrnSpeed;
-
-                    step = 0;
-                    cSpeed = pSpeed = 0F;
-                    ptrnSpeed = (float)link.getTrafPtrn().getSpeed();
-
-                    if (upLink != null) {
-                        if (upLink.getTrafFsn().getState().isState() && upLink.getTrafPtrn().getState().isState()) {
-                            // 상류 구간의 현재속도 정보와 패턴정보가 존재한다.
-                            step += 1;
-                            cSpeed += (float)upLink.getTrafFsn().getSpeed();
-                            pSpeed += (float)upLink.getTrafPtrn().getSpeed();
-                        }
-                    }
-                    if (dnLink != null) {
-                        if (dnLink.getTrafFsn().getState().isState() && dnLink.getTrafPtrn().getState().isState()) {
-                            // 상류 구간의 현재속도 정보와 패턴정보가 존재한다.
-                            step += 2;
-                            cSpeed += (float)dnLink.getTrafFsn().getSpeed();
-                            pSpeed += (float)dnLink.getTrafPtrn().getSpeed();
-                        }
-                    }
-
-                    if (step == 1) {
-                        // 상류부 소통정보 만 존재하는 경우 'H'
-                        speed = (int)( (ptrnSpeed * (cSpeed / pSpeed)) + 0.5 );
-                        link.getMissPsd().setTraffic("H", speed);
-                    }
-                    else if (step == 2) {
-                        // 하류부 소통정보 만 존재하는 경우 'L'
-                        speed = (int)( (ptrnSpeed * (cSpeed / pSpeed)) + 0.5 );
-                        link.getMissPsd().setTraffic("L", speed);
-                    }
-                    else if (step == 3)
-                    {
-                        // 상/하류부 소통정보가 모두 존재하는 경우 'Y'
-                        speed = (int)( (ptrnSpeed * ((cSpeed/2.) / (pSpeed/2.))) + 0.5 );
-                        link.getMissPsd().setTraffic("Y", speed);
-                    }
-                    else {
-                        /* 소통정보가 존재 하지 않음 */
-                        return;
-                    }
-                    if (link.getMissPsd().getSpeed() > link.getMaxSpeed()) {
-                        link.getMissPsd().setSpeed(link.getMaxSpeed());
-                    }
-                    nCalCnt.incrementAndGet();
-                }
-            );
-
-        log.info("[FUSION.] LinkTrafFusionService.missingDataCorrectPSD: ..end. {} EA. {}", nCalCnt.get(), Elapsed.elapsedStr(elapsed.nanoSeconds()));
-        return nCalCnt.get();
-    }
-
-    private int correctLevelTraffic(int linkLevel, String dataResType) {
-        log.info("[FUSION.] LinkTrafFusionService.correctLevelTraffic[Level:{}]: start.", linkLevel);
-        Elapsed elapsed = new Elapsed();
-        AtomicInteger nCalCnt = new AtomicInteger();
-
-
-        this.linkRepo.getLinkMap().values().parallelStream()
-                .filter(link -> link.getLinkLevel() == linkLevel)
-                .forEach(link -> {
-                    // 링크그룹에 속한 레벨1 링크의 소통정보를 이용하여 링크그룹 소통정보를 생성한다.
-                    if (link.getLinkIds() == null || link.getLinkIds().isEmpty()) {
-                        return;
-                    }
-                    float sumSpeed, sumLength, speed;
-                    int   clctCnt;
-                    sumSpeed = sumLength = speed = 0.F;
-                    clctCnt = 0;
-                    for (String linkId : link.getLinkIds()) {
-                        LinkDto subLink = this.linkRepo.getLink(linkId);
-                        if (subLink == null) {
-                            log.error("[FUSION.] LinkTrafFusionService.correctLevelTraffic[Level:{}]: {} link not found.", linkLevel, linkId);
-                            continue;
-                        }
-                        if (!subLink.getTrafFsn().getState().isState()) {
-                            continue;
-                        }
-                        if (subLink.getTrafFsn().getSpeed() > 0) {
-                            sumSpeed += (float)(subLink.getTrafFsn().getSpeed() * subLink.getLength());
-                            sumLength+= (float)subLink.getLength();
-                            clctCnt++;
-                        }
-                    }
-                    if (sumSpeed > 0. && sumLength > 0. && clctCnt > 0) {
-
-                        nCalCnt.incrementAndGet();
-                    }
-                }
-            );
-
-        log.info("[FUSION.] LinkTrafFusionService.correctLevelTraffic[Level:{}]: ..end. {} EA. {}", linkLevel, nCalCnt.get(), Elapsed.elapsedStr(elapsed.nanoSeconds()));
-        return nCalCnt.get();
-    }
-
-    private int missingDataCorrect() {
-        log.info("[FUSION.] LinkTrafFusionService.missingDataCorrect: start.");
-        Elapsed elapsed = new Elapsed();
-
-        // 모든 결측 알고리즘에 대해 결측 처리를 수행하고 최종 선택된 결측 알고리즘으로 결측을 수행한다.
-        // 1. PSD 알고리즘
-        missingDataCorrectPSD();
-
-        // 2. 결측처리된 레벨1 구간 소통정보를 이용하여 레벨4 구간 소통정보 생성
-        correctLevelTraffic(4, "P");
-
-        log.info("[FUSION.] LinkTrafFusionService.missingDataCorrect: ..end. {}", Elapsed.elapsedStr(elapsed.nanoSeconds()));
-        return 0;
-    }
-
     private int trafficCorrect() {
         log.info("[FUSION.] LinkTrafFusionService.trafficCorrect: start.");
         Elapsed elapsed = new Elapsed();
 
         AtomicInteger nCalCnt = new AtomicInteger();
-        this.linkRepo.getLinkMap().values().parallelStream()
+        this.linkRepositoryService.getLinkMap().values().parallelStream()
                 .filter(link -> link.getLinkLevel() == 1)
                 .forEach(link -> {
                     TrafficGrade grade = Optional.ofNullable(this.trafParamService.getTrafGradeMap().get(link.getLinkId()))
@@ -257,7 +113,7 @@ public class LinkTrafFusionService implements AbstractProcessService {
     }
 
     private boolean fusionTraffic(LinkCollectDto clctTraf, final String clctSystCd) {
-        LinkDto link = this.linkRepo.getLink(clctTraf.getLinkId());
+        LinkDto link = this.linkRepositoryService.getLink(clctTraf.getLinkId());
         if (link == null) {
             log.error("[FUSION.] LinkTrafFusionService.fusionTraffic: {} link not found[{}].", clctTraf.getLinkId(), clctSystCd);
             return false;
@@ -276,25 +132,25 @@ public class LinkTrafFusionService implements AbstractProcessService {
         AtomicInteger nCalCnt = new AtomicInteger();
         this.collectUTIS.getLists().parallelStream()
                 .forEach(clctTraf -> {
-                    if (fusionTraffic(clctTraf, LinkCollectSetupService.UTIS)) {
+                    if (fusionTraffic(clctTraf, LinkTrafCollectSetupService.UTIS)) {
                         nCalCnt.incrementAndGet();
                     }
                 });
         this.collectPRIO.getLists().parallelStream()
                 .forEach(clctTraf -> {
-                    if (fusionTraffic(clctTraf, LinkCollectSetupService.PRIO)) {
+                    if (fusionTraffic(clctTraf, LinkTrafCollectSetupService.PRIO)) {
                         nCalCnt.incrementAndGet();
                     }
                 });
         this.collectPRIOETC.getLists().parallelStream()
                 .forEach(clctTraf -> {
-                    if (fusionTraffic(clctTraf, LinkCollectSetupService.PRIOETC)) {
+                    if (fusionTraffic(clctTraf, LinkTrafCollectSetupService.PRIOETC)) {
                         nCalCnt.incrementAndGet();
                     }
                 });
         this.collectDONGBU.getLists().parallelStream()
                 .forEach(clctTraf -> {
-                    if (fusionTraffic(clctTraf, LinkCollectSetupService.DONGBU)) {
+                    if (fusionTraffic(clctTraf, LinkTrafCollectSetupService.DONGBU)) {
                         nCalCnt.incrementAndGet();
                     }
                 });
@@ -307,13 +163,13 @@ public class LinkTrafFusionService implements AbstractProcessService {
         log.info("[FUSION.] LinkTrafFusionService.weightFusion: start.");
         Elapsed elapsed = new Elapsed();
 
-        Map<String, LinkCollectDto> utisMap = collectUTIS.getLists().stream()
+        Map<String, LinkCollectDto> utisMap = this.collectUTIS.getLists().stream()
                 .collect(Collectors.toMap(LinkCollectDto::getLinkId, dto -> dto, (existing, replacement) -> existing));
-        Map<String, LinkCollectDto> prioMap = collectPRIO.getLists().stream()
+        Map<String, LinkCollectDto> prioMap = this.collectPRIO.getLists().stream()
                 .collect(Collectors.toMap(LinkCollectDto::getLinkId, dto -> dto, (existing, replacement) -> existing));
-        Map<String, LinkCollectDto> prioEtcMap = collectPRIOETC.getLists().stream()
+        Map<String, LinkCollectDto> prioEtcMap = this.collectPRIOETC.getLists().stream()
                 .collect(Collectors.toMap(LinkCollectDto::getLinkId, dto -> dto, (existing, replacement) -> existing));
-        Map<String, LinkCollectDto> dongbuMap = collectDONGBU.getLists().stream()
+        Map<String, LinkCollectDto> dongbuMap = this.collectDONGBU.getLists().stream()
                 .collect(Collectors.toMap(LinkCollectDto::getLinkId, dto -> dto, (existing, replacement) -> existing));
 
         AtomicReference<String> gps = new AtomicReference<>("0");
@@ -322,7 +178,7 @@ public class LinkTrafFusionService implements AbstractProcessService {
         AtomicReference<String> dongbu = new AtomicReference<>("0");
 
         AtomicInteger nCalCnt = new AtomicInteger();
-        this.linkRepo.getLinkMap().values().parallelStream()
+        this.linkRepositoryService.getLinkMap().values().parallelStream()
                 .filter(link -> link.getLinkLevel() == 1)
                 .filter(link -> !link.getTrafFsn().getState().isState())
                 .forEach(link -> {
@@ -384,7 +240,7 @@ public class LinkTrafFusionService implements AbstractProcessService {
     }
 
     private boolean externalFusionTraffic(LinkCollectDto clctTraf, final String clctSystCd) {
-        LinkDto link = this.linkRepo.getLink(clctTraf.getLinkId());
+        LinkDto link = this.linkRepositoryService.getLink(clctTraf.getLinkId());
         if (link == null) {
             log.error("[FUSION.] LinkTrafFusionService.externalFusionTraffic: {} link not found[{}].", clctTraf.getLinkId(), clctSystCd);
             return false;
@@ -403,19 +259,19 @@ public class LinkTrafFusionService implements AbstractProcessService {
         AtomicInteger nCalCnt = new AtomicInteger();
         this.collectUTIS.getLists().parallelStream()
                 .forEach(clctTraf -> {
-                    if (externalFusionTraffic(clctTraf, LinkCollectSetupService.UTIS)) {
+                    if (externalFusionTraffic(clctTraf, LinkTrafCollectSetupService.UTIS)) {
                         nCalCnt.incrementAndGet();
                     }
                 });
         this.collectPRIO.getLists().parallelStream()
                 .forEach(clctTraf -> {
-                    if (externalFusionTraffic(clctTraf, LinkCollectSetupService.PRIO)) {
+                    if (externalFusionTraffic(clctTraf, LinkTrafCollectSetupService.PRIO)) {
                         nCalCnt.incrementAndGet();
                     }
                 });
         this.collectPRIOETC.getLists().parallelStream()
                 .forEach(clctTraf -> {
-                    if (externalFusionTraffic(clctTraf, LinkCollectSetupService.PRIOETC)) {
+                    if (externalFusionTraffic(clctTraf, LinkTrafCollectSetupService.PRIOETC)) {
                         nCalCnt.incrementAndGet();
                     }
                 });
@@ -429,7 +285,7 @@ public class LinkTrafFusionService implements AbstractProcessService {
         Elapsed elapsed = new Elapsed();
         int nCalCnt = 0;
         for (LinkCollectDto dto : this.collectOPER.getLists()) {
-            LinkDto link = this.linkRepo.getLink(dto.getLinkId());
+            LinkDto link = this.linkRepositoryService.getLink(dto.getLinkId());
             if (link == null) {
                 log.error("[FUSION.] LinkTrafFusionService.operatorFusion: {} link not found.", dto.getLinkId());
                 continue;

+ 391 - 0
utic-ptis-server/src/main/java/com/utic/ptis/server/service/LinkTrafMissingService.java

@@ -0,0 +1,391 @@
+package com.utic.ptis.server.service;
+
+import com.utic.common.utils.Elapsed;
+import com.utic.ptis.server.dto.LinkCollectDto;
+import com.utic.ptis.server.dto.LinkCollectResultDto;
+import com.utic.ptis.server.dto.LinkDto;
+import com.utic.ptis.server.dto.LinkTrafState;
+import com.utic.ptis.server.dto.utic.TrafficGrade;
+import lombok.Getter;
+import lombok.RequiredArgsConstructor;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.stereotype.Service;
+
+import java.util.ArrayList;
+import java.util.Optional;
+import java.util.concurrent.atomic.AtomicInteger;
+
+@Slf4j
+@Getter
+@RequiredArgsConstructor
+@Service
+public class LinkTrafMissingService implements AbstractProcessService {
+
+    private final LinkRepositoryService linkRepo;
+    private final LinkTrafParamService trafParamService;
+    private final LinkTrafCollectService collectService;
+
+    private void initialize() {
+        log.info("[MISSING] LinkTrafMissingService.initialize: start.");
+        Elapsed elapsed = new Elapsed();
+        log.info("[MISSING] LinkTrafMissingService.initialize: ..end. {}", Elapsed.elapsedStr(elapsed.nanoSeconds()));
+    }
+    public int processing() {
+        log.info("[MISSING] LinkTrafMissingService.processing: start.");
+        Elapsed elapsed = new Elapsed();
+
+        // 0. 결측 초기화
+        initialize();
+
+        // 모든 결측 알고리즘에 대해 결측 처리를 수행하고 
+        // 최종 선택된 결측 알고리즘으로 결측을 수행한다.
+        
+        // 1. PSD 알고리즘
+        missingLinkPsd();
+
+        // 2. 레벨1 구간 소통정보를 이용하여 레벨4 구간 소통정보 생성
+        groupLinkTrafficCreate(4, "P");
+
+        // 3. 레벨4 링크를 이용하여 레벨1 링크 PSD 결측정보 처리
+        missingGroupPsd();
+
+        // 4. 결측된 구간에 대하여 결측 알고리즘을 이용하여 속도 계산
+        missingLinkCorrect();
+
+        // 5. 패턴을 이용하여 결측 처리
+        missingLinkPattern();
+
+        // 6. 외부 연계 소통정보를 이용하여 결측 처리
+        missingLinkExternal();
+
+        // 7. 국토부 민간소통정보를 이용한 결측
+        //    - 외부연계퓨전은 국토부 민간소통정보를 이용하여 결측처리하지 않으므로외부연계퓨전처리 완료후 결측을 처리함
+        missingLinkMoct();
+
+        // 8. 결측 처리된 레벨1 소통정보를 이용하여 상위레벨 소통정보를 생성(레벨2,3,4)
+        for (int ii = 2; ii <= 4; ii++) {
+            groupLinkTrafficCreate(ii, "P");
+        }
+
+        log.info("[MISSING] LinkTrafMissingService.processing: ..end. {}", Elapsed.elapsedStr(elapsed.nanoSeconds()));
+        return 0;
+    }
+
+    private int missingLinkMoct() {
+        log.info("[MISSING] LinkTrafMissingService.missingLinkMoct: start.");
+        Elapsed elapsed = new Elapsed();
+
+        // 결측처리 방식: 국토부 민간소통정보를 이용하여 결측
+        LinkCollectResultDto collectMOCT = Optional.ofNullable(this.collectService.get(LinkTrafCollectSetupService.MOCT))
+                .orElseGet(() -> LinkCollectResultDto.builder().clctSystCd(LinkTrafCollectSetupService.MOCT).lists(new ArrayList<>()).build());
+
+        int nCalCnt = 0;
+        for (LinkCollectDto clctTraf: collectMOCT.getLists()) {
+            LinkDto link = this.linkRepo.getLink(clctTraf.getLinkId());
+            if (link == null) {
+                log.error("[MISSING] LinkTrafMissingService.missingLinkMoct: {} link not found.", clctTraf.getLinkId());
+                continue;
+            }
+
+            if (link.getTrafFsn().getState().isState()) {
+                // 퓨전 소통정보가 존재하면 처리하지 않음
+                continue;
+            }
+            if (clctTraf.getSpeed() > 0) {
+                TrafficGrade grade = Optional.ofNullable(this.trafParamService.getTrafGradeMap().get(link.getLinkId()))
+                        .orElseGet(() -> TrafficGrade.builder().roadRank("999").minSpeed(30).maxSpeed(49).build());
+                link.getTrafFsn().getState().setCrtDataType(LinkTrafState.TRAFFIC_CRT_DATA_TYPE.CRT_DATA_MISSING);
+                link.getTrafFsn().setTraffic(clctTraf.getCenterId(), clctTraf.getSpeed(), clctTraf.getMissValueYn(), clctTraf.getDataResType());
+                link.getTrafExt().trafficCorrect(link.getLength(), link.getMaxSpeed(), grade.getMinSpeed(), grade.getMaxSpeed());
+                nCalCnt++;
+            }
+        }
+        log.info("[MISSING] LinkTrafMissingService.missingLinkMoct: ..end. {} EA. {}", nCalCnt, Elapsed.elapsedStr(elapsed.nanoSeconds()));
+        return nCalCnt;
+    }
+
+    private int missingLinkExternal() {
+        log.info("[MISSING] LinkTrafMissingService.missingLinkExternal: start.");
+        Elapsed elapsed = new Elapsed();
+
+        // 결측처리 방식: 구간의 현재 패턴정보를 이용
+        AtomicInteger nCalCnt = new AtomicInteger();
+        this.linkRepo.getLinkMap().values().parallelStream()
+                .filter(link -> link.getLinkLevel() == 1)
+                .forEach(link -> {
+                    // 구간의 연계소통정보가 존재하면 처리하지 않음
+                    if (link.getTrafExt().getState().isState()) {
+                        return;
+                    }
+                    // 구간의 퓨전소통정보가 존재하지 않으면 처리하지 못함
+                    if (!link.getTrafFsn().getState().isState()) {
+                        return;
+                    }
+
+                    // 동부데이터가 들어가 있는것은 제외하여야 한다.
+                    // 즉, 정상적으로 수집된 정보는 제외한다.(동부정보가 들어가있으므로)
+                    if (link.getTrafFsn().getState().getCrtDataType() == LinkTrafState.TRAFFIC_CRT_DATA_TYPE.CRT_DATA_NORMAL) {
+                        return;
+                    }
+
+                    link.getTrafExt().copy(link.getTrafFsn());
+                    nCalCnt.incrementAndGet();
+                }
+            );
+
+        log.info("[MISSING] LinkTrafMissingService.missingLinkExternal: ..end. {} EA. {}", nCalCnt.get(), Elapsed.elapsedStr(elapsed.nanoSeconds()));
+        return nCalCnt.get();
+    }
+
+    private int missingLinkPattern() {
+        log.info("[MISSING] LinkTrafMissingService.missingLinkPattern: start.");
+        Elapsed elapsed = new Elapsed();
+
+        // 결측처리 방식: 구간의 현재 패턴정보를 이용
+        AtomicInteger nCalCnt = new AtomicInteger();
+        this.linkRepo.getLinkMap().values().parallelStream()
+                .filter(link -> link.getLinkLevel() == 1)
+                .forEach(link -> {
+                            // 구간의 퓨전소통정보가 존재하면 처리하지 않음
+                            if (link.getTrafFsn().getState().isState()) {
+                                return;
+                            }
+                            // 구간의 패턴소통정보가 존재하지 않으면 처리하지 못함
+                            if (!link.getTrafPtrn().getState().isState()) {
+                                return;
+                            }
+
+                            if (link.getTrafPtrn().getSpeed() > 0) {
+                                TrafficGrade grade = Optional.ofNullable(this.trafParamService.getTrafGradeMap().get(link.getLinkId()))
+                                        .orElseGet(() -> TrafficGrade.builder().roadRank("999").minSpeed(30).maxSpeed(49).build());
+                                link.getTrafFsn().getState().setCrtDataType(LinkTrafState.TRAFFIC_CRT_DATA_TYPE.CRT_DATA_MISSING);
+                                link.getTrafFsn().setTraffic("C00", link.getTrafPtrn().getSpeed(), "T", "P");
+                                link.getTrafExt().trafficCorrect(link.getLength(), link.getMaxSpeed(), grade.getMinSpeed(), grade.getMaxSpeed());
+                                nCalCnt.incrementAndGet();
+                            }
+                        }
+                );
+
+        log.info("[MISSING] LinkTrafMissingService.missingLinkPattern: ..end. {} EA. {}", nCalCnt.get(), Elapsed.elapsedStr(elapsed.nanoSeconds()));
+        return nCalCnt.get();
+    }
+
+    private int missingLinkCorrect() {
+        log.info("[MISSING] LinkTrafMissingService.missingLinkCorrect: start.");
+        Elapsed elapsed = new Elapsed();
+
+        // 결측처리 방식: 우선순위, KNN(사용하지 않음)
+        AtomicInteger nCalCnt = new AtomicInteger();
+        this.linkRepo.getLinkMap().values().parallelStream()
+                .filter(link -> link.getLinkLevel() == 1)
+                .forEach(link -> {
+                            // 구간의 퓨전소통정보가 존재하면 처리하지 않음
+                            if (link.getTrafFsn().getState().isState()) {
+                                return;
+                            }
+
+                            if (link.getMissPsd().getSpeed() > 0) {
+                                TrafficGrade grade = Optional.ofNullable(this.trafParamService.getTrafGradeMap().get(link.getLinkId()))
+                                        .orElseGet(() -> TrafficGrade.builder().roadRank("999").minSpeed(30).maxSpeed(49).build());
+                                link.getTrafFsn().getState().setCrtDataType(LinkTrafState.TRAFFIC_CRT_DATA_TYPE.CRT_DATA_MISSING);
+                                link.getTrafFsn().setTraffic("C00", link.getMissPsd().getSpeed(), link.getMissPsd().getMissValueYn(), "P");
+                                link.getTrafExt().trafficCorrect(link.getLength(), link.getMaxSpeed(), grade.getMinSpeed(), grade.getMaxSpeed());
+                                nCalCnt.incrementAndGet();
+                            }
+                        }
+                );
+
+        log.info("[MISSING] LinkTrafMissingService.missingLinkCorrect: ..end. {} EA. {}", nCalCnt.get(), Elapsed.elapsedStr(elapsed.nanoSeconds()));
+        return nCalCnt.get();
+    }
+
+    private int missingLinkPsd() {
+        log.info("[MISSING] LinkTrafMissingService.missingLinkPsd: start.");
+        Elapsed elapsed = new Elapsed();
+
+        /* PSD 알고리즘 결측정보 처리
+         *  1. 레벨1 구간에 대한 처리
+         *  2. 결측된 링크의 현재 패턴정보가 존재해야 처리할 수 있음.
+         *  3. 상/하류 구간의 현재/패턴 정보가 존재해야함.
+         *    3.1 상/하류 구간 정보가 모두 존재하는 경우
+         *        결측속도 = 결측구간 패턴속도 * { [AVG(상류부현재속도+하류부현재속도)] / [AVG(상류부패턴속도+하류부패턴속도)]  }
+         *    3.2 상/하류 구간 중 하나의 구간 정보 만 존해하는 경우
+         *        결측속도 = 결측구간 패턴속도 * { 상/하류구간현재속도 / 상/하류구간패턴속도 }
+         *  4. 3항에서 결측한 결측 속도를 포함한 레벨4 구간의 속도정보를 계산
+         *  5. 결측이 발생한 레벨1 구간에 대해
+         *        결측속도 = 결측구간 패턴속도 * { 레벨4현재속도 / 레벨4패턴속도 }
+         */
+        AtomicInteger nCalCnt = new AtomicInteger();
+        this.linkRepo.getLinkMap().values().parallelStream()
+                .filter(link -> link.getLinkLevel() == 1)
+                .forEach(link -> {
+                    // 구간의 패턴정보가 존재하지 않는 다면 결측 처리 못함
+                    if (!link.getTrafPtrn().getState().isState()) {
+                        return;
+                    }
+                    LinkDto upLink = this.linkRepo.getLink(link.getUpLinkId());
+                    LinkDto dnLink = this.linkRepo.getLink(link.getDnLinkId());
+
+                    int step, speed;
+                    float cSpeed, pSpeed, ptrnSpeed;
+                    step = speed = 0;
+                    cSpeed = pSpeed = 0F;
+                    ptrnSpeed = (float)link.getTrafPtrn().getSpeed();
+
+                    if (upLink != null) {
+                        if (upLink.getTrafFsn().getState().isState() && upLink.getTrafPtrn().getState().isState()) {
+                            // 상류 구간의 현재속도 정보와 패턴정보가 존재한다.
+                            step += 1;
+                            cSpeed += (float)upLink.getTrafFsn().getSpeed();
+                            pSpeed += (float)upLink.getTrafPtrn().getSpeed();
+                        }
+                    }
+                    if (dnLink != null) {
+                        if (dnLink.getTrafFsn().getState().isState() && dnLink.getTrafPtrn().getState().isState()) {
+                            // 상류 구간의 현재속도 정보와 패턴정보가 존재한다.
+                            step += 2;
+                            cSpeed += (float)dnLink.getTrafFsn().getSpeed();
+                            pSpeed += (float)dnLink.getTrafPtrn().getSpeed();
+                        }
+                    }
+
+                    String missValueYn = "";
+                    if (step == 1 || step == 2) {
+                        // 상류부(H) 또는 하류부(L) 소통정보 만 존재하는 경우
+                        speed = (int)( (ptrnSpeed * (cSpeed / pSpeed)) + 0.5 );
+                        missValueYn = (step == 1) ? "H" : "L";
+                    }
+                    else if (step == 3) {
+                        // 상/하류부 소통정보가 모두 존재하는 경우 'Y'
+                        speed = (int)( (ptrnSpeed * ((cSpeed/2.) / (pSpeed/2.))) + 0.5 );
+                        missValueYn = "Y";
+                    }
+                    if (speed > 0) {
+                        if (speed > link.getMaxSpeed()) {
+                            speed = link.getMaxSpeed();
+                        }
+                        link.getMissPsd().setTraffic(missValueYn, speed);
+                        nCalCnt.incrementAndGet();
+                    }
+                }
+            );
+
+        log.info("[MISSING] LinkTrafMissingService.missingLinkPsd: ..end. {} EA. {}", nCalCnt.get(), Elapsed.elapsedStr(elapsed.nanoSeconds()));
+        return nCalCnt.get();
+    }
+
+    private int groupLinkTrafficCreate(int linkLevel, String dataResType) {
+        log.info("[MISSING] LinkTrafMissingService.groupLinkTrafficCreate[Level:{}]: start.", linkLevel);
+        Elapsed elapsed = new Elapsed();
+        AtomicInteger nCalCnt = new AtomicInteger();
+
+        this.linkRepo.getLinkMap().values().parallelStream()
+                .filter(link -> link.getLinkLevel() == linkLevel)
+                .forEach(link -> {
+                    // 링크그룹에 속한 레벨1 링크의 소통정보를 이용하여 링크그룹 소통정보를 생성한다.
+                    if (link.getLinkIds() == null || link.getLinkIds().isEmpty()) {
+                        return;
+                    }
+
+                    float sumSpeed, sumLength, sumSpeedExt, sumLengthExt;
+                    int   clctCnt, clctCntExt;
+
+                    sumSpeed = sumLength = sumSpeedExt = sumLengthExt = 0.F;
+                    clctCntExt = clctCnt = 0;
+                    for (String linkId : link.getLinkIds()) {
+                        LinkDto subLink = this.linkRepo.getLink(linkId);
+                        if (subLink == null) {
+                            log.error("[MISSING] LinkTrafMissingService.groupLinkTrafficCreate[Level:{}]: {} link not found.", linkLevel, linkId);
+                            continue;
+                        }
+                        if (!subLink.getTrafFsn().getState().isState()) {
+                            // 퓨전 소통정보 생성
+                            if (subLink.getTrafFsn().getSpeed() > 0) {
+                                sumSpeed  += subLink.getTrafFsn().getSpeed() * subLink.getLength();
+                                sumLength += subLink.getLength();
+                                clctCnt++;
+                            }
+                        }
+                        if (!subLink.getTrafExt().getState().isState()) {
+                            // 외부연계 소통정보 생성
+                            if (subLink.getTrafExt().getSpeed() > 0) {
+                                sumSpeedExt  += subLink.getTrafExt().getSpeed() * subLink.getLength();
+                                sumLengthExt += subLink.getLength();
+                                clctCntExt++;
+                            }
+                        }
+                    }
+
+                    TrafficGrade grade = Optional.ofNullable(this.trafParamService.getTrafGradeMap().get(link.getLinkId()))
+                            .orElseGet(() -> TrafficGrade.builder().roadRank("999").minSpeed(30).maxSpeed(49).build());
+                    if (sumSpeed > 0. && sumLength > 0. && clctCnt > 0) {
+                        int speed = (int)( (sumSpeed / sumLength) + 0.5 );
+                        link.getTrafFsn().setTraffic("C00", speed, "M", dataResType);
+                        link.getTrafFsn().trafficCorrect(link.getLength(), link.getMaxSpeed(), grade.getMinSpeed(), grade.getMaxSpeed());
+                        nCalCnt.incrementAndGet();
+                    }
+                    if (sumSpeedExt > 0. && sumLengthExt > 0. && clctCntExt > 0) {
+                        int speedExt = (int)( (sumSpeedExt / sumLengthExt) + 0.5 );
+                        link.getTrafExt().setTraffic("C00", speedExt, "M", dataResType);
+                        link.getTrafExt().trafficCorrect(link.getLength(), link.getMaxSpeed(), grade.getMinSpeed(), grade.getMaxSpeed());
+                    }
+                }
+            );
+
+        log.info("[MISSING] LinkTrafMissingService.groupLinkTrafficCreate[Level:{}]: ..end. {} EA. {}", linkLevel, nCalCnt.get(), Elapsed.elapsedStr(elapsed.nanoSeconds()));
+        return nCalCnt.get();
+    }
+
+    private int missingGroupPsd() {
+        log.info("[MISSING] LinkTrafMissingService.missingGroupPsd: start.");
+        Elapsed elapsed = new Elapsed();
+        AtomicInteger nCalCnt = new AtomicInteger();
+
+        // 레벨4 구간을 이용한 PSD 결측정보 처리
+        // 레벨1은 모든 구간에 대하여 PSD 알고리즘을 수행하고
+        // 레벨4 소통정보 다운 알고리즘은 생성되지 않은 레벨1 구간에 대하여 수행함
+        // PSD 상/하위 구간으로 처리하지 못한 구간에 대하여 4레벨 다운 소통정보를 생성
+        // 레벨1 PSD 속도 = 레벨1 패턴속도 * (레벨4 퓨전속도 / 레벨4 패턴속도)
+        this.linkRepo.getLinkMap().values().parallelStream()
+                .filter(link -> link.getLinkLevel() == 4)
+                .forEach(link -> {
+                if (link.getLinkIds() == null || link.getLinkIds().isEmpty()) {
+                    // 레벨4 구간에 속한 레벨1 구간이 존재하지 않음
+                    return;
+                }
+
+                if (!link.getTrafFsn().getState().isState() || !link.getTrafPtrn().getState().isState()) {
+                    // 레벨4 구간의 퓨전속도 또는 패턴속도가 존재하지 않으면 결측처리를 수행할 수 없다.
+                    return;
+                }
+
+                for (String linkId : link.getLinkIds()) {
+                    LinkDto subLink = this.linkRepo.getLink(linkId);
+                    if (subLink == null) {
+                        log.error("[MISSING] LinkTrafMissingService.missingGroupPsd: {} link not found.", linkId);
+                        continue;
+                    }
+                    if (subLink.getMissPsd().getSpeed() > 0) {
+                        // 레벨1 구간의 PSD 속도정보가 존재하면 결측처리 수행하지 않음
+                        continue;
+                    }
+                    if (!subLink.getTrafPtrn().getState().isState()) {
+                        // 레벨1 구간의 패턴속도가 존재하지 않으면 결측처리 수행하지 않음
+                        continue;
+                    }
+                    int speed = (int)( (subLink.getTrafPtrn().getSpeed() * ((double) link.getTrafFsn().getSpeed() / link.getTrafPtrn().getSpeed())) + 0.5 );
+                    subLink.getMissPsd().setSpeed(speed);
+                    subLink.getMissPsd().setMissValueYn("K");
+                    if (subLink.getMissPsd().getSpeed() > subLink.getMaxSpeed()) {
+                        subLink.getMissPsd().setSpeed(subLink.getMaxSpeed());
+                    }
+                    nCalCnt.incrementAndGet();
+                }
+            }
+        );
+
+        log.info("[MISSING] LinkTrafMissingService.missingGroupPsd: ..end. {} EA. {}", nCalCnt.get(), Elapsed.elapsedStr(elapsed.nanoSeconds()));
+        return nCalCnt.get();
+    }
+
+}

+ 2 - 2
utic-ptis-server/src/main/java/com/utic/ptis/server/service/LinkTrafPatternService.java

@@ -49,7 +49,7 @@ public class LinkTrafPatternService implements AbstractProcessService {
     private final ConcurrentHashMap<String, TrafficGrade> trafGradeMap = new ConcurrentHashMap<>();
 
     public int processing() {
-        log.info("[PARAM..] processing: start.");
+        log.info("[PATTERN] processing: start.");
         Elapsed elapsed = new Elapsed();
 
         try {
@@ -93,7 +93,7 @@ public class LinkTrafPatternService implements AbstractProcessService {
         } catch (Exception e) {
             log.error("findTrafficGrade: {}", e.getMessage());
         }
-        log.info("[PARAM..] processing: end. {}", Elapsed.elapsedStr(elapsed.nanoSeconds()));
+        log.info("[PATTERN] processing: end. {}", Elapsed.elapsedStr(elapsed.nanoSeconds()));
         return 0;
     }
 

+ 2 - 2
utic-ptis-server/src/main/java/com/utic/ptis/server/service/TrafPrcsTime.java → utic-ptis-server/src/main/java/com/utic/ptis/server/service/LinkTrafPrcsTime.java

@@ -15,7 +15,7 @@ import java.util.Date;
 @Getter
 @Setter
 @Service
-public class TrafPrcsTime {
+public class LinkTrafPrcsTime {
 
 	/*
 	 * 모든 시각은 'YYYYMMDDHH24MISS' 형태로 사용한다.
@@ -72,7 +72,7 @@ public class TrafPrcsTime {
 	private String ptrn05M;
 	private String ptrn15M;
 
-	public TrafPrcsTime() {
+	public LinkTrafPrcsTime() {
 		startDate = new Date();
 		endDate   = new Date();
 	}

+ 116 - 0
utic-ptis-server/src/main/java/com/utic/ptis/server/service/worker/LinkTrafCollectWorker.java

@@ -0,0 +1,116 @@
+package com.utic.ptis.server.service.worker;
+
+import com.utic.common.spring.SpringUtils;
+import com.utic.ptis.server.dto.LinkCollectDto;
+import com.utic.ptis.server.dto.LinkCollectParam;
+import com.utic.ptis.server.dto.LinkCollectResultDto;
+import com.utic.ptis.server.dto.LinkCollectSetupDto;
+import com.utic.ptis.server.service.LinkTrafCollectSetupService;
+import lombok.RequiredArgsConstructor;
+import lombok.extern.slf4j.Slf4j;
+import org.apache.ibatis.mapping.MappedStatement;
+import org.apache.ibatis.session.ExecutorType;
+import org.apache.ibatis.session.SqlSession;
+import org.apache.ibatis.session.SqlSessionFactory;
+import org.springframework.util.StopWatch;
+
+import java.util.ArrayList;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Set;
+import java.util.concurrent.ConcurrentHashMap;
+
+@Slf4j
+@RequiredArgsConstructor
+public class LinkTrafCollectWorker implements Runnable {
+
+    private final String clctSystCd;
+    private final LinkCollectParam params;
+    private final ConcurrentHashMap<String, LinkCollectResultDto> mapData;
+    private final LinkTrafCollectSetupService collectSetupService;
+
+    @Override
+    public void run() {
+        SqlSessionFactory sqlSessionFactory;
+
+        LinkCollectSetupDto stup = this.collectSetupService.get(this.clctSystCd);
+        String jobType = (stup == null) ? " (SEL) UNKNOWN, " + this.clctSystCd : stup.getClctSystNm();
+
+        StopWatch stopWatch = new StopWatch();
+        stopWatch.start(jobType);
+
+        try {
+            sqlSessionFactory = (SqlSessionFactory)SpringUtils.getBean(this.clctSystCd.toLowerCase());
+        } catch (Exception e) {
+            sqlSessionFactory = SpringUtils.getBean(SqlSessionFactory.class);
+        }
+
+        if (sqlSessionFactory == null) {
+            log.error("[COLLECT] LinkTrafCollectWorker.run: SqlSessionFactory is null. [{}], {}.", this.clctSystCd, jobType);
+            this.mapData.put(this.clctSystCd, LinkCollectResultDto.builder().clctSystCd(this.clctSystCd).lists(new ArrayList<>()).build());
+            return;
+        }
+
+        int resultCount = 0;
+        try {
+            Thread.sleep(10);
+
+            String queryId = "findLinkCollect" + clctSystCd;
+            MappedStatement mappedStatement = sqlSessionFactory.getConfiguration().getMappedStatement(queryId);
+            if (mappedStatement == null) {
+                log.error("[COLLECT] LinkTrafCollectWorker.run: [{}], {}, {}, queryId is not found.", this.clctSystCd, jobType, queryId);
+                this.mapData.put(this.clctSystCd, LinkCollectResultDto.builder().clctSystCd(this.clctSystCd).lists(new ArrayList<>()).build());
+                return;
+            }
+
+            // 쿼리 ID가 존재하는 경우에만 실행
+            List<LinkCollectDto> queryResult = null;
+            SqlSession sqlSession = null;
+            try {
+                sqlSession = sqlSessionFactory.openSession(ExecutorType.SIMPLE, false);
+                queryResult = sqlSession.selectList(queryId, params);
+            }
+            catch (Exception e) {
+                log.error("[COLLECT] LinkTrafCollectWorker.run: Exception: [{}], {}, {}, {}", this.clctSystCd, jobType, queryId, e.getMessage());
+            }
+            finally {
+                if (sqlSession != null) {
+                    sqlSession.close();
+                }
+            }
+            if (queryResult == null) {
+                this.mapData.put(this.clctSystCd, LinkCollectResultDto.builder().clctSystCd(this.clctSystCd).lists(new ArrayList<>()).build());
+            }
+            else {
+                resultCount = queryResult.size();
+
+                if (LinkTrafCollectSetupService.PRIO.equals(this.clctSystCd) || LinkTrafCollectSetupService.PRIOETC.equals(this.clctSystCd)) {
+                    // 우선순위 수집의 경우 LinkId 가 중복될 수 있으므로
+                    // 중복된 LinkId 를 제거하기 위해 HashSet 을 사용하여 중복값을 제거
+                    List<LinkCollectDto> result = new ArrayList<>();
+                    Set<String> uniqueSet = new HashSet<>();
+                    for (LinkCollectDto dto : queryResult) {
+                        if (uniqueSet.add(dto.getLinkId())) {  // HashSet 의 add() 메서드는 중복값이 있으면 false 를 반환
+                            result.add(dto);
+                        }
+                    }
+                    this.mapData.put(this.clctSystCd, LinkCollectResultDto.builder().clctSystCd(this.clctSystCd).lists(result).build());
+                }
+                else {
+                    this.mapData.put(this.clctSystCd, LinkCollectResultDto.builder().clctSystCd(this.clctSystCd).lists(queryResult).build());
+                }
+            }
+        }
+        catch (InterruptedException e) {
+            log.info("[COLLECT] LinkTrafCollectWorker.run: InterruptedException, [{}], {}, {}.", this.clctSystCd, jobType, e.getMessage());
+            this.mapData.put(this.clctSystCd, LinkCollectResultDto.builder().clctSystCd(this.clctSystCd).lists(new ArrayList<>()).build());
+        }
+        catch (Exception e) {
+            log.info("[COLLECT] LinkTrafCollectWorker.run: Exception, [{}], {}, {}.", this.clctSystCd, jobType, e.getMessage());
+            this.mapData.put(this.clctSystCd, LinkCollectResultDto.builder().clctSystCd(this.clctSystCd).lists(new ArrayList<>()).build());
+        }
+        stopWatch.stop();
+        log.info("[COLLECT] LinkTrafCollectWorker.run: {}: [{} EA. {} ms]", jobType, resultCount, stopWatch.getTotalTimeMillis());
+    }
+
+}

+ 18 - 34
utic-ptis-server/src/main/java/com/utic/ptis/server/service/collect/LinkCollectWorker.java → utic-ptis-server/src/main/java/com/utic/ptis/server/service/worker/LinkTrafDeleteWorker.java

@@ -1,10 +1,11 @@
-package com.utic.ptis.server.service.collect;
+package com.utic.ptis.server.service.worker;
 
 import com.utic.common.spring.SpringUtils;
 import com.utic.ptis.server.dto.LinkCollectDto;
 import com.utic.ptis.server.dto.LinkCollectParam;
 import com.utic.ptis.server.dto.LinkCollectResultDto;
-import com.utic.ptis.server.repository.eTrafPrcsJob;
+import com.utic.ptis.server.dto.LinkCollectSetupDto;
+import com.utic.ptis.server.service.LinkTrafCollectSetupService;
 import lombok.RequiredArgsConstructor;
 import lombok.extern.slf4j.Slf4j;
 import org.apache.ibatis.mapping.MappedStatement;
@@ -21,45 +22,31 @@ import java.util.concurrent.ConcurrentHashMap;
 
 @Slf4j
 @RequiredArgsConstructor
-public class LinkCollectWorker implements Runnable {
+public class LinkTrafDeleteWorker implements Runnable {
 
     private final String clctSystCd;
     private final LinkCollectParam params;
     private final ConcurrentHashMap<String, LinkCollectResultDto> mapData;
+    private final LinkTrafCollectSetupService collectSetupService;
 
     @Override
     public void run() {
-        SqlSessionFactory sqlSessionFactory = null;
-        String beanName = this.clctSystCd.toLowerCase();
+        SqlSessionFactory sqlSessionFactory;
 
-        eTrafPrcsJob jobType = null;
-        if (LinkCollectSetupService.OPER.toLowerCase().equals(beanName)) {
-            jobType = eTrafPrcsJob.PRCS_LOAD_RAW_OPER;
-        } else if (LinkCollectSetupService.UTIS.toLowerCase().equals(beanName)) {
-            jobType = eTrafPrcsJob.PRCS_LOAD_RAW_UTIS;
-        } else if (LinkCollectSetupService.PRIO.toLowerCase().equals(beanName)) {
-            jobType = eTrafPrcsJob.PRCS_LOAD_RAW_PRIO;
-        } else if (LinkCollectSetupService.PRIOETC.toLowerCase().equals(beanName)) {
-            jobType = eTrafPrcsJob.PRCS_LOAD_RAW_PRIOETC;
-        } else if (LinkCollectSetupService.DONGBU.toLowerCase().equals(beanName)) {
-            jobType = eTrafPrcsJob.PRCS_LOAD_RAW_DONGBU;
-        } else if (LinkCollectSetupService.MOCT.toLowerCase().equals(beanName)) {
-            jobType = eTrafPrcsJob.PRCS_LOAD_RAW_MOCT;
-        }
+        LinkCollectSetupDto stup = this.collectSetupService.get(this.clctSystCd);
+        String jobType = (stup == null) ? " (SEL) UNKNOWN, " + this.clctSystCd : stup.getClctSystNm();
 
         StopWatch stopWatch = new StopWatch();
-        if (jobType != null) {
-            stopWatch.start(jobType.getName());
-        }
+        stopWatch.start(jobType);
 
         try {
-            sqlSessionFactory = (SqlSessionFactory)SpringUtils.getBean(beanName);
+            sqlSessionFactory = (SqlSessionFactory)SpringUtils.getBean(this.clctSystCd.toLowerCase());
         } catch (Exception e) {
             sqlSessionFactory = SpringUtils.getBean(SqlSessionFactory.class);
         }
 
         if (sqlSessionFactory == null) {
-            log.error("[COLLECT] LinkCollectWorker:run----: SqlSessionFactory is null. [{}].", this.clctSystCd);
+            log.error("[COLLECT] LinkTrafDeleteWorker.run: SqlSessionFactory is null. [{}], {}.", this.clctSystCd, jobType);
             this.mapData.put(this.clctSystCd, LinkCollectResultDto.builder().clctSystCd(this.clctSystCd).lists(new ArrayList<>()).build());
             return;
         }
@@ -69,10 +56,9 @@ public class LinkCollectWorker implements Runnable {
             Thread.sleep(10);
 
             String queryId = "findLinkCollect" + clctSystCd;
-
             MappedStatement mappedStatement = sqlSessionFactory.getConfiguration().getMappedStatement(queryId);
             if (mappedStatement == null) {
-                log.error("[COLLECT] LinkCollectWorker:run----: [{}], {}, queryId is not found.", this.clctSystCd, queryId);
+                log.error("[COLLECT] LinkTrafDeleteWorker.run: [{}], {}, {}, queryId is not found.", this.clctSystCd, jobType, queryId);
                 this.mapData.put(this.clctSystCd, LinkCollectResultDto.builder().clctSystCd(this.clctSystCd).lists(new ArrayList<>()).build());
                 return;
             }
@@ -85,7 +71,7 @@ public class LinkCollectWorker implements Runnable {
                 queryResult = sqlSession.selectList(queryId, params);
             }
             catch (Exception e) {
-                log.error("[COLLECT] LinkCollectWorker:collect, Exception: {}, {}, {}", this.clctSystCd, queryId, e.getMessage());
+                log.error("[COLLECT] LinkTrafDeleteWorker.run: Exception: [{}], {}, {}, {}", this.clctSystCd, jobType, queryId, e.getMessage());
             }
             finally {
                 if (sqlSession != null) {
@@ -98,7 +84,7 @@ public class LinkCollectWorker implements Runnable {
             else {
                 resultCount = queryResult.size();
 
-                if (LinkCollectSetupService.PRIO.equals(clctSystCd) || LinkCollectSetupService.PRIOETC.equals(clctSystCd)) {
+                if (LinkTrafCollectSetupService.PRIO.equals(this.clctSystCd) || LinkTrafCollectSetupService.PRIOETC.equals(this.clctSystCd)) {
                     // 우선순위 수집의 경우 LinkId 가 중복될 수 있으므로
                     // 중복된 LinkId 를 제거하기 위해 HashSet 을 사용하여 중복값을 제거
                     List<LinkCollectDto> result = new ArrayList<>();
@@ -116,17 +102,15 @@ public class LinkCollectWorker implements Runnable {
             }
         }
         catch (InterruptedException e) {
-            log.info("[COLLECT] LinkCollectWorker:run----: InterruptedException, [{}], {}, {}.", this.clctSystCd, jobType.getName(), e.getMessage());
+            log.info("[COLLECT] LinkTrafDeleteWorker.run: InterruptedException, [{}], {}, {}.", this.clctSystCd, jobType, e.getMessage());
             this.mapData.put(this.clctSystCd, LinkCollectResultDto.builder().clctSystCd(this.clctSystCd).lists(new ArrayList<>()).build());
         }
         catch (Exception e) {
-            log.info("[COLLECT] LinkCollectWorker:run----: Exception, [{}], {}, {}.", this.clctSystCd, jobType.getName(), e.getMessage());
+            log.info("[COLLECT] LinkTrafDeleteWorker.run: Exception, [{}], {}, {}.", this.clctSystCd, jobType, e.getMessage());
             this.mapData.put(this.clctSystCd, LinkCollectResultDto.builder().clctSystCd(this.clctSystCd).lists(new ArrayList<>()).build());
         }
-        if (jobType != null) {
-            stopWatch.stop();
-            log.info("[COLLECT] LinkCollectWorker:run----: [{}], {}, [{}] EA. {} ms.", this.clctSystCd, jobType.getName(), resultCount, stopWatch.getTotalTimeMillis());
-        }
+        stopWatch.stop();
+        log.info("[COLLECT] LinkTrafDeleteWorker.run: {}: [{} EA. {} ms]", jobType, resultCount, stopWatch.getTotalTimeMillis());
     }
 
 }

+ 18 - 0
utic-ptis-server/src/main/resources/mybatis/mapper/utic/DeleteMapper.xml

@@ -0,0 +1,18 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
+
+<mapper namespace="com.utic.ptis.server.dao.mapper.utic.DeleteMapper">
+
+    <delete id="deleteTrafficCenter">
+    <![CDATA[
+        DELETE FROM TRAFFIC_CENTER
+        ]]>
+    </delete>
+
+    <delete id="deleteTrafficCenterExt">
+    <![CDATA[
+        DELETE FROM TRAFFIC_CENTER
+        ]]>
+    </delete>
+
+</mapper>