shjung 1 tahun lalu
induk
melakukan
32d0db700f

TEMPAT SAMPAH
app-install/agip-comm-server.exe.old


+ 2 - 0
app-install/agip-comm-server.txt.jsmooth

@@ -6,6 +6,7 @@
 <JVMSearchPath>registry</JVMSearchPath>
 <JVMSearchPath>exepath</JVMSearchPath>
 <JVMSearchPath>jview</JVMSearchPath>
+<arguments></arguments>
 <currentDirectory>${EXECUTABLEPATH}</currentDirectory>
 <embeddedJar>true</embeddedJar>
 <executableName>agip-comm-server.exe</executableName>
@@ -23,6 +24,7 @@
 </skeletonProperties>
 <skeletonProperties>
 <key>URL</key>
+<value></value>
 </skeletonProperties>
 <skeletonProperties>
 <key>SingleProcess</key>

+ 3 - 1
conf/debug.properties

@@ -1,3 +1,5 @@
 #system debug setting configuration...
-#Tue Nov 28 11:31:30 KST 2023
+#Thu Dec 14 15:39:14 KST 2023
+packet-info=x
+packet-dump=x
 system-debug=false

+ 13 - 0
src/main/java/com/its/bis/config/ServerConfig.java

@@ -7,6 +7,8 @@ import lombok.extern.slf4j.Slf4j;
 import org.springframework.boot.context.properties.ConfigurationProperties;
 import org.springframework.context.annotation.Configuration;
 
+import javax.annotation.PostConstruct;
+
 @Slf4j
 @Getter
 @Setter
@@ -23,5 +25,16 @@ public class ServerConfig {
     private int maxDistance = 20;   // 노드와의 최대 거리(반지름)
     private int maxTrvlMin = 60;    // 지점간 최대 여행시간
 
+    @PostConstruct
+    private void init() {
+        if (this.maxDistance < 10) {
+            this.maxDistance = 10;
+        }
+        if (this.maxDistance > 50) {
+            this.maxDistance = 50;
+        }
+        log.info("{}", this);
+    }
+
 }
 

+ 1 - 0
src/main/java/com/its/bis/dao/mapper/NodeLinkMapper.java

@@ -10,6 +10,7 @@ import java.util.List;
 public interface NodeLinkMapper {
 
     List<TbNode> selectNodeAll();
+    List<TbNodeRgn> selectNodeRgnAll();
     List<TbLink> selectLinkAll();
 
     int createBisLinkTraf(@Param("obj") MakeTrafParam obj);

+ 35 - 6
src/main/java/com/its/bis/dto/BisObe.java

@@ -24,11 +24,40 @@ public class BisObe  implements Serializable {
 
     private float moveDist;
 
-    private Long stNodeId = 0L;
-    private Long edNodeId = 0L;
-    private int  trvlHh = 0;    // stNodeId ~ edNodeId travel time(seconds)
-
-    private long stNodeTm;
-    private long edNodeTm;
+    private NodeRunDto stNode;
+    private NodeRunDto edNode;
+    private NodeRunDto runNode;
+    private LinkRunDto runLink;
+
+//    private Long stNodeId = 0L;
+//    private Long edNodeId = 0L;
+//    private int  trvlHh = 0;    // stNodeId ~ edNodeId travel time(seconds)
+//
+//    private long stNodeTm;
+//    private long edNodeTm;
+//
+//    private Long runNodeId = 0L;    // 운행중 노드
+//    private long runNodeTm = 0L;    // 운행중 노드 진입시각
+//    private int runNodeWaitTm = 0;  // 운행중 노드 대기시각(진출시각 - 진입시각)
+
+    public void initRunNodeInfo() {
+//        this.runNodeId = 0L;
+//        this.runNodeTm = 0L;
+    }
+
+    public int calTravelTime() {
+        if (this.stNode.isValid() && this.edNode.isValid()) {
+            return 1;
+        }
+        else return 0;
+    }
+
+    public int calNodeWaitTm() {
+        return 0;
+//        if (this.runNodeId != 0L && this.runNodeTm != 0L) {
+//            this.runNodeWaitTm = (int) ((System.currentTimeMillis() - this.runNodeTm) / 1000);
+//        }
+//        return this.runNodeWaitTm;
+    }
 
 }

+ 33 - 0
src/main/java/com/its/bis/dto/LinkRunDto.java

@@ -0,0 +1,33 @@
+package com.its.bis.dto;
+
+import com.fasterxml.jackson.annotation.JsonProperty;
+import io.swagger.annotations.ApiModel;
+import io.swagger.annotations.ApiModelProperty;
+import lombok.Builder;
+import lombok.Data;
+
+import java.io.Serializable;
+
+/**
+ * 링크정보 DTO Class
+ */
+@Data
+@Builder
+@ApiModel("TbLinkDto(링크운행정보)")
+public class LinkRunDto implements Serializable {
+    private static final long serialVersionUID = 1L;
+
+    @ApiModelProperty("링크ID")  // N NUMBER(10)
+    private Long linkId;
+
+    @ApiModelProperty("시작노드ID")  // Y NUMBER(10)
+    private Long fNodeId;
+
+    @ApiModelProperty("종료노드ID")  // Y NUMBER(10)
+    private Long tNodeId;
+
+    @ApiModelProperty("삭제 여부")  // Y CHAR(1)
+    @JsonProperty("trvl_hh")
+    private Integer trvlHh;
+
+}

+ 49 - 0
src/main/java/com/its/bis/dto/NodeRunDto.java

@@ -0,0 +1,49 @@
+package com.its.bis.dto;
+
+import lombok.*;
+
+import java.io.Serializable;
+
+@Getter
+@Setter
+@ToString
+@Builder
+@NoArgsConstructor//(access = AccessLevel.PROTECTED)
+@AllArgsConstructor
+public class NodeRunDto implements Serializable {
+    private static final long serialVersionUID = 1L;
+
+    private Long nodeId = 0L;
+    private long inTime = 0L;
+    private long outTime = 0L;
+    private int waitTm = 0;  // 운행중 노드 대기시각(진출시각 - 진입시각)
+
+    public void init() {
+        this.nodeId = 0L;
+        this.inTime = 0L;
+        this.outTime = 0L;
+        this.waitTm = 0;
+    }
+
+    public void copy(NodeRunDto runDto) {
+        this.nodeId = runDto.getNodeId();
+        this.inTime = runDto.getInTime();
+        this.outTime = runDto.getOutTime();
+        this.waitTm = runDto.getWaitTm();
+    }
+
+    public boolean isValid() {
+        // 노드가 존재하고 노드진입시각이 존재하고 노드진출시각이 존재하여야 한다.
+        return this.nodeId != 0L && this.inTime != 0L && this.outTime != 0L;
+    }
+
+    public void calWaitTm() {
+        if (this.nodeId != 0L && this.inTime != 0L && this.outTime != 0L) {
+            this.waitTm = (int) ((this.outTime - this.inTime) / 1000);
+        }
+        else {
+            this.waitTm = 0;
+        }
+    }
+
+}

+ 2 - 0
src/main/java/com/its/bis/dto/TbNodeDto.java

@@ -21,4 +21,6 @@ public class TbNodeDto implements Serializable {
     private Double xCrdn;
     private Double yCrdn;
 
+    private float bisRadius;    // 노드접근 반경(m)
+
 }

+ 21 - 0
src/main/java/com/its/bis/entity/TbNodeRgn.java

@@ -0,0 +1,21 @@
+package com.its.bis.entity;
+
+import io.swagger.annotations.ApiModel;
+import lombok.Builder;
+import lombok.Data;
+
+import java.io.Serializable;
+
+/**
+ * 노드영역정보 Entity Class
+ */
+@ApiModel("노드영역정보")
+@Data
+@Builder
+public class TbNodeRgn implements Serializable {
+    private static final long serialVersionUID = 1L;
+
+    private Long nodeId;
+    private Integer bisRad;
+
+}

+ 6 - 1
src/main/java/com/its/bis/service/AppRepositoryService.java

@@ -29,7 +29,12 @@ public class AppRepositoryService {
     public ConcurrentMap<Long, TbNodeDto> getNodeMap() {
         return this.nodeMap;
     }
-
+    public ConcurrentMap<Long, TbLinkDto> getLinkMap() {
+        return this.linkMap;
+    }
+    public ConcurrentMap<String, TbLinkDto> getSectMap() {
+        return this.sectMap;
+    }
     public TbNodeDto putNodeMap(TbNodeDto obj) {
         return this.nodeMap.put(obj.getNodeId(), obj);
     }

+ 1 - 0
src/main/java/com/its/bis/service/BisAgipService.java

@@ -5,6 +5,7 @@ import com.its.bis.config.ServerConfig;
 import com.its.bis.config.ThreadPoolInitializer;
 import com.its.bis.dto.TbLinkDto;
 import com.its.bis.process.DbmsDataProcess;
+import com.its.bis.service.worker.BisAgipWorker;
 import lombok.RequiredArgsConstructor;
 import lombok.extern.slf4j.Slf4j;
 import org.slf4j.MDC;

+ 33 - 4
src/main/java/com/its/bis/service/NodeLinkService.java

@@ -9,6 +9,7 @@ import com.its.bis.dto.TbNodeDto;
 import com.its.bis.entity.MakeTrafParam;
 import com.its.bis.entity.TbLink;
 import com.its.bis.entity.TbNode;
+import com.its.bis.entity.TbNodeRgn;
 import com.its.bis.process.DbmsData;
 import com.its.bis.process.DbmsDataProcess;
 import com.its.bis.process.DbmsDataType;
@@ -39,6 +40,7 @@ public class NodeLinkService {
 
     public void loadDb() {
         loadNodeInfo();
+        loadNodeRgnInfo();
         loadLinkInfo();
     }
 
@@ -49,8 +51,9 @@ public class NodeLinkService {
             List<TbNode> infoList  = this.mapper.selectNodeAll();
             log.info("NodeService.loadNodeInfo: {} EA", infoList.size());
             for (TbNode dto : infoList) {
-                log.info("NodeService.loadNodeInfo: {}.", dto);
+//                log.info("NodeService.loadNodeInfo: {}.", dto);
                 TbNodeDto nodeObj = dto.toDto();
+                nodeObj.setBisRadius((float)this.config.getMaxDistance());
                 this.repoService.putNodeMap(nodeObj);
             }
         }
@@ -63,6 +66,32 @@ public class NodeLinkService {
         });
         log.info("NodeService.loadNodeInfo: {} EA, {} ms.", this.repoService.getNodeMap().size(), elapsed.milliSeconds());
     }
+    public void loadNodeRgnInfo() {
+        Elapsed elapsed = new Elapsed();
+
+        try {
+            List<TbNodeRgn> infoList  = this.mapper.selectNodeRgnAll();
+            log.info("NodeService.loadNodeRgnInfo: {} EA", infoList.size());
+            for (TbNodeRgn dto : infoList) {
+                log.info("NodeService.loadNodeRgnInfo: {}.", dto);
+                TbNodeDto nodeObj = this.repoService.getNodeMap().get(dto.getNodeId());
+                if (nodeObj != null) {
+                    if (dto.getBisRad() < 10) {
+                        dto.setBisRad(10);
+                    }
+                    nodeObj.setBisRadius(dto.getBisRad());
+                    if (dto.getBisRad() > this.config.getMaxDistance()) {
+                        this.config.setMaxDistance(dto.getBisRad());
+                    }
+                }
+            }
+        }
+        catch (Exception e) {
+            log.error("NodeService.loadNodeRgnInfo: {}.", e.toString());
+        }
+        log.info("NodeService.loadNodeRgnInfo: {} EA, {} ms.", this.repoService.getNodeMap().size(), elapsed.milliSeconds());
+    }
+
     public void loadLinkInfo() {
         Elapsed elapsed = new Elapsed();
 
@@ -70,7 +99,7 @@ public class NodeLinkService {
             List<TbLink> infoList  = this.mapper.selectLinkAll();
             log.info("NodeService.loadLinkInfo: {} EA", infoList.size());
             for (TbLink dto : infoList) {
-                log.info("NodeService.loadLinkInfo: {}.", dto);
+//                log.info("NodeService.loadLinkInfo: {}.", dto);
                 TbLinkDto linkObj = dto.toDto();
                 this.repoService.putLinkMap(linkObj);
                 this.repoService.putSectMap(linkObj);
@@ -80,10 +109,10 @@ public class NodeLinkService {
             log.error("NodeService.loadLinkInfo: {}.", e.toString());
         }
 
-        this.repoService.getNodeMap().forEach((key, obj) -> {
+        this.repoService.getLinkMap().forEach((key, obj) -> {
             log.info("NodeService.loadLinkInfo:: {}.", obj.toString());
         });
-        log.info("NodeService.loadLinkInfo: {} EA, {} ms.", this.repoService.getNodeMap().size(), elapsed.milliSeconds());
+        log.info("NodeService.loadLinkInfo: LINK: {} EA, SECT: {} EA, {} ms.", this.repoService.getLinkMap().size(), this.repoService.getSectMap().size(), elapsed.milliSeconds());
     }
 
     /**

+ 350 - 0
src/main/java/com/its/bis/service/worker/BisAgipWorker.java

@@ -0,0 +1,350 @@
+package com.its.bis.service.worker;
+
+import com.its.app.utils.Elapsed;
+import com.its.app.utils.SysUtils;
+import com.its.app.utils.TimeUtils;
+import com.its.bis.api.dto.AgipObeLoc;
+import com.its.bis.config.ServerConfig;
+import com.its.bis.dto.*;
+import com.its.bis.entity.TbBisVehLoc;
+import com.its.bis.process.DbmsData;
+import com.its.bis.process.DbmsDataProcess;
+import com.its.bis.process.DbmsDataType;
+import com.its.bis.service.AppRepositoryService;
+import lombok.extern.slf4j.Slf4j;
+import org.slf4j.MDC;
+
+import java.util.Map;
+import java.util.concurrent.LinkedBlockingQueue;
+
+@Slf4j
+public class BisAgipWorker implements Runnable {
+
+    private long avgTime = 0;
+    private int idx;
+    private int qSize;
+
+    private final ServerConfig config;
+    private final AppRepositoryService repoService;
+    private final DbmsDataProcess dbmsDataProcess;
+    private final LinkedBlockingQueue<AgipObeLoc> DATA_QUEUE;
+
+    public BisAgipWorker(int idx, int qSize, ServerConfig config, AppRepositoryService repoService, DbmsDataProcess dbmsDataProcess) {
+        this.idx = idx;
+        this.qSize = qSize;
+        this.config = config;
+        this.repoService = repoService;
+        this.dbmsDataProcess = dbmsDataProcess;
+        this.DATA_QUEUE = new LinkedBlockingQueue<>(qSize);
+    }
+
+    protected long calcProcessTime(long recvTime) {
+        long jobTime = System.nanoTime() - recvTime;
+        if (this.avgTime == 0) {
+            this.avgTime = jobTime;
+        }
+        else {
+            this.avgTime = (this.avgTime + jobTime) / 2L;
+        }
+        return this.avgTime;
+    }
+
+    /*
+     *  작업큐에 데이터 추가
+     */
+    public boolean add(AgipObeLoc obeLoc) {
+        boolean offer = false;
+        try {
+            //offer => full -> return
+            //add   => full -> wait
+            offer = this.DATA_QUEUE.offer(obeLoc);
+            if (!offer) {
+                MDC.put("id", obeLoc.getDeviceId());
+                log.error("Packet Queue.offer: {}/{}, Queue Full: {} EA, {}, {}",
+                        obeLoc.getDeviceId(), this.DATA_QUEUE.size(), this.qSize, TimeUtils.elapsedTime(obeLoc.getRcvNanoSeconds()), Thread.currentThread().getName());
+                MDC.clear();
+            }
+        } catch (Exception e) {
+            MDC.put("id", obeLoc.getDeviceId());
+            log.error("Packet Queue.offer: Exception: {}, {}, {}", obeLoc.getDeviceId(), Thread.currentThread().getName(), e.getMessage());
+            MDC.clear();
+        }
+        return offer;
+    }
+
+    public void process(AgipObeLoc obeLoc) {
+        // 샘플데이터: latitude=36.56392018, longitude=128.74352336
+        Location currLocation = Location.builder()
+                .mDistance(0)
+                .mInitialBearing(0)
+                .mFinalBearing(0)
+                .mLatitude(obeLoc.getGnssInfo().getLongitude())
+                .mLongitude(obeLoc.getGnssInfo().getLatitude())
+//                .mLatitude(obeLoc.getGnssInfo().getLatitude())
+//                .mLongitude(obeLoc.getGnssInfo().getLongitude())
+                .build();
+
+        BisObe bisObe = this.repoService.getObeMap(obeLoc.getDeviceId());
+        if (bisObe == null) {
+            bisObe = BisObe.builder()
+                    .deviceId(obeLoc.getDeviceId())
+                    .carId(obeLoc.getCarId())
+                    .carNumber(obeLoc.getCarNumber())
+                    .location(currLocation)
+                    .moveDist(0)
+                    .stNode(NodeRunDto.builder().nodeId(0L).inTime(0L).outTime(0L).waitTm(0).build())
+                    .edNode(NodeRunDto.builder().nodeId(0L).inTime(0L).outTime(0L).waitTm(0).build())
+                    .runNode(NodeRunDto.builder().nodeId(0L).inTime(0L).outTime(0L).waitTm(0).build())
+                    .runLink(LinkRunDto.builder().linkId(0L).fNodeId(0L).tNodeId(0L).trvlHh(0).build())
+                    .build();
+            this.repoService.putObeMap(bisObe);
+        }
+        else {
+            bisObe.setLocation(currLocation);
+        }
+
+        bisObe.setHeight(obeLoc.getGnssInfo().getHeight());
+        bisObe.setSpeed(obeLoc.getGnssInfo().getSpeed());
+        bisObe.setAngle(obeLoc.getGnssInfo().getAngle());
+
+        MDC.put("id", bisObe.getDeviceId());
+
+        /**************************************************************************************************
+            노드진입1 - 노드1운행 - 노드진출1 ---- 구간 운행중 ---- 노드진입2 - 노드2운행 - 노드진출2
+            BIS 구간 운행시간 = 노드진입2 - 노드진출1
+        ***************************************************************************************************/
+
+        /**
+         * 최근접 통과노드정보를 구한다.
+         */
+        long currSysTime = System.currentTimeMillis();
+        NearNodeDto passNode = getNearNode(currLocation);
+        Long stNodeId = bisObe.getStNode().getNodeId();
+        Long edNodeId = bisObe.getEdNode().getNodeId();
+        Long passNodeId = passNode.getNodeId();
+        if (passNodeId != 0L) {
+            log.info("DEVICE ID: {}, 노드운행: {}", bisObe.getDeviceId(), passNodeId);
+            if (bisObe.getRunNode().getNodeId() == 0L) {
+                // 운행중 노드정보 설정
+                bisObe.getRunNode().setNodeId(passNodeId);
+                bisObe.getRunNode().setInTime(currSysTime);
+                bisObe.getRunNode().setOutTime(currSysTime);
+            } else {
+                // 운행중 노드의 진출시각을 업데이트
+                bisObe.getRunNode().setOutTime(currSysTime);
+            }
+
+            if (stNodeId == 0L) {
+                // 시작노드가 없으면 시작노드 설정
+                bisObe.getStNode().setNodeId(passNodeId);
+                bisObe.getStNode().setInTime(currSysTime);
+                bisObe.getStNode().setOutTime(currSysTime);
+                log.info("DEVICE ID: {}, 시작노드 도착: {}", bisObe.getDeviceId(), passNodeId);
+            } else {
+                if (stNodeId.equals(passNodeId)) {
+                    // 시작노드와 동일한 노드를 운행중
+                    log.info("DEVICE ID: {}, 시작노드 운행중: {}", bisObe.getDeviceId(), passNodeId);
+                    bisObe.getStNode().setOutTime(currSysTime);
+                }
+            }
+        }
+        else {
+            // 근접한 노드를 찾을 수 없을 때...
+            if (bisObe.getRunNode().getNodeId() != 0L) {
+                // 노드운행을 종료(진출)
+                bisObe.getRunNode().setOutTime(currSysTime);
+                bisObe.getRunNode().calWaitTm();    // 노드 대기시간 계산
+                log.info("DEVICE ID: {}, 노드진출: {}, 대기시간: {} sec.", bisObe.getDeviceId(), bisObe.getRunNode().getNodeId(), bisObe.getRunNode().getWaitTm());
+
+                if (bisObe.getStNode().getNodeId().equals(bisObe.getRunNode().getNodeId())) {
+                    bisObe.getStNode().setOutTime(currSysTime);
+                    bisObe.getStNode().calWaitTm();    // 노드 대기시간 계산
+                    log.info("DEVICE ID: {}, 시작노드진출: {}, 대기시간: {} sec.", bisObe.getDeviceId(), bisObe.getStNode().getNodeId(), bisObe.getStNode().getWaitTm());
+                }
+                if (bisObe.getEdNode().getNodeId().equals(bisObe.getRunNode().getNodeId())) {
+                    bisObe.getEdNode().setOutTime(currSysTime);
+                    bisObe.getEdNode().calWaitTm();    // 노드 대기시간 계산
+                    log.info("DEVICE ID: {}, 종료노드진출: {}, 대기시간: {} sec.", bisObe.getDeviceId(), bisObe.getEdNode().getNodeId(), bisObe.getStNode().getWaitTm());
+
+                    bisObe.getStNode().copy(bisObe.getEdNode());
+                    bisObe.getEdNode().init();
+                }
+
+                bisObe.getRunNode().init(); // 운행중 노드 초기화
+            }
+            else {
+                log.info("DEVICE ID: {}, 노선운행 중: {}", bisObe.getDeviceId(), passNodeId);
+            }
+        }
+
+/**
+
+
+            if (bisObe != null) {
+            }
+                else {
+                    if (!stNodeId.equals(passNodeId) && !edNodeId.equals(passNodeId)) {
+                        // 시작노드 값이 존재하면서 통과노드가 시작노드 및 종료노드와 같지 않으면 종료노드로 설정
+                        log.info("DEVICE ID: {}, 종료노드 통과: {}", bisObe.getDeviceId(), passNodeId);
+                        // 종료노드와 같지 않은 경우 종료노드에 도착한 것이므로 구간 소통정보를 생성하자....
+                        bisObe.setEdNodeId(passNodeId);
+                        bisObe.setEdNodeTm(currSysTime);
+                        int travelSec = (int) ((bisObe.getEdNodeTm() - bisObe.getStNodeTm()) / 1000);
+                        if (travelSec > (this.config.getMaxTrvlMin() * 60)) {
+                            // 구간 통과 시간이 설정한 값보다 크기 때문에 통행시간을 계산하지 않는다.
+                            // 현재 통과 노드를 시작노드로 설정한다.
+                            log.warn("DEVICE ID: {}, 시작노드: {}, 종료노드: {}, 여행시간 오류: {} sec.", bisObe.getDeviceId(), bisObe.getStNodeId(), bisObe.getEdNodeId(), travelSec);
+                            bisObe.setStNodeId(bisObe.getEdNodeId());
+                            bisObe.setStNodeTm(bisObe.getEdNodeTm());
+                            bisObe.setEdNodeId(0L);
+                            bisObe.setEdNodeTm(0);
+                        }
+                        else {
+                            TbLinkDto link = this.repoService.getSectMap(bisObe.getStNodeId(), bisObe.getEdNodeId());
+                            if (link == null) {
+                                // 구간을 찾지 못하였음... 종료노드를 시작노드로 설정
+                                log.warn("DEVICE ID: {}, 시작노드: {}, 종료노드: {}, 구간 맷칭 오류...", bisObe.getDeviceId(), bisObe.getStNodeId(), bisObe.getEdNodeId());
+                                bisObe.setStNodeId(bisObe.getEdNodeId());
+                                bisObe.setStNodeTm(bisObe.getEdNodeTm());
+                                bisObe.setEdNodeId(0L);
+                                bisObe.setEdNodeTm(0);
+                            }
+                            else {
+                                // 구간을 통과하였으므로 구간교통정보를 생성한다.
+                                int speed = calcSpeed(link.getLinkLeng(), travelSec);
+                                log.warn("DEVICE ID: {}, 시작노드: {}, 종료노드: {}, 구간통과: {}, {} m, {} km/h, {} seconds.",
+                                        bisObe.getDeviceId(), bisObe.getStNodeId(), bisObe.getEdNodeId(), link.getLinkId(), link.getLinkLeng(), speed, travelSec);
+                                TbBisLinkTrafClct bisLinkTrafClct = TbBisLinkTrafClct.builder()
+                                        .CLCT_DT(SysUtils.getSysTime())
+                                        .LINK_ID(link.getLinkId())
+                                        .DEVICE_ID(bisObe.getDeviceId())
+                                        .SPED(speed)
+                                        .TRVL_HH(travelSec)
+                                        .ST_NODE_ARR_DT(TimeUtils.millisToString(bisObe.getStNodeTm()))
+                                        .ED_NODE_ARR_DT(TimeUtils.millisToString(bisObe.getEdNodeTm()))
+                                        .build();
+
+                                this.dbmsDataProcess.add(new DbmsData(DbmsDataType.DBMS_DATA_CRT_BIS_LINK_TRAF_CLCT, false, bisLinkTrafClct));
+
+                                bisObe.setStNodeId(bisObe.getEdNodeId());
+                                bisObe.setStNodeTm(bisObe.getEdNodeTm());
+                                bisObe.setEdNodeId(0L);
+                                bisObe.setEdNodeTm(0);
+                            }
+                        }
+                    }
+                    else {
+                        log.info("DEVICE ID: {}, 시작노드: {}, 종료노드: {}, 통과노드: {}", bisObe.getDeviceId(), stNodeId, edNodeId, passNodeId);
+                    }
+                }
+            }
+        }
+        else {
+        log.info("DEVICE ID: {}, 노선운행: {}", bisObe.getDeviceId(), passNodeId);
+            if (bisObe.getRunNodeId() != 0L) {
+                int nodeWaitTm = bisObe.calNodeWaitTm();
+                log.info("DEVICE ID: {}, 운행노드: {}, 대기시간: {} sec, 통과....", bisObe.getDeviceId(), bisObe.getRunNodeId(), nodeWaitTm);
+                bisObe.initRunNodeInfo();   // 운행중 노드 정보를 초기화 한다.
+            }
+
+            if (stNodeId != 0 && edNodeId != 0) {
+                // 시작노드와 종료노드가 설정된 상태에서 이번에 아무런 노드정보가 없으므로 노드를 빠져 나온것이므로
+                // 종료노드를 시작노드로 설정하고 종료노드는 0으로 설정한다.
+                // 노드 통과 후 구간 정보를 생성하기 위해서는 여기서 처리
+                log.info("DEVICE ID: {}, 시작노드: {}, 종료노드: {}, 통과노드: {}", bisObe.getDeviceId(), stNodeId, edNodeId, passNodeId);
+                bisObe.setStNodeId(edNodeId);
+                bisObe.setStNodeTm(currSysTime);
+                // 종료노드 초기화
+                bisObe.setEdNodeId(0L);
+                bisObe.setEdNodeTm(0);
+            }
+            else {
+                log.info("DEVICE ID: {}, 시작노드: {}, 종료노드: {}, 통과노드: {}, 구간 운행 중...", bisObe.getDeviceId(), stNodeId, edNodeId, passNodeId);
+            }
+        }
+**/
+        MDC.remove(bisObe.getDeviceId());
+        MDC.clear();
+
+        /**
+         * 버스 현재위치 정보를 업데이트 한다.
+         */
+        TbBisVehLoc bisVehLoc = TbBisVehLoc.builder()
+                .DEVICE_ID(bisObe.getDeviceId())
+                .CLCT_DT(SysUtils.getSysTime())
+                .LOC_TYPE(obeLoc.getGnssInfo().getType())
+                .SPEED(obeLoc.getGnssInfo().getSpeed())
+                .HEGT(obeLoc.getGnssInfo().getHeight())
+                .ANGLE(obeLoc.getGnssInfo().getAngle())
+                .LNG(obeLoc.getGnssInfo().getLongitude())
+                .LAT(obeLoc.getGnssInfo().getLatitude())
+                .PASS_NODE_ID(passNodeId)
+                .build();
+        this.dbmsDataProcess.add(new DbmsData(DbmsDataType.DBMS_DATA_UPD_BIS_VEH_LOC, false, bisVehLoc));
+    }
+
+    public void report() {
+        long avgTime = 0;
+        log.info("Packet: Remain Q: {}, Average: {}, {}", this.DATA_QUEUE.size(), TimeUtils.elapsedTimeStr(avgTime), Thread.currentThread().getName());
+    }
+
+    public int calcSpeed(int distance, int seconds) {
+        int speed;
+        if (distance <= 0 || seconds <= 0) {
+            return 2;
+        }
+        speed = (int)(((distance * 3.6) / (float)seconds) + 0.5);
+        return speed;
+    }
+
+    public NearNodeDto getNearNode(Location loc) {
+        Elapsed elapsed = new Elapsed();
+        //Location(mDistance=0.0, mInitialBearing=0.0, mFinalBearing=0.0, mLatitude=128.73881251, mLongitude=36.56128759)
+        double maxDistance = this.config.getMaxDistance()+1.;
+        NearNodeDto nearNode = NearNodeDto.builder().nodeId(0L).distance(maxDistance).build();
+        for (Map.Entry<Long, TbNodeDto> e : this.repoService.getEntrySetNode()) {
+            TbNodeDto node = e.getValue();
+            double fDistance = (float) getDistance(loc.getMLatitude(), loc.getMLongitude(), node.getXCrdn(), node.getYCrdn());
+            if (fDistance < node.getBisRadius()) {
+                // 노드영역 안에 위치하고 있음....
+                if (maxDistance > fDistance) {
+                    // 혹시 모를 최근접 노드를 확인....
+                    maxDistance = fDistance;
+                    nearNode.setNodeId(node.getNodeId());
+                    nearNode.setDistance(fDistance);
+                }
+            }
+        }
+        log.info("getNearNode: {} ms. {} m, {}", elapsed.milliSeconds(), maxDistance, nearNode);
+        return nearNode;
+    }
+
+    public double getDistance(double lat1, double lon1, double lat2, double lon2) {
+        double EARTH_RADIUS = 6371.0;
+        double dLat = Math.toRadians(lat2 - lat1);
+        double dLon = Math.toRadians(lon2 - lon1);
+
+        double a = Math.sin(dLat/2)* Math.sin(dLat/2)+ Math.cos(Math.toRadians(lat1))* Math.cos(Math.toRadians(lat2))* Math.sin(dLon/2)* Math.sin(dLon/2);
+        double c = 2 * Math.atan2(Math.sqrt(a), Math.sqrt(1-a));
+        return (EARTH_RADIUS * c * 1000);    // Distance in m
+    }
+
+    @Override
+    public void run() {
+        log.info("{} Start. Q_SIZE: {}", Thread.currentThread().getName(), this.qSize);
+        while (true) {
+            try {
+                AgipObeLoc obeLoc = this.DATA_QUEUE.take();
+                if (obeLoc != null) {
+                    process(obeLoc);
+                }
+                else {
+                    Thread.yield();
+                }
+            }
+            catch (Exception e) {
+                log.error("Exception: {}", e.getMessage());
+            }
+        }
+    }
+}

+ 16 - 3
src/main/java/com/its/bis/service/BisAgipWorker.java → src/main/java/com/its/bis/service/worker/BisAgipWorkerBackup.java

@@ -1,4 +1,4 @@
-package com.its.bis.service;
+package com.its.bis.service.worker;
 
 import com.its.app.utils.Elapsed;
 import com.its.app.utils.SysUtils;
@@ -11,6 +11,7 @@ import com.its.bis.entity.TbBisVehLoc;
 import com.its.bis.process.DbmsData;
 import com.its.bis.process.DbmsDataProcess;
 import com.its.bis.process.DbmsDataType;
+import com.its.bis.service.AppRepositoryService;
 import lombok.extern.slf4j.Slf4j;
 import org.slf4j.MDC;
 
@@ -18,7 +19,7 @@ import java.util.Map;
 import java.util.concurrent.LinkedBlockingQueue;
 
 @Slf4j
-public class BisAgipWorker implements Runnable {
+public class BisAgipWorkerBackup implements Runnable {
 
     private long avgTime = 0;
     private int idx;
@@ -29,7 +30,7 @@ public class BisAgipWorker implements Runnable {
     private final DbmsDataProcess dbmsDataProcess;
     private final LinkedBlockingQueue<AgipObeLoc> DATA_QUEUE;
 
-    public BisAgipWorker(int idx, int qSize, ServerConfig config, AppRepositoryService repoService, DbmsDataProcess dbmsDataProcess) {
+    public BisAgipWorkerBackup(int idx, int qSize, ServerConfig config, AppRepositoryService repoService, DbmsDataProcess dbmsDataProcess) {
         this.idx = idx;
         this.qSize = qSize;
         this.config = config;
@@ -109,6 +110,8 @@ public class BisAgipWorker implements Runnable {
         bisObe.setSpeed(obeLoc.getGnssInfo().getSpeed());
         bisObe.setAngle(obeLoc.getGnssInfo().getAngle());
 
+        MDC.put("id", bisObe.getDeviceId());
+
         /**
          * 최근접 통과노드정보를 구한다.
          */
@@ -181,9 +184,16 @@ public class BisAgipWorker implements Runnable {
             }
         }
         else {
+            if (bisObe.getRunNodeId() != 0L) {
+                int nodeWaitTm = bisObe.calNodeWaitTm();
+                log.info("DEVICE ID: {}, 운행노드: {}, 대기시간: {} sec, 통과....", bisObe.getDeviceId(), bisObe.getRunNodeId(), nodeWaitTm);
+                bisObe.initRunNodeInfo();   // 운행중 노드 정보를 초기화 한다.
+            }
+
             if (stNodeId != 0 && edNodeId != 0) {
                 // 시작노드와 종료노드가 설정된 상태에서 이번에 아무런 노드정보가 없으므로 노드를 빠져 나온것이므로
                 // 종료노드를 시작노드로 설정하고 종료노드는 0으로 설정한다.
+                // 노드 통과 후 구간 정보를 생성하기 위해서는 여기서 처리
                 log.info("DEVICE ID: {}, 시작노드: {}, 종료노드: {}, 통과노드: {}", bisObe.getDeviceId(), stNodeId, edNodeId, passNodeId);
                 bisObe.setStNodeId(edNodeId);
                 bisObe.setStNodeTm(System.currentTimeMillis());
@@ -196,6 +206,9 @@ public class BisAgipWorker implements Runnable {
             }
         }
 
+        MDC.remove(bisObe.getDeviceId());
+        MDC.clear();
+
         /**
          * 버스 현재위치 정보를 업데이트 한다.
          */

+ 22 - 0
src/main/resources/logback-spring-appender.xml

@@ -29,6 +29,28 @@
         </sift>
     </appender>
 
+    <appender name="BUS_PACKET" class="ch.qos.logback.classic.sift.SiftingAppender">
+        <discriminator>
+            <key>id</key>
+            <defaultValue>${LOG_FILE_NAME_BUS}</defaultValue>
+        </discriminator>
+        <sift>
+            <appender name="BUS-${id}" class="ch.qos.logback.core.rolling.RollingFileAppender">
+                <file>${LOG_PATH}bus/${id}.log</file>
+                <encoder class="ch.qos.logback.classic.encoder.PatternLayoutEncoder">
+                    <charset>${LOG_CHARSET}</charset>
+                    <Pattern>${LOG_PATTERN_PACKET}</Pattern>
+                </encoder>
+
+                <rollingPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedRollingPolicy">
+                    <FileNamePattern>${LOG_BACKUP_PATH}bus/${id}.${LOG_FILE_NAME_PATTERN}</FileNamePattern>
+                    <maxFileSize>${MAX_FILESIZE}</maxFileSize>
+                    <maxHistory>${MAX_HISTORY}</maxHistory>
+                </rollingPolicy>
+            </appender>
+        </sift>
+    </appender>
+
     <appender name="FILE_LOG" class="ch.qos.logback.core.rolling.RollingFileAppender">
         <file>${LOG_PATH}${LOG_FILE_NAME}</file>
         <encoder class="ch.qos.logback.classic.encoder.PatternLayoutEncoder">

+ 7 - 1
src/main/resources/logback-spring.xml

@@ -3,7 +3,7 @@
     <shutdownHook class="ch.qos.logback.core.hook.DelayingShutdownHook"/>
 
     <property name="APP_CLASS_PATH"  value="com.its.bis"/>
-    <property name="PROJECT_PREFIX"  value="vms"/>
+    <property name="PROJECT_PREFIX"  value="agip"/>
     <property name="PROJECT_NAME"    value="${PROJECT_PREFIX}-comm-server"/>
     <property name="ROOT_LOG_LEVEL"  value="INFO"/>
     <property name="LOG_CHARSET"     value="UTF-8" />
@@ -14,6 +14,7 @@
     <property name="LOG_FILE_NAME_ERROR"       value="${PROJECT_NAME}.err.log"/>
     <property name="LOG_FILE_NAME_PATTERN"     value="%d{yyyyMMdd}_%i.log.gz"/>
     <property name="LOG_FILE_NAME_PACKET"      value="${PROJECT_PREFIX}-packet"/>
+    <property name="LOG_FILE_NAME_BUS"         value="${PROJECT_PREFIX}-bus"/>
     <property name="LOG_FILE_NAME_SESSION"     value="${PROJECT_PREFIX}-session.log"/>
     <property name="LOG_FILE_NAME_CENTER_COMM" value="${PROJECT_PREFIX}-center-comm.log"/>
     <property name="LOG_FILE_NAME_SQL"         value="${PROJECT_PREFIX}-sql.log"/>
@@ -48,6 +49,11 @@
         <appender-ref ref="FILE_ERROR"/>
     </logger>
 
+    <logger name="${APP_CLASS_PATH}.service.worker" level="INFO" additivity="false">
+        <appender-ref ref="BUS_PACKET"/>
+        <appender-ref ref="FILE_ERROR"/>
+    </logger>
+
     <logger name="${APP_CLASS_PATH}.xnetudp" level="INFO" additivity="false">
         <appender-ref ref="CONSOLE"/>
         <appender-ref ref="CENTER_COMM"/>

+ 8 - 0
src/main/resources/mybatis/mapper/NodeLinkMapper.xml

@@ -16,6 +16,14 @@
         ]]>
     </select>
 
+    <select id="selectNodeRgnAll" resultType="com.its.bis.entity.TbNodeRgn" fetchSize="1000">
+    <![CDATA[
+        SELECT A.NODE_ID,
+               A.BIS_RAD
+        FROM TB_NODE_RGN A
+        ]]>
+    </select>
+
     <select id="selectLinkAll" resultType="com.its.bis.entity.TbLink" fetchSize="1000">
     <![CDATA[
         SELECT A.LINK_ID,

+ 3 - 4
src/test/java/com/its/app/AgipCommServerApplicationTests.java

@@ -249,7 +249,6 @@ public class AgipCommServerApplicationTests {
 //        log.info("{}", crc);
     }
 
-//[
 //    {
 //        "tenant": {
 //        "entityStatus": null,
@@ -284,8 +283,8 @@ public class AgipCommServerApplicationTests {
 //                "type": "nmea",
 //                "raw": "$GPGGA,064217.63,3729.1261326,N,12653.6691112,E,1,00,1.0,19.203,M,0.000,M,0.0,*4C\r\n$GNRMC,064217.63,A,3729.1261326,N,12653.6691112,E,1.34,250.29,270421,0.0,E,A,V*5F\r\n$GNVTG,250.29,T,,M,1.339,N,2.480,K,D*2C\r\n$GNGST,064217.63,10,1.000,1.000,1.000,0.700,5.960,8.770*61\r",
 //                "hertz": 0,
-//                "latitude": 37.48543554333333,
-//                "longitude": 126.89448518666667,
+//                "latitude": 36.43776988,
+//                "longitude": 128.83885507,
 //                "height": 19.203,
 //                "speed": 2.48,
 //                "angle": 250.29,
@@ -324,6 +323,6 @@ public class AgipCommServerApplicationTests {
 //            "routeId": null,
 //            "runStatus": null
 //    }
-//]
+
 
 }