Ver código fonte

first commit

shjung 2 anos atrás
commit
a3e3fee647
100 arquivos alterados com 8691 adições e 0 exclusões
  1. 46 0
      .gitignore
  2. 118 0
      .mvn/wrapper/MavenWrapperDownloader.java
  3. 2 0
      .mvn/wrapper/maven-wrapper.properties
  4. BIN
      app-install/application.png
  5. 43 0
      app-install/dsrc-comm-server.txt.jsmooth
  6. 212 0
      conf/vms-comm-server-logback.xml
  7. 72 0
      conf/vms-comm-server.properties
  8. 322 0
      mvnw
  9. 182 0
      mvnw.cmd
  10. 230 0
      pom.xml
  11. 3 0
      src/main/java/META-INF/MANIFEST.MF
  12. 31 0
      src/main/java/com/its/app/AppUtils.java
  13. 35 0
      src/main/java/com/its/app/ApplicationContextProvider.java
  14. 39 0
      src/main/java/com/its/app/utils/BcdConverter.java
  15. 312 0
      src/main/java/com/its/app/utils/ByteUtils.java
  16. 22 0
      src/main/java/com/its/app/utils/Elapsed.java
  17. 535 0
      src/main/java/com/its/app/utils/FloodFill.java
  18. 39 0
      src/main/java/com/its/app/utils/IOUtils.java
  19. 392 0
      src/main/java/com/its/app/utils/ItsUtils.java
  20. 246 0
      src/main/java/com/its/app/utils/NettyUtils.java
  21. 8 0
      src/main/java/com/its/app/utils/OS.java
  22. 26 0
      src/main/java/com/its/app/utils/Ping.java
  23. 301 0
      src/main/java/com/its/app/utils/StatisticsTime.java
  24. 20 0
      src/main/java/com/its/app/utils/StringUtils.java
  25. 250 0
      src/main/java/com/its/app/utils/SysUtils.java
  26. 216 0
      src/main/java/com/its/app/utils/TimeUtils.java
  27. 210 0
      src/main/java/com/its/vms/VmsCommServerApplication.java
  28. 123 0
      src/main/java/com/its/vms/config/ApplicationConfig.java
  29. 83 0
      src/main/java/com/its/vms/config/CommunicationConfig.java
  30. 73 0
      src/main/java/com/its/vms/config/DatabaseConfig.java
  31. 55 0
      src/main/java/com/its/vms/config/SwaggerConfig.java
  32. 102 0
      src/main/java/com/its/vms/config/ThreadPoolInitializer.java
  33. 133 0
      src/main/java/com/its/vms/dao/mapper/BatchDaoService.java
  34. 12 0
      src/main/java/com/its/vms/dao/mapper/RseObuClctMapper.java
  35. 21 0
      src/main/java/com/its/vms/dao/mapper/RseOffrSectMapper.java
  36. 18 0
      src/main/java/com/its/vms/dao/mapper/RseSectMapper.java
  37. 13 0
      src/main/java/com/its/vms/dao/mapper/RseStatMapper.java
  38. 16 0
      src/main/java/com/its/vms/dao/mapper/UnitSystMapper.java
  39. 12 0
      src/main/java/com/its/vms/dao/mapper/VmsAtmpMapper.java
  40. 26 0
      src/main/java/com/its/vms/dao/mapper/VmsCtlrMapper.java
  41. 14 0
      src/main/java/com/its/vms/dao/mapper/VmsFontMapper.java
  42. 14 0
      src/main/java/com/its/vms/dao/mapper/VmsIfscMapper.java
  43. 14 0
      src/main/java/com/its/vms/dao/mapper/VmsSymbMapper.java
  44. 98 0
      src/main/java/com/its/vms/dao/mapper/batch/VmsCtlrDao.java
  45. 7 0
      src/main/java/com/its/vms/dto/NET.java
  46. 75 0
      src/main/java/com/its/vms/dto/TbVmsAtmpDto.java
  47. 145 0
      src/main/java/com/its/vms/dto/TbVmsCtlrDto.java
  48. 86 0
      src/main/java/com/its/vms/dto/TbVmsCtlrSttsDto.java
  49. 32 0
      src/main/java/com/its/vms/dto/TbVmsFontColrDto.java
  50. 30 0
      src/main/java/com/its/vms/dto/TbVmsFontNameDto.java
  51. 69 0
      src/main/java/com/its/vms/dto/TbVmsIfscTrafDto.java
  52. 52 0
      src/main/java/com/its/vms/dto/TbVmsRltnIfscDto.java
  53. 36 0
      src/main/java/com/its/vms/dto/TbVmsSymbIfscDto.java
  54. 96 0
      src/main/java/com/its/vms/dto/TbVmsSymbLibDto.java
  55. 15 0
      src/main/java/com/its/vms/dto/voDsrcObuPassInfo.java
  56. 19 0
      src/main/java/com/its/vms/dto/voDsrcOffrSectTraf.java
  57. 26 0
      src/main/java/com/its/vms/dto/voStatisticsTime.java
  58. 26 0
      src/main/java/com/its/vms/entity/TbRseCtlrCnncHs.java
  59. 18 0
      src/main/java/com/its/vms/entity/TbRseCtrlHs.java
  60. 18 0
      src/main/java/com/its/vms/entity/TbRseObuClct.java
  61. 15 0
      src/main/java/com/its/vms/entity/TbRseObuNonCrypt.java
  62. 15 0
      src/main/java/com/its/vms/entity/TbRseOffrDrct.java
  63. 18 0
      src/main/java/com/its/vms/entity/TbRseOffrSect.java
  64. 16 0
      src/main/java/com/its/vms/entity/TbRseOffrSectTraf.java
  65. 27 0
      src/main/java/com/its/vms/entity/TbRseSect.java
  66. 16 0
      src/main/java/com/its/vms/entity/TbRseSectPassHs.java
  67. 16 0
      src/main/java/com/its/vms/entity/TbRseSectTraf.java
  68. 22 0
      src/main/java/com/its/vms/entity/TbUnitSyst.java
  69. 17 0
      src/main/java/com/its/vms/entity/TbUnitSystStts.java
  70. 183 0
      src/main/java/com/its/vms/entity/TbVmsAtmp.java
  71. 358 0
      src/main/java/com/its/vms/entity/TbVmsCtlr.java
  72. 26 0
      src/main/java/com/its/vms/entity/TbVmsFontColr.java
  73. 25 0
      src/main/java/com/its/vms/entity/TbVmsFontName.java
  74. 40 0
      src/main/java/com/its/vms/entity/TbVmsIfsc.java
  75. 36 0
      src/main/java/com/its/vms/entity/TbVmsIfscTraf.java
  76. 28 0
      src/main/java/com/its/vms/entity/TbVmsRltnIfsc.java
  77. 30 0
      src/main/java/com/its/vms/entity/TbVmsSymbIfsc.java
  78. 104 0
      src/main/java/com/its/vms/entity/TbVmsSymbLib.java
  79. 44 0
      src/main/java/com/its/vms/entity/eVmsImageType.java
  80. 67 0
      src/main/java/com/its/vms/global/AppRepository.java
  81. 20 0
      src/main/java/com/its/vms/process/DbmsData.java
  82. 16 0
      src/main/java/com/its/vms/process/DbmsDataAsyncTask.java
  83. 152 0
      src/main/java/com/its/vms/process/DbmsDataProcess.java
  84. 15 0
      src/main/java/com/its/vms/process/DbmsDataType.java
  85. 112 0
      src/main/java/com/its/vms/scheduler/SchedulerTask.java
  86. 116 0
      src/main/java/com/its/vms/service/MultimediaService.java
  87. 87 0
      src/main/java/com/its/vms/service/RseObuClctService.java
  88. 456 0
      src/main/java/com/its/vms/service/RseSectService.java
  89. 98 0
      src/main/java/com/its/vms/service/StatisticsServices.java
  90. 132 0
      src/main/java/com/its/vms/service/UnitSystService.java
  91. 85 0
      src/main/java/com/its/vms/service/VmsAtmpService.java
  92. 160 0
      src/main/java/com/its/vms/service/VmsCtlrService.java
  93. 58 0
      src/main/java/com/its/vms/service/VmsFontService.java
  94. 87 0
      src/main/java/com/its/vms/service/VmsIfscService.java
  95. 16 0
      src/main/java/com/its/vms/service/VmsPrcsService.java
  96. 192 0
      src/main/java/com/its/vms/service/VmsSymbService.java
  97. 33 0
      src/main/java/com/its/vms/ui/CtlrSttsDetlTableCellRenderer.java
  98. 32 0
      src/main/java/com/its/vms/ui/CtlrSttsTableCellRenderer.java
  99. 162 0
      src/main/java/com/its/vms/ui/CtlrSttsTableModel.java
  100. 70 0
      src/main/java/com/its/vms/ui/JTextAreaOutputStream.java

+ 46 - 0
.gitignore

@@ -0,0 +1,46 @@
+HELP.md
+target/
+!.mvn/wrapper/maven-wrapper.jar
+!**/src/main/**/target/
+!**/src/test/**/target/
+
+### LOG ###
+/logs/
+/images/
+/fonts/
+/REAL-RUN/
+
+### STS ###
+.apt_generated
+.classpath
+.factorypath
+.project
+.settings
+.springBeans
+.sts4-cache
+
+### IntelliJ IDEA ###
+.idea
+*.iws
+*.iml
+*.ipr
+*.jar
+*.exe
+
+
+### NetBeans ###
+/nbproject/private/
+/nbbuild/
+/dist/
+/nbdist/
+/.nb-gradle/
+build/
+!**/src/main/**/build/
+!**/src/test/**/build/
+
+### VS Code ###
+.vscode/
+
+*.exe
+*.jar
+*.run

+ 118 - 0
.mvn/wrapper/MavenWrapperDownloader.java

@@ -0,0 +1,118 @@
+/*
+ * Copyright 2007-present the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      https://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+import java.net.*;
+import java.io.*;
+import java.nio.channels.*;
+import java.util.Properties;
+
+public class MavenWrapperDownloader {
+
+    private static final String WRAPPER_VERSION = "0.5.6";
+    /**
+     * Default URL to download the maven-wrapper.jar from, if no 'downloadUrl' is provided.
+     */
+    private static final String DEFAULT_DOWNLOAD_URL = "https://repo.maven.apache.org/maven2/io/takari/maven-wrapper/"
+            + WRAPPER_VERSION + "/maven-wrapper-" + WRAPPER_VERSION + ".jar";
+
+    /**
+     * Path to the maven-wrapper.properties file, which might contain a downloadUrl property to
+     * use instead of the default one.
+     */
+    private static final String MAVEN_WRAPPER_PROPERTIES_PATH =
+            ".mvn/wrapper/maven-wrapper.properties";
+
+    /**
+     * Path where the maven-wrapper.jar will be saved to.
+     */
+    private static final String MAVEN_WRAPPER_JAR_PATH =
+            ".mvn/wrapper/maven-wrapper.jar";
+
+    /**
+     * Name of the property which should be used to override the default download url for the wrapper.
+     */
+    private static final String PROPERTY_NAME_WRAPPER_URL = "wrapperUrl";
+
+    public static void main(String args[]) {
+        System.out.println("- Downloader started");
+        File baseDirectory = new File(args[0]);
+        System.out.println("- Using base directory: " + baseDirectory.getAbsolutePath());
+
+        // If the maven-wrapper.properties exists, read it and check if it contains a custom
+        // wrapperUrl parameter.
+        File mavenWrapperPropertyFile = new File(baseDirectory, MAVEN_WRAPPER_PROPERTIES_PATH);
+        String url = DEFAULT_DOWNLOAD_URL;
+        if (mavenWrapperPropertyFile.exists()) {
+            FileInputStream mavenWrapperPropertyFileInputStream = null;
+            try {
+                mavenWrapperPropertyFileInputStream = new FileInputStream(mavenWrapperPropertyFile);
+                Properties mavenWrapperProperties = new Properties();
+                mavenWrapperProperties.load(mavenWrapperPropertyFileInputStream);
+                url = mavenWrapperProperties.getProperty(PROPERTY_NAME_WRAPPER_URL, url);
+            } catch (IOException e) {
+                System.out.println("- ERROR loading '" + MAVEN_WRAPPER_PROPERTIES_PATH + "'");
+            } finally {
+                try {
+                    if (mavenWrapperPropertyFileInputStream != null) {
+                        mavenWrapperPropertyFileInputStream.close();
+                    }
+                } catch (IOException e) {
+                    // Ignore ...
+                }
+            }
+        }
+        System.out.println("- Downloading from: " + url);
+
+        File outputFile = new File(baseDirectory.getAbsolutePath(), MAVEN_WRAPPER_JAR_PATH);
+        if (!outputFile.getParentFile().exists()) {
+            if (!outputFile.getParentFile().mkdirs()) {
+                System.out.println(
+                        "- ERROR creating output directory '" + outputFile.getParentFile().getAbsolutePath() + "'");
+            }
+        }
+        System.out.println("- Downloading to: " + outputFile.getAbsolutePath());
+        try {
+            downloadFileFromURL(url, outputFile);
+            System.out.println("Done");
+            System.exit(0);
+        } catch (Throwable e) {
+            System.out.println("- Error downloading");
+            e.printStackTrace();
+            System.exit(1);
+        }
+    }
+
+    private static void downloadFileFromURL(String urlString, File destination) throws Exception {
+        if (System.getenv("MVNW_USERNAME") != null && System.getenv("MVNW_PASSWORD") != null) {
+            String username = System.getenv("MVNW_USERNAME");
+            char[] password = System.getenv("MVNW_PASSWORD").toCharArray();
+            Authenticator.setDefault(new Authenticator() {
+                @Override
+                protected PasswordAuthentication getPasswordAuthentication() {
+                    return new PasswordAuthentication(username, password);
+                }
+            });
+        }
+        URL website = new URL(urlString);
+        ReadableByteChannel rbc;
+        rbc = Channels.newChannel(website.openStream());
+        FileOutputStream fos = new FileOutputStream(destination);
+        fos.getChannel().transferFrom(rbc, 0, Long.MAX_VALUE);
+        fos.close();
+        rbc.close();
+    }
+
+}

+ 2 - 0
.mvn/wrapper/maven-wrapper.properties

@@ -0,0 +1,2 @@
+distributionUrl=https://repo.maven.apache.org/maven2/org/apache/maven/apache-maven/3.6.3/apache-maven-3.6.3-bin.zip
+wrapperUrl=https://repo.maven.apache.org/maven2/io/takari/maven-wrapper/0.5.6/maven-wrapper-0.5.6.jar

BIN
app-install/application.png


+ 43 - 0
app-install/dsrc-comm-server.txt.jsmooth

@@ -0,0 +1,43 @@
+<?xml version="1.0" encoding="ISO-8859-1"?>
+<jsmoothproject>
+<JVMSearchPath>javahome</JVMSearchPath>
+<JVMSearchPath>jrepath</JVMSearchPath>
+<JVMSearchPath>jdkpath</JVMSearchPath>
+<JVMSearchPath>registry</JVMSearchPath>
+<JVMSearchPath>exepath</JVMSearchPath>
+<JVMSearchPath>jview</JVMSearchPath>
+<currentDirectory>${EXECUTABLEPATH}</currentDirectory>
+<embeddedJar>true</embeddedJar>
+<executableName>vms-comm-server.exe</executableName>
+<iconLocation>application.png</iconLocation>
+<initialMemoryHeap>-1</initialMemoryHeap>
+<jarLocation>vms-comm-server-0.0.1.jar</jarLocation>
+<mainClassName>org.springframework.boot.loader.JarLauncher</mainClassName>
+<maximumMemoryHeap>-1</maximumMemoryHeap>
+<maximumVersion></maximumVersion>
+<minimumVersion>1.8</minimumVersion>
+<skeletonName>Windowed Wrapper</skeletonName>
+<skeletonProperties>
+<key>Message</key>
+<value>Java has not been found on your computer. Do you want to download it?</value>
+</skeletonProperties>
+<skeletonProperties>
+<key>URL</key>
+</skeletonProperties>
+<skeletonProperties>
+<key>SingleProcess</key>
+<value>0</value>
+</skeletonProperties>
+<skeletonProperties>
+<key>SingleInstance</key>
+<value>0</value>
+</skeletonProperties>
+<skeletonProperties>
+<key>JniSmooth</key>
+<value>0</value>
+</skeletonProperties>
+<skeletonProperties>
+<key>Debug</key>
+<value>0</value>
+</skeletonProperties>
+</jsmoothproject>

+ 212 - 0
conf/vms-comm-server-logback.xml

@@ -0,0 +1,212 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<configuration scan="true" scanPeriod="60 seconds">
+    <shutdownHook class="ch.qos.logback.core.hook.DelayingShutdownHook"/>
+
+    <property name="PROJECT_NAME"    value="vms-comm-server"/>
+    <property name="ROOT_LOG_LEVEL"  value="INFO"/>
+    <property name="LOG_CHARSET"     value="UTF-8" />
+    <property name="LOG_PATH"        value="${user.dir}/logs/"/>
+    <property name="LOG_BACKUP_PATH" value="${user.dir}/logs/backup/"/>
+
+    <property name="LOG_FILE_NAME"             value="${PROJECT_NAME}.log"/>
+    <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="vms-packet"/>
+    <property name="LOG_FILE_NAME_SESSION"     value="vms-session.log"/>
+    <property name="LOG_FILE_NAME_CENTER_COMM" value="vms-center-comm.log"/>
+    <property name="LOG_FILE_NAME_SQL"         value="vms-sql.log"/>
+    <property name="LOG_FILE_NAME_SCHEDULE"    value="vms-schedule.log"/>
+    <property name="LOG_FILE_NAME_STATISTICS"  value="vms-statistics.log"/>
+
+    <property name="MAX_FILESIZE" value="10MB"/>
+    <property name="MAX_HISTORY"  value="30"/>
+    <property name="LOG_PATTERN_FILE"        value="[%d{yyyy-MM-dd HH:mm:ss.SSS}] [%-5level] %msg%n"/>
+    <property name="LOG_PATTERN_ERROR"       value="[%d{yyyy-MM-dd HH:mm:ss.SSS}] [%30t] [%5level] %42logger{35}.%-20M ${PID:-} %n%msg%n"/>
+    <property name="LOG_PATTERN_PACKET"      value="[%d{yyyy-MM-dd HH:mm:ss.SSS}] [%-5level] %msg%n"/>
+    <property name="LOG_PATTERN_SESSION"     value="[%d{yyyy-MM-dd HH:mm:ss.SSS}] [%-5level] %msg%n"/>
+    <property name="LOG_PATTERN_CENTER_COMM" value="[%d{yyyy-MM-dd HH:mm:ss.SSS}] [%-5level] %msg%n"/>
+    <property name="LOG_PATTERN_SQL"         value="[%d{yyyy-MM-dd HH:mm:ss.SSS}] [%-5level] %msg%n"/>
+    <property name="LOG_PATTERN_SCHEDULE"    value="[%d{yyyy-MM-dd HH:mm:ss.SSS}] [%-5level] %msg%n"/>
+    <property name="LOG_PATTERN_STATISTICS"  value="[%d{yyyy-MM-dd HH:mm:ss.SSS}] [%-5level] %msg%n"/>
+    <!--<property name="LOG_PATTERN_CONSOLE"     value="%d{HH:mm:ss.SSS} [%30thread] %highlight([%5level]) %cyan(%42logger{35}.%-20M)${PID:-} : %msg%n"/>
+    <property name="LOG_PATTERN_FILE"        value="[%d{yyyy-MM-dd HH:mm:ss.SSS}] [%30t] [%5level] %42logger{35}.%-20M ${PID:-} : %msg%n"/>
+    <property name="LOG_PATTERN_ERROR"       value="[%d{yyyy-MM-dd HH:mm:ss.SSS}] [%30t] [%5level] %42logger{35}.%-20M ${PID:-} : %msg%n"/>
+    <property name="LOG_PATTERN_PACKET"      value="[%d{yyyy-MM-dd HH:mm:ss.SSS}] [%-5level] [%thread] %msg%n"/>
+    <property name="LOG_PATTERN_SESSION"     value="[%d{yyyy-MM-dd HH:mm:ss.SSS}] [%-5level] %msg%n"/>
+    <property name="LOG_PATTERN_CENTER_COMM" value="[%d{yyyy-MM-dd HH:mm:ss.SSS}] [%30t] [%5level] %42logger{35}.%-20M ${PID:-} : %msg%n"/>
+    <property name="LOG_PATTERN_SQL"         value="[%d{yyyy-MM-dd HH:mm:ss.SSS}] [%-5level] [%thread] %msg%n"/>
+    <property name="LOG_PATTERN_SCHEDULE"    value="[%d{yyyy-MM-dd HH:mm:ss.SSS}] [%-5level] [%30thread] %msg%n"/>
+    <property name="LOG_PATTERN_CONSOLE"     value="[%d{HH:mm:ss.SSS}] %highlight([%5level]) %highlight(${PID:-}): %cyan(%msg) [%class{0}.%method] [%thread] %n"/>
+    -->
+    <property name="LOG_PATTERN_CONSOLE" value="[%d{HH:mm:ss.SSS}] %highlight([%5level]) %highlight(${PID:-}): %cyan(%msg) %n"/>
+
+    <appender name="CONSOLE" class="ch.qos.logback.core.ConsoleAppender">
+        <withJansi>true</withJansi>
+        <encoder class="ch.qos.logback.classic.encoder.PatternLayoutEncoder">
+            <pattern>${LOG_PATTERN_CONSOLE}</pattern>
+        </encoder>
+    </appender>
+
+    <appender name="FILE_PACKET" class="ch.qos.logback.classic.sift.SiftingAppender">
+        <discriminator>
+            <key>id</key>
+            <defaultValue>${LOG_FILE_NAME_PACKET}</defaultValue>
+        </discriminator>
+        <sift>
+            <appender name="FILE-${id}" class="ch.qos.logback.core.rolling.RollingFileAppender">
+                <file>${LOG_PATH}packet/${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}packet/${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">
+            <charset>${LOG_CHARSET}</charset>
+            <pattern>${LOG_PATTERN_FILE}</pattern>
+        </encoder>
+        <rollingPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedRollingPolicy">
+            <fileNamePattern>${LOG_BACKUP_PATH}${LOG_FILE_NAME}.${LOG_FILE_NAME_PATTERN}</fileNamePattern>
+            <maxFileSize>${MAX_FILESIZE}</maxFileSize>
+            <maxHistory>${MAX_HISTORY}</maxHistory>
+        </rollingPolicy>
+    </appender>
+
+    <appender name="FILE_ERROR" class="ch.qos.logback.core.rolling.RollingFileAppender">
+        <filter class="ch.qos.logback.classic.filter.LevelFilter">
+            <level>error</level>
+            <onMatch>ACCEPT</onMatch>
+            <onMismatch>DENY</onMismatch>
+        </filter>
+        <file>${LOG_PATH}${LOG_FILE_NAME_ERROR}</file>
+        <encoder class="ch.qos.logback.classic.encoder.PatternLayoutEncoder">
+            <charset>${LOG_CHARSET}</charset>
+            <pattern>${LOG_PATTERN_ERROR}</pattern>
+        </encoder>
+        <rollingPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedRollingPolicy">
+            <fileNamePattern>${LOG_BACKUP_PATH}${LOG_FILE_NAME_ERROR}.%d{yyyy-MM-dd}_%i.log</fileNamePattern>
+            <maxFileSize>${MAX_FILESIZE}</maxFileSize>
+            <maxHistory>${MAX_HISTORY}</maxHistory>
+        </rollingPolicy>
+    </appender>
+
+    <root level="INFO">
+        <appender-ref ref="CONSOLE"/>
+        <appender-ref ref="FILE_LOG"/>
+        <appender-ref ref="FILE_ERROR"/>
+    </root>
+
+    <logger name="com.its.app.xnettcp" level="DEBUG" additivity="false">
+        <appender-ref ref="CONSOLE"/>
+        <appender-ref ref="FILE_PACKET"/>
+        <appender-ref ref="FILE_ERROR"/>
+    </logger>
+
+    <appender name="CENTER_COMM" class="ch.qos.logback.core.rolling.RollingFileAppender">
+        <file>${LOG_PATH}${LOG_FILE_NAME_CENTER_COMM}</file>
+        <encoder class="ch.qos.logback.classic.encoder.PatternLayoutEncoder">
+            <charset>${LOG_CHARSET}</charset>
+            <pattern>${LOG_PATTERN_CENTER_COMM}</pattern>
+        </encoder>
+        <rollingPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedRollingPolicy">
+            <fileNamePattern>${LOG_BACKUP_PATH}CenterComm/${LOG_FILE_NAME_CENTER_COMM}.${LOG_FILE_NAME_PATTERN}</fileNamePattern>
+            <maxFileSize>${MAX_FILESIZE}</maxFileSize>
+            <maxHistory>${MAX_HISTORY}</maxHistory>
+        </rollingPolicy>
+    </appender>
+
+    <logger name="com.its.app.xnetudp" level="DEBUG" additivity="false">
+        <appender-ref ref="CONSOLE"/>
+        <appender-ref ref="CENTER_COMM"/>
+        <appender-ref ref="FILE_ERROR"/>
+    </logger>
+
+    <appender name="FILE_SESSION" class="ch.qos.logback.core.rolling.RollingFileAppender">
+        <file>${LOG_PATH}${LOG_FILE_NAME_SESSION}</file>
+        <encoder class="ch.qos.logback.classic.encoder.PatternLayoutEncoder">
+            <charset>${LOG_CHARSET}</charset>
+            <pattern>${LOG_PATTERN_FILE}</pattern>
+        </encoder>
+        <rollingPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedRollingPolicy">
+            <fileNamePattern>${LOG_BACKUP_PATH}${LOG_FILE_NAME_SESSION}.${LOG_FILE_NAME_PATTERN}</fileNamePattern>
+            <maxFileSize>${MAX_FILESIZE}</maxFileSize>
+            <maxHistory>${MAX_HISTORY}</maxHistory>
+        </rollingPolicy>
+    </appender>
+
+    <logger name="com.its.app.xnettcp.handler" level="DEBUG" additivity="true">
+        <appender-ref ref="CONSOLE"/>
+        <appender-ref ref="FILE_SESSION"/>
+        <appender-ref ref="FILE_ERROR"/>
+    </logger>
+
+    <appender name="FILE_STATISTICS" class="ch.qos.logback.core.rolling.RollingFileAppender">
+        <file>${LOG_PATH}${LOG_FILE_NAME_STATISTICS}</file>
+        <encoder class="ch.qos.logback.classic.encoder.PatternLayoutEncoder">
+            <charset>${LOG_CHARSET}</charset>
+            <pattern>${LOG_PATTERN_STATISTICS}</pattern>
+        </encoder>
+        <rollingPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedRollingPolicy">
+            <fileNamePattern>${LOG_BACKUP_PATH}Schedule/${LOG_FILE_NAME_STATISTICS}.${LOG_FILE_NAME_PATTERN}</fileNamePattern>
+            <maxFileSize>${MAX_FILESIZE}</maxFileSize>
+            <maxHistory>${MAX_HISTORY}</maxHistory>
+        </rollingPolicy>
+    </appender>
+
+    <logger name="com.its.vms.service.StatisticsServices" level="DEBUG" additivity="false">
+        <appender-ref ref="CONSOLE"/>
+        <appender-ref ref="FILE_STATISTICS"/>
+        <appender-ref ref="FILE_ERROR"/>
+    </logger>
+
+    <appender name="FILE_SCHEDULE" class="ch.qos.logback.core.rolling.RollingFileAppender">
+        <file>${LOG_PATH}${LOG_FILE_NAME_SCHEDULE}</file>
+        <encoder class="ch.qos.logback.classic.encoder.PatternLayoutEncoder">
+            <charset>${LOG_CHARSET}</charset>
+            <pattern>${LOG_PATTERN_SCHEDULE}</pattern>
+        </encoder>
+        <rollingPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedRollingPolicy">
+            <fileNamePattern>${LOG_BACKUP_PATH}${LOG_FILE_NAME_SCHEDULE}.${LOG_FILE_NAME_PATTERN}</fileNamePattern>
+            <maxFileSize>${MAX_FILESIZE}</maxFileSize>
+            <maxHistory>${MAX_HISTORY}</maxHistory>
+        </rollingPolicy>
+    </appender>
+
+    <logger name="com.its.app.scheduler" level="DEBUG" additivity="false">
+        <appender-ref ref="CONSOLE"/>
+        <appender-ref ref="FILE_SCHEDULE"/>
+        <appender-ref ref="FILE_ERROR"/>
+    </logger>
+
+    <appender name="FILE_SQL" class="ch.qos.logback.core.rolling.RollingFileAppender">
+        <file>${LOG_PATH}${LOG_FILE_NAME_SQL}</file>
+        <encoder class="ch.qos.logback.classic.encoder.PatternLayoutEncoder">
+            <charset>${LOG_CHARSET}</charset>
+            <pattern>${LOG_PATTERN_SQL}</pattern>
+        </encoder>
+        <rollingPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedRollingPolicy">
+            <fileNamePattern>${LOG_BACKUP_PATH}${LOG_FILE_NAME_SQL}.${LOG_FILE_NAME_PATTERN}</fileNamePattern>
+            <maxFileSize>${MAX_FILESIZE}</maxFileSize>
+            <maxHistory>${MAX_HISTORY}</maxHistory>
+        </rollingPolicy>
+    </appender>
+
+    <logger name="jdbc"                level="OFF"   additivity="false"> <appender-ref ref="FILE_SQL" /> <appender-ref ref="FILE_ERROR"/> </logger>
+    <logger name="jdbc.sqlonly"        level="INFO"  additivity="false"> <appender-ref ref="FILE_SQL" /> <appender-ref ref="FILE_ERROR"/> </logger>
+    <logger name="jdbc.sqltiming"      level="DEBUG" additivity="false"> <appender-ref ref="FILE_SQL" /> <appender-ref ref="FILE_ERROR"/> </logger>
+    <logger name="jdbc.audit"          level="OFF"   additivity="false"> <appender-ref ref="FILE_SQL" /> <appender-ref ref="FILE_ERROR"/> </logger>
+    <logger name="jdbc.resultset"      level="INFO"  additivity="false"> <appender-ref ref="FILE_SQL" /> <appender-ref ref="FILE_ERROR"/> </logger>
+    <logger name="jdbc.resultsettable" level="INFO"  additivity="false"> <appender-ref ref="FILE_SQL" /> <appender-ref ref="FILE_ERROR"/> </logger>
+    <logger name="jdbc.connection"     level="INFO"  additivity="false"> <appender-ref ref="FILE_SQL" /> <appender-ref ref="FILE_ERROR"/> </logger>
+
+</configuration>

+ 72 - 0
conf/vms-comm-server.properties

@@ -0,0 +1,72 @@
+#[logging]
+logging.config=conf//vms-comm-server-logback.xml
+
+#[Application properties]
+process.id=vms01
+process.name=vms Communication Server
+
+#[server config]
+server.user.id=1
+server.user.pswd=1
+server.db.threads=20
+server.data.threads=20
+server.task.statistics=true
+
+#[server <---> operator]
+server.center.bind.port=4602
+server.center.dump=false
+
+#[server <---> controller]
+server.tcp.bind.port=355
+server.tcp.recv.dump=false
+server.tcp.send.dump=false
+server.tcp.allIdleTime=60
+
+#[vms]
+vms.server.authuser=test1
+vms.server.authpassword=test1
+vms.server.senderText=vms Center Unit
+
+#OBU ID 암호화해제 등록요청
+vms.publication.nonCryptObu=true
+#최초 안테나 활성화시 안테나 갯수
+vms.publication.antenna=1
+#최초 상태정보 요청등록시 true
+vms.subscription.status=true
+#최초 교통정보 요청등록시 true
+vms.subscription.traffic=true
+
+#구간가공정보 파라미터
+vms.filtering.minSpeed=3
+vms.filtering.maxSpeed=140
+vms.filtering.historyMinute=60
+
+
+#[Database properties]
+#spring.datasource.hikari.driver-class-name=com.tmax.tibero.jdbc.TbDriver
+#spring.datasource.hikari.jdbc-url=jdbc:tibero:thin:@192.168.20.29:8629:tibero
+#spring.datasource.hikari.username=gmutis
+#spring.datasource.hikari.password=gmutis
+
+#spring.datasource.hikari.driver-class-name=oracle.jdbc.OracleDriver
+#spring.datasource.hikari.jdbc-url=jdbc:oracle:thin:@127.0.0.1:1521:HANTE
+spring.datasource.hikari.driver-class-name=net.sf.log4jdbc.sql.jdbcapi.DriverSpy
+spring.datasource.hikari.jdbc-url=jdbc:log4jdbc:oracle:thin:@127.0.0.1:1521:HANTE
+spring.datasource.hikari.username=gmutis
+spring.datasource.hikari.password=gmutis
+
+spring.datasource.hikari.jpool-name=hikari-cp
+spring.datasource.hikari.jmaximum-pool-size=30
+spring.datasource.hikari.jminimum-idle=2
+
+# FOR WEB UI: START
+server.shutdown=graceful
+server.port=80
+server.error.whitelabel.enabled=true
+server.error.include-exception=false
+server.error.include-stacktrace=never
+
+spring.mvc.view.prefix=/WEB-INF/jsp/
+spring.mvc.view.suffix=.jsp
+server.servlet.session.timeout=300
+# FOR WEB UI: END

+ 322 - 0
mvnw

@@ -0,0 +1,322 @@
+#!/bin/sh
+# ----------------------------------------------------------------------------
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements.  See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership.  The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License.  You may obtain a copy of the License at
+#
+#    https://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied.  See the License for the
+# specific language governing permissions and limitations
+# under the License.
+# ----------------------------------------------------------------------------
+
+# ----------------------------------------------------------------------------
+# Maven Start Up Batch script
+#
+# Required ENV vars:
+# ------------------
+#   JAVA_HOME - location of a JDK home dir
+#
+# Optional ENV vars
+# -----------------
+#   M2_HOME - location of maven2's installed home dir
+#   MAVEN_OPTS - parameters passed to the Java VM when running Maven
+#     e.g. to debug Maven itself, use
+#       set MAVEN_OPTS=-Xdebug -Xrunjdwp:transport=dt_socket,server=y,suspend=y,address=8000
+#   MAVEN_SKIP_RC - flag to disable loading of mavenrc files
+# ----------------------------------------------------------------------------
+
+if [ -z "$MAVEN_SKIP_RC" ]; then
+
+  if [ -f /etc/mavenrc ]; then
+    . /etc/mavenrc
+  fi
+
+  if [ -f "$HOME/.mavenrc" ]; then
+    . "$HOME/.mavenrc"
+  fi
+
+fi
+
+# OS specific support.  $var _must_ be set to either true or false.
+cygwin=false
+darwin=false
+mingw=false
+case "$(uname)" in
+CYGWIN*) cygwin=true ;;
+MINGW*) mingw=true ;;
+Darwin*)
+  darwin=true
+  # Use /usr/libexec/java_home if available, otherwise fall back to /Library/Java/Home
+  # See https://developer.apple.com/library/mac/qa/qa1170/_index.html
+  if [ -z "$JAVA_HOME" ]; then
+    if [ -x "/usr/libexec/java_home" ]; then
+      export JAVA_HOME="$(/usr/libexec/java_home)"
+    else
+      export JAVA_HOME="/Library/Java/Home"
+    fi
+  fi
+  ;;
+esac
+
+if [ -z "$JAVA_HOME" ]; then
+  if [ -r /etc/gentoo-release ]; then
+    JAVA_HOME=$(java-config --jre-home)
+  fi
+fi
+
+if [ -z "$M2_HOME" ]; then
+  ## resolve links - $0 may be a link to maven's home
+  PRG="$0"
+
+  # need this for relative symlinks
+  while [ -h "$PRG" ]; do
+    ls=$(ls -ld "$PRG")
+    link=$(expr "$ls" : '.*-> \(.*\)$')
+    if expr "$link" : '/.*' >/dev/null; then
+      PRG="$link"
+    else
+      PRG="$(dirname "$PRG")/$link"
+    fi
+  done
+
+  saveddir=$(pwd)
+
+  M2_HOME=$(dirname "$PRG")/..
+
+  # make it fully qualified
+  M2_HOME=$(cd "$M2_HOME" && pwd)
+
+  cd "$saveddir"
+  # echo Using m2 at $M2_HOME
+fi
+
+# For Cygwin, ensure paths are in UNIX format before anything is touched
+if $cygwin; then
+  [ -n "$M2_HOME" ] &&
+    M2_HOME=$(cygpath --unix "$M2_HOME")
+  [ -n "$JAVA_HOME" ] &&
+    JAVA_HOME=$(cygpath --unix "$JAVA_HOME")
+  [ -n "$CLASSPATH" ] &&
+    CLASSPATH=$(cygpath --path --unix "$CLASSPATH")
+fi
+
+# For Mingw, ensure paths are in UNIX format before anything is touched
+if $mingw; then
+  [ -n "$M2_HOME" ] &&
+    M2_HOME="$( (
+      cd "$M2_HOME"
+      pwd
+    ))"
+  [ -n "$JAVA_HOME" ] &&
+    JAVA_HOME="$( (
+      cd "$JAVA_HOME"
+      pwd
+    ))"
+fi
+
+if [ -z "$JAVA_HOME" ]; then
+  javaExecutable="$(which javac)"
+  if [ -n "$javaExecutable" ] && ! [ "$(expr \"$javaExecutable\" : '\([^ ]*\)')" = "no" ]; then
+    # readlink(1) is not available as standard on Solaris 10.
+    readLink=$(which readlink)
+    if [ ! $(expr "$readLink" : '\([^ ]*\)') = "no" ]; then
+      if $darwin; then
+        javaHome="$(dirname \"$javaExecutable\")"
+        javaExecutable="$(cd \"$javaHome\" && pwd -P)/javac"
+      else
+        javaExecutable="$(readlink -f \"$javaExecutable\")"
+      fi
+      javaHome="$(dirname \"$javaExecutable\")"
+      javaHome=$(expr "$javaHome" : '\(.*\)/bin')
+      JAVA_HOME="$javaHome"
+      export JAVA_HOME
+    fi
+  fi
+fi
+
+if [ -z "$JAVACMD" ]; then
+  if [ -n "$JAVA_HOME" ]; then
+    if [ -x "$JAVA_HOME/jre/sh/java" ]; then
+      # IBM's JDK on AIX uses strange locations for the executables
+      JAVACMD="$JAVA_HOME/jre/sh/java"
+    else
+      JAVACMD="$JAVA_HOME/bin/java"
+    fi
+  else
+    JAVACMD="$(which java)"
+  fi
+fi
+
+if [ ! -x "$JAVACMD" ]; then
+  echo "Error: JAVA_HOME is not defined correctly." >&2
+  echo "  We cannot execute $JAVACMD" >&2
+  exit 1
+fi
+
+if [ -z "$JAVA_HOME" ]; then
+  echo "Warning: JAVA_HOME environment variable is not set."
+fi
+
+CLASSWORLDS_LAUNCHER=org.codehaus.plexus.classworlds.launcher.Launcher
+
+# traverses directory structure from process work directory to filesystem root
+# first directory with .mvn subdirectory is considered project base directory
+find_maven_basedir() {
+
+  if [ -z "$1" ]; then
+    echo "Path not specified to find_maven_basedir"
+    return 1
+  fi
+
+  basedir="$1"
+  wdir="$1"
+  while [ "$wdir" != '/' ]; do
+    if [ -d "$wdir"/.mvn ]; then
+      basedir=$wdir
+      break
+    fi
+    # workaround for JBEAP-8937 (on Solaris 10/Sparc)
+    if [ -d "${wdir}" ]; then
+      wdir=$(
+        cd "$wdir/.."
+        pwd
+      )
+    fi
+    # end of workaround
+  done
+  echo "${basedir}"
+}
+
+# concatenates all lines of a file
+concat_lines() {
+  if [ -f "$1" ]; then
+    echo "$(tr -s '\n' ' ' <"$1")"
+  fi
+}
+
+BASE_DIR=$(find_maven_basedir "$(pwd)")
+if [ -z "$BASE_DIR" ]; then
+  exit 1
+fi
+
+##########################################################################################
+# Extension to allow automatically downloading the maven-wrapper.jar from Maven-central
+# This allows using the maven wrapper in projects that prohibit checking in binary data.
+##########################################################################################
+if [ -r "$BASE_DIR/.mvn/wrapper/maven-wrapper.jar" ]; then
+  if [ "$MVNW_VERBOSE" = true ]; then
+    echo "Found .mvn/wrapper/maven-wrapper.jar"
+  fi
+else
+  if [ "$MVNW_VERBOSE" = true ]; then
+    echo "Couldn't find .mvn/wrapper/maven-wrapper.jar, downloading it ..."
+  fi
+  if [ -n "$MVNW_REPOURL" ]; then
+    jarUrl="$MVNW_REPOURL/io/takari/maven-wrapper/0.5.6/maven-wrapper-0.5.6.jar"
+  else
+    jarUrl="https://repo.maven.apache.org/maven2/io/takari/maven-wrapper/0.5.6/maven-wrapper-0.5.6.jar"
+  fi
+  while IFS="=" read key value; do
+    case "$key" in wrapperUrl)
+      jarUrl="$value"
+      break
+      ;;
+    esac
+  done <"$BASE_DIR/.mvn/wrapper/maven-wrapper.properties"
+  if [ "$MVNW_VERBOSE" = true ]; then
+    echo "Downloading from: $jarUrl"
+  fi
+  wrapperJarPath="$BASE_DIR/.mvn/wrapper/maven-wrapper.jar"
+  if $cygwin; then
+    wrapperJarPath=$(cygpath --path --windows "$wrapperJarPath")
+  fi
+
+  if command -v wget >/dev/null; then
+    if [ "$MVNW_VERBOSE" = true ]; then
+      echo "Found wget ... using wget"
+    fi
+    if [ -z "$MVNW_USERNAME" ] || [ -z "$MVNW_PASSWORD" ]; then
+      wget "$jarUrl" -O "$wrapperJarPath"
+    else
+      wget --http-user=$MVNW_USERNAME --http-password=$MVNW_PASSWORD "$jarUrl" -O "$wrapperJarPath"
+    fi
+  elif command -v curl >/dev/null; then
+    if [ "$MVNW_VERBOSE" = true ]; then
+      echo "Found curl ... using curl"
+    fi
+    if [ -z "$MVNW_USERNAME" ] || [ -z "$MVNW_PASSWORD" ]; then
+      curl -o "$wrapperJarPath" "$jarUrl" -f
+    else
+      curl --user $MVNW_USERNAME:$MVNW_PASSWORD -o "$wrapperJarPath" "$jarUrl" -f
+    fi
+
+  else
+    if [ "$MVNW_VERBOSE" = true ]; then
+      echo "Falling back to using Java to download"
+    fi
+    javaClass="$BASE_DIR/.mvn/wrapper/MavenWrapperDownloader.java"
+    # For Cygwin, switch paths to Windows format before running javac
+    if $cygwin; then
+      javaClass=$(cygpath --path --windows "$javaClass")
+    fi
+    if [ -e "$javaClass" ]; then
+      if [ ! -e "$BASE_DIR/.mvn/wrapper/MavenWrapperDownloader.class" ]; then
+        if [ "$MVNW_VERBOSE" = true ]; then
+          echo " - Compiling MavenWrapperDownloader.java ..."
+        fi
+        # Compiling the Java class
+        ("$JAVA_HOME/bin/javac" "$javaClass")
+      fi
+      if [ -e "$BASE_DIR/.mvn/wrapper/MavenWrapperDownloader.class" ]; then
+        # Running the downloader
+        if [ "$MVNW_VERBOSE" = true ]; then
+          echo " - Running MavenWrapperDownloader.java ..."
+        fi
+        ("$JAVA_HOME/bin/java" -cp .mvn/wrapper MavenWrapperDownloader "$MAVEN_PROJECTBASEDIR")
+      fi
+    fi
+  fi
+fi
+##########################################################################################
+# End of extension
+##########################################################################################
+
+export MAVEN_PROJECTBASEDIR=${MAVEN_BASEDIR:-"$BASE_DIR"}
+if [ "$MVNW_VERBOSE" = true ]; then
+  echo $MAVEN_PROJECTBASEDIR
+fi
+MAVEN_OPTS="$(concat_lines "$MAVEN_PROJECTBASEDIR/.mvn/jvm.config") $MAVEN_OPTS"
+
+# For Cygwin, switch paths to Windows format before running java
+if $cygwin; then
+  [ -n "$M2_HOME" ] &&
+    M2_HOME=$(cygpath --path --windows "$M2_HOME")
+  [ -n "$JAVA_HOME" ] &&
+    JAVA_HOME=$(cygpath --path --windows "$JAVA_HOME")
+  [ -n "$CLASSPATH" ] &&
+    CLASSPATH=$(cygpath --path --windows "$CLASSPATH")
+  [ -n "$MAVEN_PROJECTBASEDIR" ] &&
+    MAVEN_PROJECTBASEDIR=$(cygpath --path --windows "$MAVEN_PROJECTBASEDIR")
+fi
+
+# Provide a "standardized" way to retrieve the CLI args that will
+# work with both Windows and non-Windows executions.
+MAVEN_CMD_LINE_ARGS="$MAVEN_CONFIG $@"
+export MAVEN_CMD_LINE_ARGS
+
+WRAPPER_LAUNCHER=org.apache.maven.wrapper.MavenWrapperMain
+
+exec "$JAVACMD" \
+  $MAVEN_OPTS \
+  -classpath "$MAVEN_PROJECTBASEDIR/.mvn/wrapper/maven-wrapper.jar" \
+  "-Dmaven.home=${M2_HOME}" "-Dmaven.multiModuleProjectDirectory=${MAVEN_PROJECTBASEDIR}" \
+  ${WRAPPER_LAUNCHER} $MAVEN_CONFIG "$@"

+ 182 - 0
mvnw.cmd

@@ -0,0 +1,182 @@
+@REM ----------------------------------------------------------------------------
+@REM Licensed to the Apache Software Foundation (ASF) under one
+@REM or more contributor license agreements.  See the NOTICE file
+@REM distributed with this work for additional information
+@REM regarding copyright ownership.  The ASF licenses this file
+@REM to you under the Apache License, Version 2.0 (the
+@REM "License"); you may not use this file except in compliance
+@REM with the License.  You may obtain a copy of the License at
+@REM
+@REM    https://www.apache.org/licenses/LICENSE-2.0
+@REM
+@REM Unless required by applicable law or agreed to in writing,
+@REM software distributed under the License is distributed on an
+@REM "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+@REM KIND, either express or implied.  See the License for the
+@REM specific language governing permissions and limitations
+@REM under the License.
+@REM ----------------------------------------------------------------------------
+
+@REM ----------------------------------------------------------------------------
+@REM Maven Start Up Batch script
+@REM
+@REM Required ENV vars:
+@REM JAVA_HOME - location of a JDK home dir
+@REM
+@REM Optional ENV vars
+@REM M2_HOME - location of maven2's installed home dir
+@REM MAVEN_BATCH_ECHO - set to 'on' to enable the echoing of the batch commands
+@REM MAVEN_BATCH_PAUSE - set to 'on' to wait for a keystroke before ending
+@REM MAVEN_OPTS - parameters passed to the Java VM when running Maven
+@REM     e.g. to debug Maven itself, use
+@REM set MAVEN_OPTS=-Xdebug -Xrunjdwp:transport=dt_socket,server=y,suspend=y,address=8000
+@REM MAVEN_SKIP_RC - flag to disable loading of mavenrc files
+@REM ----------------------------------------------------------------------------
+
+@REM Begin all REM lines with '@' in case MAVEN_BATCH_ECHO is 'on'
+@echo off
+@REM set title of command window
+title %0
+@REM enable echoing by setting MAVEN_BATCH_ECHO to 'on'
+@if "%MAVEN_BATCH_ECHO%" == "on"  echo %MAVEN_BATCH_ECHO%
+
+@REM set %HOME% to equivalent of $HOME
+if "%HOME%" == "" (set "HOME=%HOMEDRIVE%%HOMEPATH%")
+
+@REM Execute a user defined script before this one
+if not "%MAVEN_SKIP_RC%" == "" goto skipRcPre
+@REM check for pre script, once with legacy .bat ending and once with .cmd ending
+if exist "%HOME%\mavenrc_pre.bat" call "%HOME%\mavenrc_pre.bat"
+if exist "%HOME%\mavenrc_pre.cmd" call "%HOME%\mavenrc_pre.cmd"
+:skipRcPre
+
+@setlocal
+
+set ERROR_CODE=0
+
+@REM To isolate internal variables from possible post scripts, we use another setlocal
+@setlocal
+
+@REM ==== START VALIDATION ====
+if not "%JAVA_HOME%" == "" goto OkJHome
+
+echo.
+echo Error: JAVA_HOME not found in your environment. >&2
+echo Please set the JAVA_HOME variable in your environment to match the >&2
+echo location of your Java installation. >&2
+echo.
+goto error
+
+:OkJHome
+if exist "%JAVA_HOME%\bin\java.exe" goto init
+
+echo.
+echo Error: JAVA_HOME is set to an invalid directory. >&2
+echo JAVA_HOME = "%JAVA_HOME%" >&2
+echo Please set the JAVA_HOME variable in your environment to match the >&2
+echo location of your Java installation. >&2
+echo.
+goto error
+
+@REM ==== END VALIDATION ====
+
+:init
+
+@REM Find the project base dir, i.e. the directory that contains the folder ".mvn".
+@REM Fallback to current working directory if not found.
+
+set MAVEN_PROJECTBASEDIR=%MAVEN_BASEDIR%
+IF NOT "%MAVEN_PROJECTBASEDIR%"=="" goto endDetectBaseDir
+
+set EXEC_DIR=%CD%
+set WDIR=%EXEC_DIR%
+:findBaseDir
+IF EXIST "%WDIR%"\.mvn goto baseDirFound
+cd ..
+IF "%WDIR%"=="%CD%" goto baseDirNotFound
+set WDIR=%CD%
+goto findBaseDir
+
+:baseDirFound
+set MAVEN_PROJECTBASEDIR=%WDIR%
+cd "%EXEC_DIR%"
+goto endDetectBaseDir
+
+:baseDirNotFound
+set MAVEN_PROJECTBASEDIR=%EXEC_DIR%
+cd "%EXEC_DIR%"
+
+:endDetectBaseDir
+
+IF NOT EXIST "%MAVEN_PROJECTBASEDIR%\.mvn\jvm.config" goto endReadAdditionalConfig
+
+@setlocal EnableExtensions EnableDelayedExpansion
+for /F "usebackq delims=" %%a in ("%MAVEN_PROJECTBASEDIR%\.mvn\jvm.config") do set JVM_CONFIG_MAVEN_PROPS=!JVM_CONFIG_MAVEN_PROPS! %%a
+@endlocal & set JVM_CONFIG_MAVEN_PROPS=%JVM_CONFIG_MAVEN_PROPS%
+
+:endReadAdditionalConfig
+
+SET MAVEN_JAVA_EXE="%JAVA_HOME%\bin\java.exe"
+set WRAPPER_JAR="%MAVEN_PROJECTBASEDIR%\.mvn\wrapper\maven-wrapper.jar"
+set WRAPPER_LAUNCHER=org.apache.maven.wrapper.MavenWrapperMain
+
+set DOWNLOAD_URL="https://repo.maven.apache.org/maven2/io/takari/maven-wrapper/0.5.6/maven-wrapper-0.5.6.jar"
+
+FOR /F "tokens=1,2 delims==" %%A IN ("%MAVEN_PROJECTBASEDIR%\.mvn\wrapper\maven-wrapper.properties") DO (
+    IF "%%A"=="wrapperUrl" SET DOWNLOAD_URL=%%B
+)
+
+@REM Extension to allow automatically downloading the maven-wrapper.jar from Maven-central
+@REM This allows using the maven wrapper in projects that prohibit checking in binary data.
+if exist %WRAPPER_JAR% (
+    if "%MVNW_VERBOSE%" == "true" (
+        echo Found %WRAPPER_JAR%
+    )
+) else (
+    if not "%MVNW_REPOURL%" == "" (
+        SET DOWNLOAD_URL="%MVNW_REPOURL%/io/takari/maven-wrapper/0.5.6/maven-wrapper-0.5.6.jar"
+    )
+    if "%MVNW_VERBOSE%" == "true" (
+        echo Couldn't find %WRAPPER_JAR%, downloading it ...
+        echo Downloading from: %DOWNLOAD_URL%
+    )
+
+    powershell -Command "&{"^
+		"$webclient = new-object System.Net.WebClient;"^
+		"if (-not ([string]::IsNullOrEmpty('%MVNW_USERNAME%') -and [string]::IsNullOrEmpty('%MVNW_PASSWORD%'))) {"^
+		"$webclient.Credentials = new-object System.Net.NetworkCredential('%MVNW_USERNAME%', '%MVNW_PASSWORD%');"^
+		"}"^
+		"[Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12; $webclient.DownloadFile('%DOWNLOAD_URL%', '%WRAPPER_JAR%')"^
+		"}"
+    if "%MVNW_VERBOSE%" == "true" (
+        echo Finished downloading %WRAPPER_JAR%
+    )
+)
+@REM End of extension
+
+@REM Provide a "standardized" way to retrieve the CLI args that will
+@REM work with both Windows and non-Windows executions.
+set MAVEN_CMD_LINE_ARGS=%*
+
+%MAVEN_JAVA_EXE% %JVM_CONFIG_MAVEN_PROPS% %MAVEN_OPTS% %MAVEN_DEBUG_OPTS% -classpath %WRAPPER_JAR% "-Dmaven.multiModuleProjectDirectory=%MAVEN_PROJECTBASEDIR%" %WRAPPER_LAUNCHER% %MAVEN_CONFIG% %*
+if ERRORLEVEL 1 goto error
+goto end
+
+:error
+set ERROR_CODE=1
+
+:end
+@endlocal & set ERROR_CODE=%ERROR_CODE%
+
+if not "%MAVEN_SKIP_RC%" == "" goto skipRcPost
+@REM check for post script, once with legacy .bat ending and once with .cmd ending
+if exist "%HOME%\mavenrc_post.bat" call "%HOME%\mavenrc_post.bat"
+if exist "%HOME%\mavenrc_post.cmd" call "%HOME%\mavenrc_post.cmd"
+:skipRcPost
+
+@REM pause the script if MAVEN_BATCH_PAUSE is set to 'on'
+if "%MAVEN_BATCH_PAUSE%" == "on" pause
+
+if "%MAVEN_TERMINATE_CMD%" == "on" exit %ERROR_CODE%
+
+exit /B %ERROR_CODE%

+ 230 - 0
pom.xml

@@ -0,0 +1,230 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
+    <modelVersion>4.0.0</modelVersion>
+    <parent>
+        <groupId>org.springframework.boot</groupId>
+        <artifactId>spring-boot-starter-parent</artifactId>
+        <version>2.4.13</version>
+        <relativePath/> <!-- lookup parent from repository -->
+    </parent>
+    <groupId>com.its</groupId>
+    <artifactId>vms-comm-server</artifactId>
+    <version>0.0.1</version>
+    <name>vms-comm-server</name>
+    <description>VMS Communication Server</description>
+
+    <packaging>jar</packaging>
+
+    <repositories>
+        <repository>
+            <id>oracle</id>
+            <url>https://maven.jahia.org/maven2</url>
+        </repository>
+    </repositories>
+
+    <properties>
+        <java.version>1.8</java.version>
+        <swagger.version>2.9.2</swagger.version>
+        <org.projectlombok.version>1.18.20</org.projectlombok.version>
+        <org.mapstruct.version>1.4.2.Final</org.mapstruct.version>
+        <jackson.version>2.13.1</jackson.version>
+        <!-- jar 배포용 -->
+        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
+        <project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
+        <maven.compiler.source>1.8</maven.compiler.source>
+        <maven.compiler.target>1.8</maven.compiler.target>
+        <!--main 함수가 있는 class 경로-->
+        <start-class>com.its.vms.VmsCommServerApplication</start-class>
+        <webapp.lib>C:\java\repository</webapp.lib>
+        <maven.test.skip>true</maven.test.skip>
+    </properties>
+
+    <dependencies>
+        <dependency>
+            <groupId>io.springfox</groupId>
+            <artifactId>springfox-swagger2</artifactId>
+            <version>${swagger.version}</version>
+        </dependency>
+        <dependency>
+            <groupId>io.springfox</groupId>
+            <artifactId>springfox-swagger-ui</artifactId>
+            <version>${swagger.version}</version>
+        </dependency>
+        <dependency>
+            <groupId>org.springframework.boot</groupId>
+            <artifactId>spring-boot-starter-validation</artifactId>
+        </dependency>
+         <dependency>
+            <groupId>org.springframework.boot</groupId>
+            <artifactId>spring-boot-starter-test</artifactId>
+            <scope>test</scope>
+        </dependency>
+
+        <dependency>
+            <groupId>com.jcabi</groupId>
+            <artifactId>jcabi-log</artifactId>
+            <version>0.22.0</version>
+        </dependency>
+
+        <dependency>
+            <groupId>com.oracle</groupId>
+            <artifactId>ojdbc7</artifactId>
+            <version>12.1.0.2</version>
+            <scope>system</scope>
+            <systemPath>${webapp.lib}/ojdbc7-12.1.0.2.jar</systemPath>
+        </dependency>
+
+        <dependency>
+            <groupId>tibero6</groupId>
+            <artifactId>tibero6-jdbc</artifactId>
+            <version>1.0.0</version>
+            <scope>system</scope>
+            <systemPath>${webapp.lib}/tibero6-jdbc-14.jar</systemPath>
+        </dependency>
+
+        <dependency>
+            <groupId>com.google.guava</groupId>
+            <artifactId>guava</artifactId>
+            <version>31.1-jre</version>
+        </dependency>
+
+        <dependency>
+            <groupId>org.bgee.log4jdbc-log4j2</groupId>
+            <artifactId>log4jdbc-log4j2-jdbc4.1</artifactId>
+            <version>1.16</version>
+        </dependency>
+
+        <dependency>
+            <groupId>org.springframework.boot</groupId>
+            <artifactId>spring-boot-starter-quartz</artifactId>
+        </dependency>
+
+        <dependency>
+            <groupId>org.springframework.boot</groupId>
+            <artifactId>spring-boot-starter-jdbc</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>org.springframework.boot</groupId>
+            <artifactId>spring-boot-starter-web</artifactId>
+            <exclusions>
+                <!-- Exclude the Tomcat dependency -->
+                <exclusion>
+                    <groupId>org.springframework.boot</groupId>
+                    <artifactId>spring-boot-starter-tomcat</artifactId>
+                </exclusion>
+            </exclusions>
+        </dependency>
+        <dependency>
+            <groupId>org.mybatis.spring.boot</groupId>
+            <artifactId>mybatis-spring-boot-starter</artifactId>
+            <version>2.2.2</version>
+        </dependency>
+
+        <dependency>
+            <groupId>org.springframework.boot</groupId>
+            <artifactId>spring-boot-devtools</artifactId>
+            <scope>runtime</scope>
+            <optional>true</optional>
+        </dependency>
+
+        <dependency>
+            <groupId>org.springframework.boot</groupId>
+            <artifactId>spring-boot-configuration-processor</artifactId>
+            <optional>true</optional>
+        </dependency>
+        <dependency>
+            <groupId>org.projectlombok</groupId>
+            <artifactId>lombok</artifactId>
+            <optional>true</optional>
+            <scope>compile</scope>
+        </dependency>
+
+        <dependency>
+            <groupId>net.sf.json-lib</groupId>
+            <artifactId>json-lib</artifactId>
+            <version>2.4</version>
+            <classifier>jdk15</classifier>
+        </dependency>
+
+        <dependency>
+            <groupId>org.springframework.boot</groupId>
+            <artifactId>spring-boot-starter-tomcat</artifactId>
+        </dependency>
+
+        <dependency>
+            <groupId>io.netty</groupId>
+            <artifactId>netty-all</artifactId>
+            <version>4.1.52.Final</version>
+        </dependency>
+        <dependency>
+            <groupId>io.netty</groupId>
+            <artifactId>netty-transport</artifactId>
+            <version>4.1.52.Final</version>
+        </dependency>
+
+<!--        <dependency>-->
+<!--            <groupId>org.apache.commons</groupId>-->
+<!--            <artifactId>commons-lang3</artifactId>-->
+<!--            <version>3.11</version>-->
+<!--        </dependency>-->
+
+        <dependency>
+            <groupId>com.rometools</groupId>
+            <artifactId>rome</artifactId>
+            <version>1.18.0</version>
+        </dependency>
+
+        <!-- FOR WEB UI: START -->
+        <dependency>
+            <groupId>org.springframework.boot</groupId>
+            <artifactId>spring-boot-starter-security</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>javax.servlet</groupId>
+            <artifactId>jstl</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>org.apache.tomcat.embed</groupId>
+            <artifactId>tomcat-embed-jasper</artifactId>
+            <scope>provided</scope>
+        </dependency>
+        <dependency>
+            <groupId>org.springframework.boot</groupId>
+            <artifactId>spring-boot-starter-web-services</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>org.apache.httpcomponents</groupId>
+            <artifactId>httpclient</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>com.intellij</groupId>
+            <artifactId>forms_rt</artifactId>
+            <version>7.0.3</version>
+        </dependency>
+        <dependency>
+            <groupId>org.apache.commons</groupId>
+            <artifactId>commons-lang3</artifactId>
+            <version>3.12.0</version>
+        </dependency>
+        <dependency>
+            <groupId>commons-io</groupId>
+            <artifactId>commons-io</artifactId>
+            <version>2.11.0</version>
+        </dependency>
+
+    </dependencies>
+
+    <build>
+        <plugins>
+            <plugin>
+                <groupId>org.springframework.boot</groupId>
+                <artifactId>spring-boot-maven-plugin</artifactId>
+                <configuration>
+                    <includeSystemScope>true</includeSystemScope>
+                </configuration>
+            </plugin>
+        </plugins>
+    </build>
+
+</project>

+ 3 - 0
src/main/java/META-INF/MANIFEST.MF

@@ -0,0 +1,3 @@
+Manifest-Version: 1.0
+Main-Class: com.its.app.dsrc.DsrcCommServerApplication
+

+ 31 - 0
src/main/java/com/its/app/AppUtils.java

@@ -0,0 +1,31 @@
+package com.its.app;
+
+import org.springframework.context.ApplicationContext;
+import org.springframework.core.env.Environment;
+
+public final class AppUtils {
+    private AppUtils() {
+    }
+
+    public static Object getBean(Class<?> classType) {
+        ApplicationContext applicationContext = ApplicationContextProvider.getApplicationContext();
+        return applicationContext.getBean(classType);
+    }
+
+    public static Object getBean(String beanName) {
+        ApplicationContext applicationContext = ApplicationContextProvider.getApplicationContext();
+        return applicationContext.getBean(beanName);
+    }
+
+    public static ApplicationContext getApplicationContext() {
+        return ApplicationContextProvider.getApplicationContext();
+    }
+
+    public static String getApplicationId() {
+        return ApplicationContextProvider.getApplicationId();
+    }
+
+    public static Environment getApplicationEnvironment() {
+        return ApplicationContextProvider.getApplicationEnvironment();
+    }
+}

+ 35 - 0
src/main/java/com/its/app/ApplicationContextProvider.java

@@ -0,0 +1,35 @@
+package com.its.app;
+
+import org.springframework.beans.BeansException;
+import org.springframework.context.ApplicationContext;
+import org.springframework.context.ApplicationContextAware;
+import org.springframework.core.env.Environment;
+import org.springframework.stereotype.Component;
+
+@Component
+public class ApplicationContextProvider implements ApplicationContextAware {
+    private static ApplicationContext applicationContext;
+    private static String applicationId;
+    private static Environment environment;
+
+    private ApplicationContextProvider() {
+    }
+
+    public void setApplicationContext(ApplicationContext ctx) throws BeansException {
+        applicationContext = ctx;
+        applicationId = ctx.getId();
+        environment = ctx.getEnvironment();
+    }
+
+    public static ApplicationContext getApplicationContext() {
+        return applicationContext;
+    }
+
+    public static String getApplicationId() {
+        return applicationId;
+    }
+
+    public static Environment getApplicationEnvironment() {
+        return environment;
+    }
+}

+ 39 - 0
src/main/java/com/its/app/utils/BcdConverter.java

@@ -0,0 +1,39 @@
+package com.its.app.utils;
+
+public class BcdConverter {
+
+    public static String bcdToString(byte bcd) {
+        StringBuilder sb = new StringBuilder();
+        byte high = (byte)(bcd & 0xf0);
+        high >>>= (byte)4;
+        high = (byte)(high & 0x0f);
+        byte low = (byte) (bcd & 0x0f);
+
+        sb.append(high);
+        sb.append(low);
+
+        return sb.toString();
+    }
+
+    public static String bcdToString(byte[] data) {
+        StringBuilder sb = new StringBuilder();
+
+        for (byte datum : data) {
+            sb.append(bcdToString(datum));
+        }
+        return sb.toString();
+    }
+
+    public static byte[] stringToBcd(String data) {
+        if ((data.length() % 2) != 0) {
+            data += "0";
+        }
+        byte[] temp = data.getBytes();
+        int length = temp.length;
+        byte[] result = new byte[length/2];
+        for (int ii = 0; ii < length; ii+=2) {
+            result[ii/2] = (byte)((temp[ii] - '0') << 4 | (temp[ii+1] - '0'));
+        }
+        return result;
+    }
+}

+ 312 - 0
src/main/java/com/its/app/utils/ByteUtils.java

@@ -0,0 +1,312 @@
+package com.its.app.utils;
+
+public class ByteUtils {
+
+	private static final int[] BYTE_MASKED_ARRAY = { 1, 2, 4, 8, 16, 32, 64, 128 };
+
+	public static int byteToInt(byte srcValue)
+	{
+		return srcValue & 0xFF;
+	}
+
+	public static int shortToInt(short srcValue)
+	{
+		return srcValue & 0xFFFF;
+	}
+
+	public static long intToLong(int srcValue)
+	{
+		return srcValue & 0xFFFFFFFF;
+	}
+
+	public static int longToInt(long srcValue)
+	{
+		return (int)(srcValue & 0xFFFFFFFF);
+	}
+
+	public static String byteToBitString(byte srcValue)
+	{
+		return String.format("%8s", Long.toBinaryString(srcValue & 0xFF)).replace(' ', '0');
+	}
+
+	public static String shortToBitString(short srcValue)
+	{
+		return String.format("%16s", Long.toBinaryString(srcValue & 0xFF)).replace(' ', '0');
+	}
+
+	public static String intToBitString(int srcValue)
+	{
+		return String.format("%32s", Integer.toBinaryString(srcValue & 0xFF)).replace(' ', '0');
+	}
+
+	public static String longToBitString(long srcValue)
+	{
+		return String.format("%64s", Long.toBinaryString(srcValue & 0xFF)).replace(' ', '0');
+	}
+
+	public static int extractBits(byte srcValue, int beginBitDigit, int endBitDigit)
+	{
+		int maskedValue = 0;
+		for (int idx = beginBitDigit; idx <= endBitDigit; idx++) {
+			maskedValue += BYTE_MASKED_ARRAY[idx];
+		}
+		return (srcValue & maskedValue) >> beginBitDigit;
+	}
+
+	public static int extractBit(byte srcValue, int bitDigit)
+	{
+		return (srcValue & BYTE_MASKED_ARRAY[bitDigit]) == BYTE_MASKED_ARRAY[bitDigit] ? 1 : 0;
+	}
+
+	public static int compareMaskedValue(byte srcValue, int maskValue, int compareValue)
+	{
+		int resultValue = byteToInt(srcValue) & maskValue;
+		return resultValue == compareValue ? 0 : resultValue > compareValue ? 1 : -1;
+	}
+
+	public static String convertCustomDateTime(String strDate)
+	{
+		String convertDate = strDate;
+		if (convertDate.lastIndexOf(".") != -1) {
+			convertDate = convertDate.substring(0, convertDate.lastIndexOf("."));
+		}
+		return convertDate.replaceAll("-", "").replaceAll(":", "").replaceAll(" ", "");
+	}
+
+	public static byte[] hexToByteArray(String hex)
+	{
+		if ((hex == null) || (hex.length() == 0)) {
+			return null;
+		}
+		byte[] ba = new byte[hex.length() / 2];
+		for (int i = 0; i < ba.length; i++) {
+			ba[i] = ((byte)Integer.parseInt(hex.substring(2 * i, 2 * i + 2), 16));
+		}
+		return ba;
+	}
+
+	public static String byteArrayToHex(byte[] ba)
+	{
+		return byteArrayToHex(ba, null);
+	}
+
+	public static byte[] intToShortBytes(int length)
+	{
+		byte[] b3 = new byte[2];
+		if (length > 255)
+		{
+			b3[0] = ((byte)(length / 256));
+			b3[1] = ((byte)(length % 256));
+		}
+		else
+		{
+			b3[0] = 0;
+			b3[1] = ((byte)length);
+		}
+		return b3;
+	}
+
+	public static int getIntOnBit(int n, int offset, int length)
+	{
+		return n >> 32 - offset - length & (-1 << length ^ 0xFFFFFFFF);
+	}
+
+	public static String byteArrayToHex(byte[] ba, String seperator)
+	{
+		if ((ba == null) || (ba.length == 0)) {
+			return null;
+		}
+
+		StringBuffer sb = new StringBuffer(ba.length * 2);
+		for (int x = 0; x < ba.length; x++)
+		{
+			String hexNumber = "0" + Integer.toHexString(0xFF & ba[x]).toUpperCase();
+
+			sb.append(hexNumber.substring(hexNumber.length() - 2));
+			//if (seperator != null && !seperator.isEmpty()) {
+				sb.append(seperator);
+			//}
+		}
+		return sb.toString();
+	}
+
+	static final char[] HEX_ARRAY = "0123456789ABCDEF".toCharArray();
+	public static final int BIT_1 = 1;
+	public static final int BIT_2 = 3;
+	public static final int BIT_3 = 7;
+	public static final int BIT_4 = 15;
+	public static final int BIT_5 = 31;
+	public static final int BIT_6 = 63;
+	public static final int BIT_7 = 127;
+	public static final int BIT_8 = 255;
+	public static final int BIT_9 = 511;
+	public static final int BIT_10 = 1023;
+	public static final int BIT_11 = 2047;
+	public static final int BIT_12 = 4095;
+	public static final int BIT_13 = 8191;
+	public static final int BIT_14 = 16383;
+	public static final int BIT_15 = 32767;
+	public static final int BIT_16 = 65535;
+
+	public static String bytesToHex(byte[] bytes, int bundleSize, char seperator)
+	{
+		char[] hexChars = new char[bytes.length * 2 + bytes.length / bundleSize];
+		int j = 0;
+		for (int k = 1; j < bytes.length; k++)
+		{
+			int v = bytes[j] & 0xFF;
+			int start = j * 2 + j / bundleSize;
+
+			hexChars[start] = HEX_ARRAY[(v >>> 4)];
+			hexChars[(start + 1)] = HEX_ARRAY[(v & 0xF)];
+			if (k % bundleSize == 0) {
+				hexChars[(start + 2)] = seperator;
+			}
+			j++;
+		}
+		return new String(hexChars).trim();
+	}
+
+	public static String bytesToHex(byte[] bytes, int bundleSize)
+	{
+	return bytesToHex(bytes, bundleSize, ' ');
+	}
+
+	public static String byteToHex(byte b)
+	{
+	String hexNumber = "0" + Integer.toHexString(0xFF & b).toUpperCase();
+	return hexNumber.substring(hexNumber.length() - 2);
+	}
+
+	public static int convertNotNullStringToInt(String data)
+	{
+		if (data == null || data.trim().length() == 0)
+			return 0;
+		return Long.valueOf(data).intValue();
+	}
+
+	public static double convertNotNullStringToDouble(String data)
+	{
+		if (data == null || data.trim().length() == 0)
+			return 0.0D;
+		return Double.valueOf(data).doubleValue();
+	}
+
+	public static String extractFilePath(String fullPath)
+	{
+		String resultPath = fullPath;
+		int lastPathIndex = resultPath.lastIndexOf("/") != -1 ? resultPath.lastIndexOf("/") : resultPath.lastIndexOf("\\");
+		return lastPathIndex != -1 ? resultPath.substring(0, lastPathIndex + 1) : resultPath;
+	}
+
+	public static String extractFileName(String fullPath)
+	{
+		String resultPath = fullPath;
+		int lastPathIndex = resultPath.lastIndexOf("/") != -1 ? resultPath.lastIndexOf("/") : resultPath.lastIndexOf("\\");
+		return lastPathIndex != -1 ? resultPath.substring(lastPathIndex + 1) : resultPath;
+	}
+
+	public static String lpad(String str, int len, String pad)
+	{
+		String result = str;
+		int templen = len - result.length();
+		for (int i = 0; i < templen; i++) {
+			result = pad + result;
+		}
+		return result;
+	}
+
+	public static int getBitField(byte b, int field)
+	{
+		return (b & 1 << field) > 0 ? 1 : 0;
+	}
+
+	public static int getBitField(byte b, int field, int count)
+	{
+		if (count == 1) {
+			count = 1;
+		} else if (count == 2) {
+			count = 3;
+		} else if (count == 3) {
+			count = 7;
+		} else if (count == 4) {
+			count = 15;
+		} else if (count == 5) {
+			count = 31;
+		} else if (count == 6) {
+			count = 63;
+		} else if (count == 7) {
+			count = 127;
+		} else if (count == 8) {
+			count = 255;
+		} else if (count == 9) {
+			count = 511;
+		} else if (count == 10) {
+			count = 1023;
+		} else if (count == 11) {
+			count = 2047;
+		} else if (count == 12) {
+			count = 4095;
+		} else if (count == 13) {
+			count = 8191;
+		} else if (count == 14) {
+			count = 16383;
+		} else if (count == 15) {
+			count = 32767;
+		} else if (count == 16) {
+			count = 65535;
+		}
+		return b >> field & count;
+	}
+
+	public static byte setBitField(byte b, int field, int value)
+	{
+		if ((value == 0) || (value == 1)) {
+			b = (byte)(b | value << field);
+		}
+		return b;
+	}
+
+	public static byte setBitField(byte b, int field, int count, int value)
+	{
+		if ((field + count <= 8) && (value < Math.pow(2.0D, count))) {
+			if (count == 1) {
+				count = 1;
+			} else if (count == 2) {
+				count = 3;
+			} else if (count == 3) {
+				count = 7;
+			} else if (count == 4) {
+				count = 15;
+			} else if (count == 5) {
+				count = 31;
+			} else if (count == 6) {
+				count = 63;
+			} else if (count == 7) {
+				count = 127;
+			} else if (count == 8) {
+				count = 255;
+			} else if (count == 9) {
+				count = 511;
+			} else if (count == 10) {
+				count = 1023;
+			} else if (count == 11) {
+				count = 2047;
+			} else if (count == 12) {
+				count = 4095;
+			} else if (count == 13) {
+				count = 8191;
+			} else if (count == 14) {
+				count = 16383;
+			} else if (count == 15) {
+				count = 32767;
+			} else if (count == 16) {
+				count = 65535;
+			}
+		}
+		b = (byte)(b & (count << field ^ 0xFFFFFFFF));
+		b = (byte)(b | (value & count) << field);
+
+		return b;
+	}
+}

+ 22 - 0
src/main/java/com/its/app/utils/Elapsed.java

@@ -0,0 +1,22 @@
+package com.its.app.utils;
+
+public class Elapsed {
+
+	private long lTime = 0;
+	
+	public Elapsed() {
+		reset();
+	}
+	
+	public long milliSeconds() {
+		return System.currentTimeMillis() - lTime;
+	}
+
+	public long seconds() {
+		return Math.round((System.currentTimeMillis() - lTime) / 1000.0);
+	}
+	
+	public void reset() {
+		lTime = System.currentTimeMillis();
+	}
+}

+ 535 - 0
src/main/java/com/its/app/utils/FloodFill.java

@@ -0,0 +1,535 @@
+package com.its.app.utils;
+
+
+import java.awt.*;
+import java.awt.image.BufferedImage;
+import java.awt.image.DataBufferInt;
+import java.util.ArrayList;
+
+/**
+ * Drawing class which provides flood fill functionality. Found 
+ * on http://www.javagaming.org forum and adapted to be more generic. Antialiasing
+ * and texture filling capability added.
+ * 
+ * @author kingaschi (Christph Aschwanden - king@kingx.com)
+ * @author moogie (Javagaming Forum)
+ * @author tom  (Javagaming Forum)
+ * @since April 26, 2005
+ */
+public final class FloodFill {
+
+  /** 
+   * Line info class for linear non-recursive fill.
+   * 
+   * @author king
+   * @since April 27, 2005
+   */
+  static class LineInfo {
+    
+    /** The left position. */
+    int left;
+    /** The right position. */
+    int right;
+    /** The y position. */
+    int y;  
+    
+    /**
+     * Sets the line info.
+     * 
+     * @param left  Previous left position.
+     * @param right  Previous right position.
+     * @param y  Y position.
+     */
+    void setInfo(int left, int right, int y) {
+      this.left = left;
+      this.right = right;
+      this.y = y;
+    }
+  }
+  /** The array used for fast flood fill. Instantiated only once to improve performance. */
+  private ArrayList<LineInfo> linearNRTodo = new ArrayList<LineInfo>();
+  /** The index into linear non-recursive fill. */
+  private int index;
+  
+  /** True, if antialised fill should be used. */
+  private boolean antialiased = true;
+  /** The raw image data to fill. */
+  private int[] image; 
+  /** The raw mask image data with the borders. */
+  private int[] maskImage; 
+  /** The start x position for the fill. */
+  private int startX;
+  /** The start y position for the fill. */
+  private int startY;
+  /** The fill color to use for the original image. */
+  private int fillColor; 
+  /** The fill color to use for the mask image. */
+  private int maskColor;
+  /** The pattern fill color to use. */
+  private int patternColor;
+  /** The width of the chessboard pattern. */
+  private int patternWidth;
+  /** The height of the chessboard pattern. */
+  private int patternHeight;
+  /** The color to replace with the fill color. */
+  private int startColor; 
+  /** The width of the image to fill. */
+  private int width; 
+  /** The height of the image to fill. */
+  private int height; 
+  
+  /** The result image. */
+  private BufferedImage bufferedImage;
+  /** The mask image used. */
+  private BufferedImage bufferedMaskImage;
+  
+  
+  /**
+   * Constructor for flood fill, requires the image for filling operation.
+   * 
+   * @param imageToFill  The image used for filling.
+   */
+  public FloodFill(Image imageToFill) {
+    this(imageToFill, null);
+  }
+  
+  /**
+   * Constructor for flood fill, requires the image and mask for filling operation.
+   * 
+   * @param imageToFill  The image used for filling.
+   * @param maskImage    The image containing the border lines.
+   */
+  public FloodFill(Image imageToFill, Image maskImage) {
+    // sets image to fill
+    setImage(imageToFill);
+    
+    // sets the mask
+    setMask(maskImage);
+  }
+  
+  /**
+   * Returns true, if antialiased filling is used.
+   * 
+   * @return  True, for antialiased filling.
+   */
+  public boolean isAntialiased() {
+    return this.antialiased;
+  }
+  
+  /**
+   * Sets if antialiased filling is used.
+   * 
+   * @param antialiased  True, for antialiased filling.
+   */
+  public void setAntialiased(boolean antialiased) {
+    this.antialiased = antialiased;
+  }
+   
+  /**
+   * Returns the width of the fill area.
+   * 
+   * @return  The width of the fill area.
+   */
+  public int getWidth() {
+    return this.width;
+  }
+  
+  /**
+   * Returns the height of the fill area.
+   * 
+   * @return  The height of the fill area.
+   */
+  public int getHeight() {
+    return this.height;
+  }
+  
+  /**
+   * Returns the image that was filled.
+   * 
+   * @return  The image that was filled.
+   */
+  public BufferedImage getImage() {
+    return bufferedImage;
+  }
+  
+  /**
+   * Sets the image to be filled. 
+   * 
+   * @param imageToFill  The image to be filled.
+   */
+  public void setImage(Image imageToFill) {
+    // copy image to fill into buffered image first 
+    width = imageToFill.getWidth(null); 
+    height = imageToFill.getHeight(null); 
+    bufferedImage = new BufferedImage(width, height, BufferedImage.TYPE_INT_ARGB);
+    Graphics g = bufferedImage.getGraphics();
+    g.drawImage(imageToFill, 0, 0, null);
+    
+    // get fill image
+    this.image = ((DataBufferInt)bufferedImage.getRaster().getDataBuffer()).getData();
+  }
+  
+  /**
+   * Returns the mask containing the fill borders.
+   * 
+   * @return  The mask with the fill borders.
+   */
+  public BufferedImage getMask() {
+    return bufferedMaskImage;
+  }
+  
+  /**
+   * Sets the mask image which contains the borders.
+   * 
+   * @param maskImage  The mask image to set. If null, the image to fill is used as
+   *                   the mask.
+   */
+  public void setMask(Image maskImage) {
+    this.bufferedMaskImage = new BufferedImage(width, height, BufferedImage.TYPE_INT_ARGB);
+    Graphics g = this.bufferedMaskImage.getGraphics();
+
+    if (maskImage == null) {
+      // if no mask, use the original image to fill
+      g.drawImage(this.bufferedImage, 0, 0, null);
+    }
+    else {
+      // if mask, use it
+      g.drawImage(maskImage, 0, 0, null);
+    }
+    
+    this.maskImage = bufferedMaskImage.getRGB(0, 0, width, height, null, 0, width);      
+  }
+  /**
+   * Flood fills parts of an image. 
+   * 
+   * @param x  The x coordinate to start filling.
+   * @param y  The y coordinate to start filling.
+   * @param color  The new fill color.
+   */
+  public void fill(int x, int y, Color color) {
+    this.startX = x;
+    this.startY = y;
+    this.fillColor = color.getRGB();  
+    this.maskColor = color.getRGB();  // the fill color for the mask
+    this.startColor = this.maskImage[startY * width + startX]; 
+    if (fillColor != startColor) {
+      floodFill();
+    }
+  }
+  
+  /**
+   * Fills a bounded area of an image. Uses a chessboard pattern. The width in pixels
+   * of the chessboard pattern can be specified.
+   * 
+   * @param x  The x coordinate to start filling.
+   * @param y  The y coordinate to start filling.
+   * @param color  The new fill color.
+   * @param patternColor  The color of the pattern to use.
+   * @param patternWidth  The width of the chessboard pattern.
+   * @param patternHeight  The height of the chessboard pattern.
+   */
+  public void fill(int x, int y, Color color, Color patternColor, int patternWidth, int patternHeight) {
+    this.startX = x;
+    this.startY = y;
+    this.fillColor = color.getRGB();
+    this.patternColor = patternColor.getRGB();
+    this.patternWidth = (patternWidth > 0) ? patternWidth : Integer.MAX_VALUE;
+    this.patternHeight = (patternHeight > 0) ? patternHeight : Integer.MAX_VALUE;
+    this.startColor = this.maskImage[startY * width + startX]; 
+    
+    // the fill color for the mask
+    this.maskColor = ((this.fillColor >> 2) & 0x3F3F3F3F) 
+                   + ((this.patternColor >> 1) & 0x7F7F7F7F);      
+    
+    if (this.maskColor != this.startColor) {
+      // mask color ok (=different)
+      floodFill2();
+    }
+    else {
+      // create new mask color first
+      this.maskColor = ((this.fillColor >> 1) & 0x7F7F7F7F) 
+                     + ((this.patternColor >> 2) & 0x3F3F3F3F);      
+      floodFill2();
+    }
+  }
+  
+  /** 
+   * Fills the line at (x, y). Then fills the line above and below the current line. 
+   * The border is defined as any color except the start color. Non-recursive version,
+   * doesn't have JVM stack size limitations.
+   */ 
+  private void floodFill() { 
+    // init stack
+    linearNRTodo.clear();
+    index = 0;
+    floodFill(startX, startY); 
+
+    // loop through todo list
+    while (index < linearNRTodo.size()) {
+      // get loop data
+      LineInfo lineInfo = linearNRTodo.get(index);
+      index++;
+      int y = lineInfo.y;
+      int left = lineInfo.left;
+      int right = lineInfo.right;
+      
+      // check top
+      if (y > 0) {
+        int yOff = (y - 1) * width;
+        int x = left;
+        while (x <= right) {
+          if (maskImage[yOff + x] == startColor) {
+            x = floodFill(x, y - 1);
+          }
+          else {
+            // fill antialised if allowed
+            if (antialiased) {
+              int antialiasedColor = maskImage[yOff + x];
+              antialiasedColor = (antialiasedColor >> 1) & 0x7F7F7F7F;
+              antialiasedColor = antialiasedColor + ((fillColor >> 1) & 0x7F7F7F7F);      
+              if (antialiasedColor != startColor) {
+                image[yOff + x] = antialiasedColor;
+              }
+            }
+          }
+          x++;
+        }
+      }
+
+      // check bottom
+      if (y < height - 1) {
+        int yOff = (y + 1) * width;
+        int x = left;
+        while (x <= right) {
+          if (maskImage[yOff + x] == startColor) {
+            x = floodFill(x, y + 1);
+          }
+          else {
+            // fill antialised if allowed
+            if (antialiased) {
+              int antialiasedColor = maskImage[yOff + x];
+              antialiasedColor = (antialiasedColor >> 1) & 0x7F7F7F7F;
+              antialiasedColor = antialiasedColor + ((fillColor >> 1) & 0x7F7F7F7F);      
+              if (antialiasedColor != startColor) {
+                image[yOff + x] = antialiasedColor;
+              }
+            }
+          }
+          x++;
+        }
+      }
+    } 
+  } 
+  
+  /** 
+   * Fills the line at (x, y). And adds to the stack. 
+   * 
+   * @param x  The x-coordinate of the start position.
+   * @param y  The y-coordinate of the start position.
+   * @return Right.
+   */ 
+  private int floodFill(int x, int y) { 
+    int yOff = y * width;
+    
+    // fill left of (x,y) until border or edge of image
+    int left = x;
+    do {
+      image[yOff + left] = fillColor;
+      maskImage[yOff + left] = maskColor;
+      left--;
+    } 
+    while ((left >= 0) && (maskImage[yOff + left] == startColor));
+    // fill antialised if allowed
+    if ((antialiased) && (left >= 0)) {
+      int antialiasedColor = maskImage[yOff + left];
+      antialiasedColor = (antialiasedColor >> 1) & 0x7F7F7F7F;
+      antialiasedColor = antialiasedColor + ((fillColor >> 1) & 0x7F7F7F7F);      
+      if (antialiasedColor != startColor) {
+        image[yOff + left] = antialiasedColor;
+      }
+    }
+    left++;
+    
+    // fill right of (x, y) until border or edge of image
+    int right = x;
+    do {
+      image[yOff + right] = fillColor;
+      maskImage[yOff + right] = maskColor;
+      right++;
+    } 
+    while ((right < width) && (maskImage[yOff + right] == startColor));
+    // fill antialised if allowed
+    if ((antialiased) && (right < width)) {
+      int antialiasedColor = maskImage[yOff + right];
+      antialiasedColor = (antialiasedColor >> 1) & 0x7F7F7F7F;
+      antialiasedColor = antialiasedColor + ((fillColor >> 1) & 0x7F7F7F7F);      
+      if (antialiasedColor != startColor) {
+        image[yOff + right] = antialiasedColor;
+      }
+    }
+    right--;
+       
+    // add to stack
+    if (index == 0) {
+      LineInfo lineInfo = new LineInfo();
+      lineInfo.setInfo(left, right, y);
+      linearNRTodo.add(lineInfo);
+    }
+    else {
+      index--;
+      linearNRTodo.get(index).setInfo(left, right, y);
+    }
+    
+    // return right position
+    return right; 
+  }
+  
+  /** 
+   * Fills the line at (x, y). Then fills the line above and below the current line. 
+   * The border is defined as any color except the start color. Non-recursive version,
+   * doesn't have JVM stack size limitations.
+   */ 
+  private void floodFill2() { 
+    // init stack
+    linearNRTodo.clear();
+    index = 0;
+    floodFill2(startX, startY); 
+
+    // loop through todo list
+    while (index < linearNRTodo.size()) {
+      // get loop data
+      LineInfo lineInfo = linearNRTodo.get(index);
+      index++;
+      int y = lineInfo.y;
+      int left = lineInfo.left;
+      int right = lineInfo.right;
+      
+      // check top
+      if (y > 0) {
+        int yOff = (y - 1) * width;
+        int x = left;
+        while (x <= right) {
+          if (maskImage[yOff + x] == startColor) {
+            x = floodFill2(x, y - 1);
+          }
+          else {
+            // fill antialised if allowed
+            if (antialiased) {
+              int antialiasedColor = maskImage[yOff + x];
+              antialiasedColor = (antialiasedColor >> 1) & 0x7F7F7F7F;
+              antialiasedColor = antialiasedColor + ((fillColor2(x, y - 1) >> 1) & 0x7F7F7F7F);      
+              if (antialiasedColor != startColor) {
+                image[yOff + x] = antialiasedColor;
+              }
+            }
+          }
+          x++;
+        }
+      }
+
+      // check bottom
+      if (y < height - 1) {
+        int yOff = (y + 1) * width;
+        int x = left;
+        while (x <= right) {
+          if (maskImage[yOff + x] == startColor) {
+            x = floodFill2(x, y + 1);
+          }
+          else {
+            // fill antialised if allowed
+            if (antialiased) {
+              int antialiasedColor = maskImage[yOff + x];
+              antialiasedColor = (antialiasedColor >> 1) & 0x7F7F7F7F;
+              antialiasedColor = antialiasedColor + ((fillColor2(x, y + 1) >> 1) & 0x7F7F7F7F);      
+              if (antialiasedColor != startColor) {
+                image[yOff + x] = antialiasedColor;
+              }
+            }
+          }
+          x++;
+        }
+      }
+    } 
+  } 
+  
+  /** 
+   * Fills the line at (x, y). And adds to the stack. 
+   * 
+   * @param x  The x-coordinate of the start position.
+   * @param y  The y-coordinate of the start position.
+   * @return Right.
+   */ 
+  private int floodFill2(int x, int y) { 
+    int yOff = y * width;
+    
+    // fill left of (x,y) until border or edge of image
+    int left = x;
+    do {
+      image[yOff + left] = fillColor2(left, y);
+      maskImage[yOff + left] = maskColor;
+      left--;
+    } 
+    while ((left >= 0) && (maskImage[yOff + left] == startColor));
+    // fill antialised if allowed
+    if ((antialiased) && (left >= 0)) {
+      int antialiasedColor = maskImage[yOff + left];
+      antialiasedColor = (antialiasedColor >> 1) & 0x7F7F7F7F;
+      antialiasedColor = antialiasedColor + ((fillColor2(left, y) >> 1) & 0x7F7F7F7F);      
+      if (antialiasedColor != startColor) {
+        image[yOff + left] = antialiasedColor;
+      }
+    }
+    left++;
+    
+    // fill right of (x, y) until border or edge of image
+    int right = x;
+    do {
+      image[yOff + right] = fillColor2(right, y);
+      maskImage[yOff + right] = maskColor;
+      right++;
+    } 
+    while ((right < width) && (maskImage[yOff + right] == startColor));
+    // fill antialised if allowed
+    if ((antialiased) && (right < width)) {
+      int antialiasedColor = maskImage[yOff + right];
+      antialiasedColor = (antialiasedColor >> 1) & 0x7F7F7F7F;
+      antialiasedColor = antialiasedColor + ((fillColor2(right, y) >> 1) & 0x7F7F7F7F);      
+      if (antialiasedColor != startColor) {
+        image[yOff + right] = antialiasedColor;
+      }
+    }
+    right--;
+       
+    // add to stack
+    if (index == 0) {
+      LineInfo lineInfo = new LineInfo();
+      lineInfo.setInfo(left, right, y);
+      linearNRTodo.add(lineInfo);
+    }
+    else {
+      index--;
+      linearNRTodo.get(index).setInfo(left, right, y);
+    }
+    
+    // return right position
+    return right; 
+  }  
+  
+  /** 
+   * Returns the fill color for a given x and y value.
+   *
+   * @param x  The x position to return the color for.
+   * @param y  The y position to return the color for.
+   * @return  The color for the given position.
+   */
+  private int fillColor2(int x, int y) {
+    x /= this.patternWidth;
+    y /= this.patternHeight;
+    if ((x + y) % 2 == 0) {
+      return this.fillColor;
+    }
+    else {
+      return this.patternColor;
+    }
+  }
+}  

+ 39 - 0
src/main/java/com/its/app/utils/IOUtils.java

@@ -0,0 +1,39 @@
+package com.its.app.utils;
+
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+
+public class IOUtils {
+    private static final int DEFAULT_BUFFER_SIZE = 1024 * 4;
+
+    public static byte[] toByteArray(InputStream input) throws IOException {
+        ByteArrayOutputStream output = new ByteArrayOutputStream();
+        copy(input, output);
+        return output.toByteArray();
+    }
+
+    public static int copy(InputStream input, OutputStream output)
+            throws IOException {
+        long count = copyLarge(input, output);
+        if (count > Integer.MAX_VALUE) {
+            return -1;
+        }
+        return (int) count;
+    }
+
+    public static long copyLarge(InputStream input, OutputStream output)
+            throws IOException {
+        byte[] buffer = new byte[DEFAULT_BUFFER_SIZE];
+        long count = 0;
+        int n = 0;
+        while (-1 != (n = input.read(buffer))) {
+            output.write(buffer, 0, n);
+            count += n;
+        }
+
+        return count;
+
+    }
+}

+ 392 - 0
src/main/java/com/its/app/utils/ItsUtils.java

@@ -0,0 +1,392 @@
+package com.its.app.utils;
+
+import lombok.extern.slf4j.Slf4j;
+import org.apache.commons.io.FileUtils;
+
+import javax.imageio.ImageIO;
+import javax.servlet.http.HttpServletRequest;
+import java.awt.image.BufferedImage;
+import java.io.*;
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.nio.file.Paths;
+import java.text.ParseException;
+import java.text.SimpleDateFormat;
+import java.util.*;
+
+@Slf4j
+public final class ItsUtils
+{
+	// 요일유형
+	public static final String UNKNOWN_WEEK = "DTW0";
+	public static final String MONDAY       = "DTW1";
+	public static final String TUESDAY      = "DTW2";
+	public static final String WEDNESDAY    = "DTW3";
+	public static final String THURSDAY     = "DTW4";
+	public static final String FRIDAY       = "DTW5";
+	public static final String SATURDAY     = "DTW6";
+	public static final String SUNDAY       = "DTW7";
+
+	public static String getCurrFiveMinString() {
+		Calendar cal = Calendar.getInstance();
+		cal.setTime(new Date());
+		cal.set(Calendar.SECOND, 0);
+		cal.set(Calendar.MILLISECOND, 0);
+		int min = cal.get(Calendar.MINUTE);
+		cal.add(Calendar.MINUTE, -(min % 5));
+		return new SimpleDateFormat("yyyyMMddHHmmss").format(cal.getTime());
+	}
+
+	public static Date getPrcsDt(String prcsDt) {
+		SimpleDateFormat transFormat = new SimpleDateFormat("yyyyMMddHHmmss");
+		Date to = null;
+		try {
+			to = transFormat.parse(prcsDt);
+		} catch (ParseException e) {
+			log.error("getPrcsDt: ParseException");
+		}
+		return to;
+	}
+
+	public static String getMissSttsYn(String prcsDt) {
+
+		if (prcsDt == null || prcsDt.length() != 14) {
+			return "Y";
+		}
+
+		Date startDateTime = getPrcsDt(prcsDt);
+		if (startDateTime == null) {
+			return "Y";
+		}
+		Calendar currDateTime = Calendar.getInstance();
+
+		GregorianCalendar gcStartDateTime = new GregorianCalendar();
+		GregorianCalendar gcEndDateTime = new GregorianCalendar();
+		gcStartDateTime.setTime(startDateTime);
+		gcEndDateTime.setTime(currDateTime.getTime());
+
+		long gap = gcEndDateTime.getTimeInMillis() - gcStartDateTime.getTimeInMillis();
+		long min = gap / 1000L / 60L;
+		return min > 10 ? "Y" : "N";
+	}
+
+	public static String getRseCommStts(String prcsDt) {
+
+		if (prcsDt == null || prcsDt.length() != 14) {
+			return "CMS1";
+		}
+
+		Date startDateTime = getPrcsDt(prcsDt);
+		if (startDateTime == null) {
+			return "CMS1";
+		}
+		Calendar currDateTime = Calendar.getInstance();
+
+		GregorianCalendar gcStartDateTime = new GregorianCalendar();
+		GregorianCalendar gcEndDateTime = new GregorianCalendar();
+		gcStartDateTime.setTime(startDateTime);
+		gcEndDateTime.setTime(currDateTime.getTime());
+
+		long gap = gcEndDateTime.getTimeInMillis() - gcStartDateTime.getTimeInMillis();
+		long min = gap / 1000L / 60L;
+		return min > 30 ? "CMS1" : "CMS0";
+	}
+
+	public static String getServiceYn(String prcsDt) {
+
+		if (prcsDt == null || prcsDt.length() != 14) {
+			return "N";
+		}
+
+		Date startDateTime = getPrcsDt(prcsDt);
+		if (startDateTime == null) {
+			return "N";
+		}
+		Calendar currDateTime = Calendar.getInstance();
+
+		GregorianCalendar gcStartDateTime = new GregorianCalendar();
+		GregorianCalendar gcEndDateTime = new GregorianCalendar();
+		gcStartDateTime.setTime(startDateTime);
+		gcEndDateTime.setTime(currDateTime.getTime());
+
+		long gap = gcEndDateTime.getTimeInMillis() - gcStartDateTime.getTimeInMillis();
+		long min = gap / 1000L / 60L;
+		return min > 10 ? "N" : "Y";
+	}
+
+	public static String getMissYn(String prcsDt, String CMTR_GRAD_CD) {
+
+		if (("LTC0").equals(CMTR_GRAD_CD)) {
+			return "Y";
+		}
+		if (prcsDt == null || prcsDt.length() != 14) {
+			return "Y";
+		}
+
+		Date startDateTime = getPrcsDt(prcsDt);
+		if (startDateTime == null) {
+			return "Y";
+		}
+		Calendar currDateTime = Calendar.getInstance();
+
+		GregorianCalendar gcStartDateTime = new GregorianCalendar();
+		GregorianCalendar gcEndDateTime = new GregorianCalendar();
+		gcStartDateTime.setTime(startDateTime);
+		gcEndDateTime.setTime(currDateTime.getTime());
+
+		long gap = gcEndDateTime.getTimeInMillis() - gcStartDateTime.getTimeInMillis();
+		long min = gap / 1000L / 60L;
+		return min > 10 ? "Y" : "N";
+	}
+	public static Date stringToDate(String paramTime) {
+		SimpleDateFormat transFormat = new SimpleDateFormat("yyyyMMddHHmmss");
+		Date to = null;
+		try {
+			to = transFormat.parse(paramTime);
+		} catch (ParseException e) {
+			log.error("stringToDate: ParseException");
+		}
+
+		return to;
+	}
+
+	public static int getDiffMinutes(String fromDt, String toDt) {
+		Date dtFrom = stringToDate(fromDt);
+		Date dtTo = stringToDate(toDt);
+		GregorianCalendar gcFromDt= new GregorianCalendar();
+		GregorianCalendar gcToDt = new GregorianCalendar();
+		gcFromDt.setTime(dtFrom);
+		gcToDt.setTime(dtTo);
+		long gap = gcToDt.getTimeInMillis() - gcFromDt.getTimeInMillis();
+		long min = gap / 1000L / 60L;
+		return (int)min;
+	}
+
+	// 0--6: Sunday = 0, C/C++ struct tm, tm_wday
+	// 1--7: oracle, SELECT TO_CHAR(SYSDATE, 'D') FROM DUAL;, 주중의 일을 1~7로 표시(일요일이 1)
+	//     : java, Calendar cal; cal.get(Calendar.DAY_OF_WEEK, sunday=1, monday=2, ...)
+	public static String getDayOfWeek() {
+		Date dtNow = new Date();
+		int week = getDayWeek(dtNow);
+		return getDayOfWeek(week);
+	}
+	public static String getDayOfWeek(int week) {
+
+		String sWeek = UNKNOWN_WEEK;
+		switch(week)
+		{
+			case 1: sWeek = SUNDAY; 	break;
+			case 2: sWeek = MONDAY; 	break;
+			case 3: sWeek = TUESDAY; 	break;
+			case 4: sWeek = WEDNESDAY; 	break;
+			case 5: sWeek = THURSDAY; 	break;
+			case 6: sWeek = FRIDAY; 	break;
+			case 7: sWeek = SATURDAY; 	break;
+		}
+		return sWeek;
+	}
+	public static int getDayWeek(String paramDt) {
+		return getDayWeek(stringToDate(paramDt));
+	}
+	public static int getDayWeek(Date paramDt) {
+		Calendar cal = Calendar.getInstance();
+		cal.setTime(paramDt);
+		return cal.get(Calendar.DAY_OF_WEEK);		/* DAY_OF_WEEK 리턴값이 일요일(1), 월요일(2), 화요일(3) ~~ 토요일(7)을 반환합니다. */
+	}
+
+	public static String getFromToday()
+	{
+		SimpleDateFormat sdfDate = new SimpleDateFormat("yyyyMMdd");
+		Date dtNow = new Date();
+		return sdfDate.format(dtNow)+"000000";
+	}
+
+	public static String getSysTime()
+	{
+		SimpleDateFormat sdfDate = new SimpleDateFormat("yyyyMMddHHmmss");
+		Date dtNow = new Date();
+		return sdfDate.format(dtNow);
+	}
+
+	public static String getSysTime(String format)
+	{
+		SimpleDateFormat sdfDate = new SimpleDateFormat(format);
+		Date dtNow = new Date();
+		return sdfDate.format(dtNow);
+	}
+	public static String getSysMonth()
+	{
+		SimpleDateFormat sdfDate = new SimpleDateFormat("yyyyMM");
+		Date dtNow = new Date();
+		return sdfDate.format(dtNow);
+	}
+	public static String getSysDay()
+	{
+		SimpleDateFormat sdfDate = new SimpleDateFormat("yyyyMMdd");
+		Date dtNow = new Date();
+		return sdfDate.format(dtNow);
+	}
+	/**
+	 * 월 마지막날 가져오기 * @param yyyyMM
+	 * @return : yyyyMMdd
+	 */
+	public static String getLastDayOfMonth(String yyyyMMdd) {
+
+		String year  = yyyyMMdd.substring(0, 4);
+		String month = yyyyMMdd.substring(4, 6);
+
+		Calendar cal = Calendar.getInstance();
+		cal.set(Integer.parseInt(year), Integer.parseInt(month) - 1, 1);
+		String lastDay = year + month + Integer.toString(cal.getActualMaximum(Calendar.DAY_OF_MONTH));
+
+		return lastDay;
+	}
+
+	public static boolean saveByteArrayToFile(String filePath, byte[] byteArrayData) {
+		boolean result = true;
+		try {
+			FileUtils.writeByteArrayToFile(new File(filePath), byteArrayData);
+		}
+		catch (IOException e) {
+			log.error("saveByteArrayToFile: IOException");
+			result = false;
+		}
+		return result;
+	}
+
+	public static byte[] convertBmpToPng(byte[] bmpArrayData) {
+		ByteArrayOutputStream out = new ByteArrayOutputStream();
+		ByteArrayInputStream inStream = new ByteArrayInputStream(bmpArrayData);
+
+		try {
+			BufferedImage newImage = ImageIO.read(inStream);
+			ImageIO.write(newImage, "png", out);
+			return out.toByteArray();
+		}
+		catch (IOException e) {
+			log.error("saveByteArrayToFile: IOException");
+		}
+		finally {
+			try {
+				out.close();
+				inStream.close();
+			} catch (IOException e) {
+				log.error("saveByteArrayToFile: out close IOException");
+			}
+		}
+		return null;
+	}
+
+	public static String createUserDir(String userDir) {
+
+		final String sysDir = System.getProperty("user.dir");
+		String createdDir = sysDir + userDir;
+		try {
+			Path path = Paths.get(createdDir);
+			//java.nio.file.Files;
+			Files.createDirectories(path);
+
+		}
+		catch (IOException e) {
+			log.error("createUserDir: IOException");
+		}
+		return createdDir;
+	}
+	public static synchronized void saveImageFile(BufferedImage image, String extension, String fullPath)
+	{
+		try (
+			OutputStream out2 = new FileOutputStream(fullPath);
+		) {
+			ImageIO.write(image, extension, out2);
+			out2.close();
+			//RenderedImage rendImage = image;
+			//ImageIO.write(image, "bmp", new File(fullPath));
+		}
+		catch (IOException e) {
+			log.error("saveImageFile: IOException");
+		}
+	}
+
+/*
+	public static byte[] bitmapToByteArray( Bitmap bitmap ) {
+		ByteArrayOutputStream stream = new ByteArrayOutputStream() ;
+		bitmap.compress( Bitmap.CompressFormat.PNG, 100, stream) ;
+		byte[] byteArray = stream.toByteArray() ;
+		return byteArray ;
+	}
+	public static Bitmap byteArrayToBitmap(byte[] bytearr) {
+		return BitmapFactory.decodeByteArray(bytearr, 0, bytearr.length);
+	}*/
+
+/**
+ * Bitmap bitmap;
+ *
+ * ByteBuffer buffer= ByteBuffer.Allocate(bitmap.ByteCount);
+ * bitmap.copyPixelsToBuffer(buffer);
+ * byte[] byteArray = buffer.ToArray<byte>();
+ *
+ * byte[] byteArray;
+ * Bitmap bitmap;
+ *
+ * int width = 112;
+ * int height = 112;
+ *
+ * bitmap = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888);
+ * ByteBuffer buffer = ByteBuffer.wrap(byteArray);
+ * buffer.rewind();
+ * bitmap.copyPixelsFromBuffer(buffer);
+ */
+
+	public static List<String> split(String value, String delim) {
+
+		List<String> list = new ArrayList<String>();
+
+		StringTokenizer stringTokenizer = new StringTokenizer(value, delim);
+		while (stringTokenizer.hasMoreTokens()) {
+			list.add(stringTokenizer.nextToken().trim());
+		}
+
+		return list;
+	}
+
+	public static int swapEndian(int x) {
+		return swapEndian((short)x) << 16 | swapEndian((short)(x >> 16)) & 0xFFFF;
+	}
+
+	public static short swapEndian(short x) {
+		return (short)(x << 8 | x >> 8 & 0xFF);
+	}
+
+
+	public static String getHttpServletRemoteIP(HttpServletRequest request) {
+		if (request == null) {
+			return "";
+		}
+
+		String ipAddress = request.getHeader("X-FORWARDED-FOR");
+		// proxy 환경일 경우
+		if (ipAddress == null || ipAddress.length() == 0 || "unknown".equalsIgnoreCase(ipAddress)) {
+			ipAddress = request.getHeader("Proxy-Client-IP");
+		}
+		// 웹로직 서버일 경우
+		if (ipAddress == null || ipAddress.length() == 0 || "unknown".equalsIgnoreCase(ipAddress)) {
+			ipAddress = request.getHeader("WL-Proxy-Client-IP");
+		}
+		if (ipAddress == null || ipAddress.length() == 0 || "unknown".equalsIgnoreCase(ipAddress)) {
+			ipAddress = request.getHeader("HTTP_CLIENT_IP");
+		}
+		if (ipAddress == null || ipAddress.length() == 0 || "unknown".equalsIgnoreCase(ipAddress)) {
+			ipAddress = request.getHeader("HTTP_X_FORWARDED_FOR");
+		}
+		// 기타
+		if (ipAddress == null || ipAddress.length() == 0 || "unknown".equalsIgnoreCase(ipAddress)) {
+			ipAddress = request.getRemoteAddr() ;
+		}
+		//-Djava.net.preferIPv4Stack=true
+		if (ipAddress.equals("0:0:0:0:0:0:0:1"))   //==> ipv6 <== default
+		{
+			ipAddress = "127.0.0.1";   //==> localhost
+		}
+		return ipAddress;
+	}
+}

+ 246 - 0
src/main/java/com/its/app/utils/NettyUtils.java

@@ -0,0 +1,246 @@
+package com.its.app.utils;
+
+import io.netty.channel.Channel;
+import io.netty.channel.EventLoopGroup;
+import io.netty.channel.epoll.Epoll;
+import io.netty.channel.epoll.EpollEventLoopGroup;
+import io.netty.channel.epoll.EpollServerSocketChannel;
+import io.netty.channel.epoll.EpollSocketChannel;
+import io.netty.channel.nio.NioEventLoopGroup;
+import io.netty.channel.socket.ServerSocketChannel;
+import io.netty.channel.socket.SocketChannel;
+import io.netty.channel.socket.nio.NioServerSocketChannel;
+import io.netty.channel.socket.nio.NioSocketChannel;
+import io.netty.util.concurrent.DefaultThreadFactory;
+import lombok.extern.slf4j.Slf4j;
+
+import java.net.*;
+import java.util.ArrayList;
+import java.util.Enumeration;
+
+@Slf4j
+public final class NettyUtils {
+
+    public static String getTcpAddress(Channel ch) {
+        String localIp = "local-unknown";
+        String remoteIp = "remote-unknown";
+        int localPort = 0;
+        int remotePort = 0;
+        InetSocketAddress localAddr = (InetSocketAddress)ch.localAddress();
+        if (localAddr != null) {
+            localIp = localAddr.getAddress().getHostAddress();
+            localPort = localAddr.getPort();
+        }
+
+        InetSocketAddress remoteAddr = (InetSocketAddress)ch.remoteAddress();
+        if (remoteAddr != null) {
+            remoteIp = remoteAddr.getAddress().getHostAddress();
+            remotePort = remoteAddr.getPort();
+        }
+        return "[Local #(" + localIp + ":" + localPort + ") Remote #(" + remoteIp + ":" + remotePort + ")]";
+    }
+    public static String getRemoteAddress(Channel ch) {
+        String ip = getRemoteIpAddress(ch);
+        int  port = getRemotePort(ch);
+        return "[Remote #(" + ip + ":" + port + ")]";
+    }
+
+    public static String getLocalAddress(Channel ch) {
+        String ip = getLocalIpAddress(ch);
+        int  port = getLocalPort(ch);
+        return "[Local #(" + ip + ":" + port + ")]";
+    }
+
+    public static String getRemoteIpAddress(Channel ch) {
+        String ip = "unknown";
+        InetSocketAddress inetAddr = (InetSocketAddress)ch.remoteAddress();
+        if (inetAddr != null) {
+            ip = inetAddr.getAddress().getHostAddress();
+        }
+        return ip;
+    }
+
+    public static int getRemotePort(Channel ch) {
+        int port = 0;
+        InetSocketAddress inetAddr = (InetSocketAddress)ch.remoteAddress();
+        if (inetAddr != null)
+            port = inetAddr.getPort();
+        return port;
+    }
+
+    public static String getLocalIpAddress(Channel ch) {
+        String ip = "unknown";
+        InetSocketAddress inetAddr = (InetSocketAddress)ch.localAddress();
+        if (inetAddr != null) {
+            ip = inetAddr.getAddress().getHostAddress();
+        }
+        return ip;
+    }
+
+    public static int getLocalPort(Channel ch) {
+        int port = 0;
+        InetSocketAddress inetAddr = (InetSocketAddress)ch.localAddress();
+        if (inetAddr != null)
+            port = inetAddr.getPort();
+        return port;
+    }
+    public static boolean isEpollAvailable() {
+        // Netty epoll transport does not work with WSL (Windows Sybsystem for Linux) yet.
+/*
+        boolean HAS_WSLENV = System.getenv("WSLENV") != null;
+        return Epoll.isAvailable() && !HAS_WSLENV;
+*/
+        return Epoll.isAvailable();
+    }
+
+    public static EventLoopGroup newEventLoopGroup(int nThreads, String threadPoolName) {
+        if (isEpollAvailable()) {
+            if (threadPoolName.equals("")) {
+                return new EpollEventLoopGroup(nThreads);
+            }
+            else {
+                return new EpollEventLoopGroup(nThreads, new DefaultThreadFactory("epo"+threadPoolName));
+            }
+        } else {
+            if (threadPoolName.equals("")) {
+                return new NioEventLoopGroup(nThreads);
+            }
+            else {
+                return new NioEventLoopGroup(nThreads, new DefaultThreadFactory("nio" + threadPoolName));
+            }
+        }
+    }
+
+    public static Class<? extends SocketChannel> getSocketChannel() {
+        if (isEpollAvailable()) {
+            return EpollSocketChannel.class;
+        } else {
+            return NioSocketChannel.class;
+        }
+    }
+
+    public static Class<? extends ServerSocketChannel> getServerSocketChannel() {
+        if (isEpollAvailable()) {
+            return EpollServerSocketChannel.class;
+        } else {
+            return NioServerSocketChannel.class;
+        }
+    }
+
+    public static final String OS_NAME = System.getProperty("os.name");
+    private static boolean isLinuxPlatform = false;
+    private static boolean isWindowsPlatform = false;
+
+    static {
+        if (OS_NAME != null && OS_NAME.toLowerCase().contains("linux")) {
+            isLinuxPlatform = true;
+        }
+
+        if (OS_NAME != null && OS_NAME.toLowerCase().contains("windows")) {
+            isWindowsPlatform = true;
+        }
+    }
+
+    public static String getLocalAddress() {
+        // Traversal Network interface to get the first non-loopback and non-private address
+        Enumeration<NetworkInterface> enumeration = null;
+        try {
+            enumeration = NetworkInterface.getNetworkInterfaces();
+        } catch (SocketException e) {
+            log.error("getLocalAddress: getNetworkInterfaces");
+            return null;
+        }
+        ArrayList<String> ipv4Result = new ArrayList<String>();
+        ArrayList<String> ipv6Result = new ArrayList<String>();
+        while (enumeration.hasMoreElements()) {
+            final NetworkInterface networkInterface = enumeration.nextElement();
+            final Enumeration<InetAddress> en = networkInterface.getInetAddresses();
+            while (en.hasMoreElements()) {
+                final InetAddress address = en.nextElement();
+                if (!address.isLoopbackAddress()) {
+                    if (address instanceof Inet6Address) {
+                        ipv6Result.add(normalizeHostAddress(address));
+                    } else {
+                        ipv4Result.add(normalizeHostAddress(address));
+                    }
+                }
+            }
+        }
+
+        // prefer ipv4
+        if (!ipv4Result.isEmpty()) {
+            for (String ip : ipv4Result) {
+                if (ip.startsWith("127.0") || ip.startsWith("192.168")) {
+                    continue;
+                }
+                return ip;
+            }
+
+            return ipv4Result.get(ipv4Result.size() - 1);
+        } else if (!ipv6Result.isEmpty()) {
+            return ipv6Result.get(0);
+        }
+        //If failed to find,fall back to localhost
+        final InetAddress localHost;
+        try {
+            localHost = InetAddress.getLocalHost();
+        } catch (UnknownHostException e) {
+            log.error("getLocalAddress: UnknownHostException");
+            return null;
+        }
+        return normalizeHostAddress(localHost);
+    }
+
+    public static String normalizeHostAddress(final InetAddress localHost) {
+        if (localHost instanceof Inet6Address) {
+            return "[" + localHost.getHostAddress() + "]";
+        } else {
+            return localHost.getHostAddress();
+        }
+    }
+
+    public static SocketAddress string2SocketAddress(final String addr) {
+        String[] s = addr.split(":");
+        InetSocketAddress isa = new InetSocketAddress(s[0], Integer.parseInt(s[1]));
+        return isa;
+    }
+
+    public static String socketAddress2String(final SocketAddress addr) {
+        StringBuilder sb = new StringBuilder();
+        InetSocketAddress inetSocketAddress = (InetSocketAddress) addr;
+        sb.append(inetSocketAddress.getAddress().getHostAddress());
+        sb.append(":");
+        sb.append(inetSocketAddress.getPort());
+        return sb.toString();
+    }
+
+    public static String parseChannelRemoteAddr(final Channel channel) {
+        if (null == channel) {
+            return "";
+        }
+        SocketAddress remote = channel.remoteAddress();
+        final String addr = remote != null ? remote.toString() : "";
+
+        if (addr.length() > 0) {
+            int index = addr.lastIndexOf("/");
+            if (index >= 0) {
+                return addr.substring(index + 1);
+            }
+
+            return addr;
+        }
+
+        return "";
+    }
+
+    public static String parseSocketAddressAddr(SocketAddress socketAddress) {
+        if (socketAddress != null) {
+            final String addr = socketAddress.toString();
+
+            if (addr.length() > 0) {
+                return addr.startsWith("/") ? addr.substring(1) : addr;
+            }
+        }
+        return "";
+    }
+}

+ 8 - 0
src/main/java/com/its/app/utils/OS.java

@@ -0,0 +1,8 @@
+package com.its.app.utils;
+
+public class OS {
+    static final private String OS = System.getProperty("os.name").toLowerCase();
+    public static boolean isWindows() {
+        return OS.contains("win");
+    }
+}

+ 26 - 0
src/main/java/com/its/app/utils/Ping.java

@@ -0,0 +1,26 @@
+package com.its.app.utils;
+
+import java.io.IOException;
+import java.net.InetAddress;
+
+public class Ping {
+    public static boolean isReachable(String host, int timeoutSec) throws IOException, InterruptedException {
+
+        if (OS.isWindows())
+            return Ping.winPing(host);
+
+        return Ping.unixPing(host, timeoutSec);
+    }
+
+    private static boolean winPing(String host) throws IOException, InterruptedException {
+        String cmd = "cmd /c ping -n 1 " + host + " | find \"TTL\"";
+        Process proc = Runtime.getRuntime().exec(cmd);
+        int exit = proc.waitFor();
+        return (exit == 0) ? true : false;
+    }
+
+    private static boolean unixPing(String host, int timeoutSec) throws IOException {
+        InetAddress targetIp = InetAddress.getByName(host);
+        return targetIp.isReachable(timeoutSec*1000);
+    }
+}

+ 301 - 0
src/main/java/com/its/app/utils/StatisticsTime.java

@@ -0,0 +1,301 @@
+package com.its.app.utils;
+
+import java.text.ParseException;
+import java.text.SimpleDateFormat;
+import java.util.Calendar;
+import java.util.Date;
+
+public class StatisticsTime {
+
+	private final int processingTime_BEFORE  = 0;
+	//private final int processingTime_CURRENT = 1;
+
+	/*
+	 * 모든 시각은 'YYYYMMDDHH24MISS' 형태로 사용한다.
+	 */
+	private String prcsDayWeek;			/* 요일 유형 */
+	private String prcsDayQuater;		/* 분기 */
+
+	private String prcsCurrTime;		/* 20170718153504 - 현재시각 */
+	private String prcsCurrFiveMin;		/* 20170718153500 - 현재 정주기 5분 시각 */
+	private String prcsCurrFiveMinTo;   /* 20170718153459 - 현재 정주기 5분 시각 - 1초 */
+	private String prcsPrevFiveMin;		/* 20170718153000 - 이전 정주기 5분 시각 */
+
+	private String stat15MinTime;
+	private String stat15MinFrom;
+	private String stat15MinTo;
+	private String statHourTime;
+	private String statHourFrom;
+	private String statHourTo;
+	private String statDayFrom;
+	private String statDayTo;
+	private String statMonFrom;
+	private String statMonTo;
+	private String statYearFrom;
+	private String statYearTo;
+
+	private boolean isStat15Min = false;
+	private boolean isStatHour  = false;
+	private boolean isStatDay   = false;
+	private boolean isStatMon   = false;
+	private boolean isStatYear  = false;
+
+	private boolean isPatternUpdate = false;
+
+	private int analysisTime = processingTime_BEFORE;		/* 이전주기시각(0)/현재주기시각(1) */
+	private int month, hour, min;
+
+	private boolean isProcessing = false;
+	private Date    startDate;
+	private Date    endDate;
+
+	public StatisticsTime() {
+		startDate = new Date();
+		endDate   = new Date();
+	}
+
+	public void setProcessing(boolean isProcessing) {
+		this.isProcessing = isProcessing;
+		if (this.isProcessing) {
+			startDate = new Date();
+		}
+		else {
+			endDate = new Date();
+		}
+	}
+	public boolean IsProcessing() { return this.isProcessing; }
+	public Date    getStartDate() { return this.startDate; }
+	public Date    getEndDate()   { return this.endDate; }
+
+	public int getAnalysisTime() { return this.analysisTime; }
+	public void setAnalysisTime(int analysisTime) { this.analysisTime = analysisTime; }
+
+	public boolean isStat15Min() { return this.isStat15Min; }
+	public boolean isStatHour()  { return this.isStatHour; }
+	public boolean isStatDay()   { return this.isStatDay; }
+	public boolean isStatMon()   { return this.isStatMon; }
+	public boolean isStatYear()   { return this.isStatYear; }
+
+	public boolean isPatternUpdate() { return this.isPatternUpdate; }
+
+	public String getStat15MinTime() {
+		if (this.analysisTime == processingTime_BEFORE)
+			return this.stat15MinFrom;
+		return this.stat15MinTime;
+	}
+	public String getStat15MinFrom() { return this.stat15MinFrom; }
+	public String getStat15MinTo()   { return this.stat15MinTo; }
+	public String getStatHourTime() {
+		if (this.analysisTime == processingTime_BEFORE)
+			return this.statHourFrom;
+		return this.statHourTime;
+	}
+	public String getStatHourFrom()  { return this.statHourFrom; }
+	public String getStatHourTo()    { return this.statHourTo; }
+	public String getStatDayFrom()   { return this.statDayFrom; }
+	public String getStatDayTo()     { return this.statDayTo; }
+	public String getStatMonFrom()   { return this.statMonFrom; }
+	public String getStatMonTo()     { return this.statMonTo; }
+	public String getStatYearFrom()  { return this.statYearFrom; }
+	public String getStatYearTo()    { return this.statYearTo; }
+
+	public String getPrcsDayWeek()   { return this.prcsDayWeek; }
+	public String getPrcsDayQuater() { return this.prcsDayQuater; }
+
+	public String getCurrTime() { return this.prcsCurrTime;	 }
+	public String getPrcsFiveMin() {
+		/*
+		 * 정주기 5분 가공시각으로 DB에 저장하는 시각, 현재시각 이전정주기 5분 시각을 사용한다.
+		 * 만일, 현재정주기 5분 시각을 사용하려 한다면 prcsCurrFiveMin 를 사용한다.
+		 */
+		if (this.analysisTime == processingTime_BEFORE)
+			return this.prcsPrevFiveMin;
+
+		return this.prcsCurrFiveMin;
+	}
+
+	public String getCurrFiveMin()     { return this.prcsCurrFiveMin; }
+	public String getPrcsFiveMinFrom() { return this.prcsPrevFiveMin; }
+	public String getPrcsFiveMinTo()   { return this.prcsCurrFiveMinTo; }
+
+	public String calDate(String paramTm, int addSec/*초단위*/) {
+		String result = paramTm;
+		SimpleDateFormat transFormat = new SimpleDateFormat("yyyyMMddHHmmss");
+		try {
+			Date to = new Date();
+			addSec = addSec * 1000;	/* mili-second로 변환 */
+			to.setTime(transFormat.parse(paramTm).getTime() + addSec);
+			result = TimeUtils.dateToString(to, "yyyyMMddHHmmss");
+		} catch (ParseException e) {
+			e.printStackTrace();
+		}
+		return result;
+	}
+
+	public String calDateFormat(String paramFmt, String paramTm, int addSec) {
+		String result = paramTm;
+		SimpleDateFormat transFormat = new SimpleDateFormat("yyyyMMddHHmmss");
+		try {
+			Date to = new Date();
+			addSec = addSec * 1000;	/* mili-second로 변환 */
+			to.setTime(transFormat.parse(paramTm).getTime() + addSec);
+			result = TimeUtils.dateToString(to, paramFmt);
+		} catch (ParseException e) {
+			e.printStackTrace();
+		}
+		return result;
+	}
+
+	public String calLastDayFormat(String paramFmt, String paramTm) {
+		String result = paramTm;
+		SimpleDateFormat transFormat = new SimpleDateFormat("yyyyMMddHHmmss");
+		try {
+			Date to = new Date();
+			to.setTime(transFormat.parse(paramTm).getTime());
+			Calendar cal = Calendar.getInstance();
+			cal.setTime(to);
+			int day = cal.getActualMaximum(Calendar.DATE);
+
+			cal.set(Calendar.DAY_OF_MONTH, day);
+			return new SimpleDateFormat(paramFmt).format(cal.getTime());
+		} catch (ParseException e) {
+			e.printStackTrace();
+		}
+		return result;
+	}
+
+	public void setPrcsTimeInfo() {
+		Calendar cal = Calendar.getInstance();
+		try {
+			cal.setTime(TimeUtils.stringToDate(this.prcsCurrTime));
+		} catch (Exception e) {
+			e.printStackTrace();
+		}
+
+		/* 년월일시분초는 현재시각 기준으로 계산 */
+		//this.year  = cal.get(Calendar.YEAR);
+		this.month = cal.get(Calendar.MONTH) + 1;
+		//this.day   = cal.get(Calendar.DAY_OF_MONTH);
+		this.hour  = cal.get(Calendar.HOUR_OF_DAY);
+		this.min   = cal.get(Calendar.MINUTE);
+		//this.sec   = cal.get(Calendar.SECOND);
+
+		/* 요일, 사사분기는 가공시각을 기준으로 계산 */
+		try {
+			cal.setTime(TimeUtils.stringToDate(getPrcsFiveMin()));
+		} catch (Exception e) {
+			e.printStackTrace();
+		}
+		//DAY_OF_WEEK 리턴값이 일요일(1), 월요일(2), 화요일(3) ~~ 토요일(7)을 반환합니다.
+		this.prcsDayWeek   = String.valueOf(cal.get(Calendar.DAY_OF_WEEK));
+		this.prcsDayQuater = String.valueOf((this.month/3)+1);
+	}
+
+	public void initValue() {
+		this.prcsDayWeek   = "";		/* 요일 유형 */
+		this.prcsDayQuater = "";		/* 분기 */
+
+		this.prcsCurrTime      = "";	/* 20170718153504 - 현재시각 */
+		this.prcsCurrFiveMin   = "";	/* 20170718153500 - 현재 정주기 5분 시각 */
+		this.prcsCurrFiveMinTo = "";    /* 20170718153459 - 현재 정주기 5분 시각 - 1초 */
+		this.prcsPrevFiveMin   = "";	/* 20170718153000 - 이전 정주기 5분 시각 */
+
+		this.stat15MinTime = "";
+		this.stat15MinFrom = "";
+		this.stat15MinTo   = "";
+		this.statHourTime  = "";
+		this.statHourFrom  = "";
+		this.statHourTo    = "";
+		this.statDayFrom   = "";
+		this.statDayTo     = "";
+		this.statMonFrom   = "";
+		this.statMonTo     = "";
+
+		this.isStat15Min = false;
+		this.isStatHour  = false;
+		this.isStatDay   = false;
+		this.isStatMon   = false;
+		this.isStatYear  = false;
+
+		this.isPatternUpdate = false;
+	}
+	public void init() {
+
+		initValue();
+
+		/*
+		 * 시간대 계산은 아직 안함(추후 시간대 계산이 필요하면 여기서 하면 됨)
+		 */
+		this.prcsCurrTime = TimeUtils.getCurrentTimeString();
+
+		Date dt = null;
+		try {
+			dt = TimeUtils.stringToDate(this.prcsCurrTime);
+		} catch (Exception e) {
+			e.printStackTrace();
+		}
+
+		this.prcsCurrFiveMin   = TimeUtils.getFiveMinString(dt);
+		this.prcsCurrFiveMinTo = calDate(this.prcsCurrFiveMin, -1);		/* 현재 정주기 시각에서 -1초 */
+		this.prcsPrevFiveMin   = calDate(this.prcsCurrFiveMin, -60*5); 	/* 20170718153000 - 이전 정주기 5분 시각 */
+
+		setPrcsTimeInfo();
+
+		/*
+		 * 5분 정주기 가공이 끝나고 15분 주기일 경우(00, 15, 30, 45 분 일경우 15분 통계 정보를 생성한다)
+		 */
+		if (this.min % 15 == 0) {
+			this.isStat15Min = true;
+		}
+		this.stat15MinFrom = calDate(this.prcsCurrFiveMin, -60*15);
+		this.stat15MinTo   = calDate(this.stat15MinFrom,   (60*15)-1);
+		this.stat15MinTime = calDate(this.stat15MinFrom,   (60*15));
+
+		/*
+		 * 매시 5분 가공이 끝나면 1시간 통계 정보를 생성한다.
+		 */
+		if (this.min == 5) {
+			this.isStatHour = true;
+		}
+		String statHour = calDateFormat("yyyyMMddHH", this.prcsCurrFiveMin, -60*60);
+		this.statHourFrom = statHour + "0000";
+		this.statHourTo   = statHour + "5959";
+		this.statHourTime = calDateFormat("yyyyMMddHH", this.prcsCurrFiveMin, 0) + "0000";
+
+		/*
+		 * 00시 10분 가공이 끝나면 이전일의 통계 정보를 가공.
+		 */
+		if (this.hour == 0 && this.min == 10) {
+			this.isStatDay = true;
+		}
+		String statDay = calDateFormat("yyyyMMdd", this.prcsCurrFiveMin, -60*60*24);
+		this.statDayFrom = statDay + "000000";
+		this.statDayTo   = statDay + "235959";
+
+		/*
+		 * 02시 10분 가공이 끝나면 이전일의 월통계 정보를 누적 가공.
+		 */
+		if (this.hour == 2 && this.min == 10) {
+			this.isStatMon = true;
+		}
+		this.statMonFrom = calDateFormat("yyyyMM", this.prcsCurrFiveMin, -60*60*24) + "01000000";
+		this.statMonTo   = calLastDayFormat("yyyyMMdd", this.statMonFrom)           +   "235959";
+
+		/*
+		 * 02시 35분 가공이 끝나면 이전일의 연통계 정보를 누적 가공.
+		 */
+		if (this.hour == 2 && this.min == 35) {
+			this.isStatYear = true;
+		}
+		this.statYearFrom = calDateFormat("yyyy", this.prcsCurrFiveMin, -60*60*24) + "0101000000";
+		this.statYearTo   = calLastDayFormat("yyyy", this.statMonFrom)           +   "1231235959";
+
+		/*
+		 * 패턴업데이트 시각 체크: 매일 새벽 3시 20분
+		 */
+		if (this.hour == 3 && this.min == 20) {
+			this.isPatternUpdate = true;
+		}
+	}
+
+}

+ 20 - 0
src/main/java/com/its/app/utils/StringUtils.java

@@ -0,0 +1,20 @@
+package com.its.app.utils;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.StringTokenizer;
+
+public class StringUtils {
+
+    public static List<String> split(String value, String delim) {
+
+        List<String> list = new ArrayList<String>();
+
+        StringTokenizer stringTokenizer = new StringTokenizer(value, delim);
+        while (stringTokenizer.hasMoreTokens()) {
+            list.add(stringTokenizer.nextToken().trim());
+        }
+
+        return list;
+    }
+}

+ 250 - 0
src/main/java/com/its/app/utils/SysUtils.java

@@ -0,0 +1,250 @@
+package com.its.app.utils;
+
+import java.nio.ByteBuffer;
+import java.nio.ByteOrder;
+import java.text.SimpleDateFormat;
+import java.util.Calendar;
+import java.util.Date;
+import java.util.GregorianCalendar;
+
+public final class SysUtils
+{
+    public static int toInt(String paramVal, int defVal) {
+    	int result = defVal;
+    	try {
+    		result = Integer.parseInt(paramVal);
+    	} catch(Exception e) {
+    	}
+    	return result;
+    }
+
+    public static float toFloat(String paramVal, float defVal) {
+    	float result = defVal;
+    	try {
+    		result = Float.parseFloat(paramVal);
+    	} catch(Exception e) {
+    	}
+    	return result;
+    }
+    
+    public static double toDouble(String paramVal, double defVal) {
+    	double result = defVal;
+    	try {
+    		result = Double.parseDouble(paramVal);
+    	} catch(Exception e) {
+    	}
+    	return result;
+    }
+
+	public static String getSysTime()
+	{
+		SimpleDateFormat sdfDate = new SimpleDateFormat("yyyyMMddHHmmss");
+		Date dtLog = new Date();
+		return sdfDate.format(dtLog);
+	}
+	public static String getSysTimeStr() {
+		SimpleDateFormat sdfDate = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
+		Date dtLog = new Date();
+		return sdfDate.format(dtLog);
+	}
+	public static String getSysTimeStrMMDD() {
+		SimpleDateFormat sdfDate = new SimpleDateFormat("MM-dd HH:mm:ss");
+		Date dtLog = new Date();
+		return sdfDate.format(dtLog);
+	}
+
+	public static int gapTime(String startTm, String endTm, int calcType) {
+
+		if (startTm == null || startTm.equals("") || startTm.length() != 14) {
+			return -1;
+		}
+		if (endTm == null || endTm.equals("") || endTm.length() != 14) {
+			return -1;
+		}
+
+		Date startDateTime, endDateTime;
+/*
+		FastDateFormat fastDateFormat = FastDateFormat.getInstance("yyyyMMddHHmmss", new Locale("ko_KR")); //Locale.getDefault());
+		try {
+			startDateTime = fastDateFormat.parse(startTm);
+			endDateTime = fastDateFormat.parse(endTm);
+		} catch (ParseException e) {
+			e.printStackTrace();
+			return -1;
+		}
+*/
+		startDateTime = TimeUtils.stringToDate(startTm);
+		endDateTime = TimeUtils.stringToDate(endTm);
+		if (startDateTime == null || endDateTime == null) {
+			return -1;
+		}
+
+		GregorianCalendar gcStartDateTime = new GregorianCalendar();
+		GregorianCalendar gcEndDateTime = new GregorianCalendar();
+		gcStartDateTime.setTime(startDateTime);
+		gcEndDateTime.setTime(endDateTime);
+
+		long gap = gcEndDateTime.getTimeInMillis() - gcStartDateTime.getTimeInMillis();
+		long hour = gap / 1000L / 60L / 60L;
+		long min = gap / 1000L / 60L;
+		long second = gap / 1000L;
+		if (Calendar.HOUR == calcType)
+			return (int)hour;
+		if (Calendar.MINUTE == calcType)
+			return (int)min;
+		if (Calendar.SECOND == calcType)
+			return (int)second;
+		return -1;
+	}
+
+	public static String byteArrayToString(byte[] data) {
+		StringBuilder sb = new StringBuilder(data.length);
+		for (int ii = 0; ii < data.length; ++ ii) {
+			if (data[ii] >= 0x21 && data[ii] <= 0x7E) {
+				sb.append((char) data[ii]);
+			}
+			else {
+				break;
+			}
+		}
+		return sb.toString();
+	}
+
+	public static String byteArrayToHex(byte[] AData)
+	{
+		if ((AData == null) || (AData.length == 0)) {
+			return "";
+		}
+
+		int ALen = AData.length;
+		int line = ALen / 16;
+		int pos;
+
+		StringBuffer sb = new StringBuffer((ALen*3)+line);
+		sb.append("\r\n");
+		for (int ii = 0; ii < ALen; ii += 16)
+		{
+			for (int jj = 0; jj < 16; jj++) {
+				pos = ii + jj;
+				if (pos < ALen) {
+					String hexNumber = "0" + Integer.toHexString(0xFF & AData[pos]).toUpperCase();
+					sb.append(hexNumber.substring(hexNumber.length() - 2));
+					sb.append(" ");
+				}
+				else {
+					break;
+				}
+			}
+			sb.append("\r\n");
+		}
+		return sb.toString();
+	}
+
+	public static int getBitValue(byte b, int pos) {
+		int val = (b >> pos) & 0x01;
+		return val;
+	}
+
+	public static long ipToLong(String ipAddress) {
+		String[] ipAddressInArray = ipAddress.split("\\.");
+		long result = 0;
+		for (int i = 0; i < ipAddressInArray.length; i++) {
+			int power = 3 - i;
+			int ip = Integer.parseInt(ipAddressInArray[i]);
+			result += ip * Math.pow(256, power);
+		}
+		return result;
+	}
+	public static long ipToLong2(String ipAddress) {
+		long result = 0;
+		String[] ipAddressInArray = ipAddress.split("\\.");
+
+		for (int i = 3; i >= 0; i--) {
+			long ip = Long.parseLong(ipAddressInArray[3 - i]);
+			//left shifting 24,16,8,0 and bitwise OR
+			//1. 192 << 24
+			//1. 168 << 16
+			//1. 1   << 8
+			//1. 2   << 0
+			result |= ip << (i * 8);
+		}
+		return result;
+	}
+	public static String longToIp(long i) {
+
+		return ((i >> 24) & 0xFF) +
+				"." + ((i >> 16) & 0xFF) +
+				"." + ((i >> 8) & 0xFF) +
+				"." + (i & 0xFF);
+
+	}
+	public static String longToIp2(long ip) {
+		StringBuilder sb = new StringBuilder(15);
+
+		for (int i = 0; i < 4; i++) {
+			// 1. 2
+			// 2. 1
+			// 3. 168
+			// 4. 192
+			sb.insert(0, Long.toString(ip & 0xff));
+
+			if (i < 3) {
+				sb.insert(0, '.');
+			}
+			// 1. 192.168.1.2
+			// 2. 192.168.1
+			// 3. 192.168
+			// 4. 192
+			ip = ip >> 8;
+
+		}
+
+		return sb.toString();
+	}
+
+	public static int bytesToInt(byte[] bytes) {
+		return ByteBuffer.wrap(bytes).getInt();
+	}
+	public static int bytesToInt(byte[] bytes, int fromIdx, ByteOrder byteOrder) {
+
+		if (byteOrder == ByteOrder.BIG_ENDIAN) {
+			return (
+					((bytes[fromIdx+0] & 0xFF) << 24) |
+					((bytes[fromIdx+1] & 0xFF) << 16) |
+					((bytes[fromIdx+2] & 0xFF) << 8 ) |
+					((bytes[fromIdx+3] & 0xFF) << 0 )
+			);
+		}
+		return (
+				((bytes[fromIdx+3] & 0xFF) << 24) |
+				((bytes[fromIdx+2] & 0xFF) << 16) |
+				((bytes[fromIdx+1] & 0xFF) << 8 ) |
+				((bytes[fromIdx+0] & 0xFF) << 0 )
+		);
+	}
+	public static byte[] intToBytes(int value) {
+		// BIG_ENDIAN
+		return  ByteBuffer.allocate(4).putInt(value).array();
+	}
+
+	public static int bytesToShort(byte[] bytes) {
+		return ByteBuffer.wrap(bytes).getShort();
+	}
+	public static int bytesToShort(byte[] bytes, int fromIdx, ByteOrder byteOrder) {
+
+		if (byteOrder == ByteOrder.BIG_ENDIAN) {
+			return (
+					((bytes[fromIdx+0] & 0xFF) << 8) |
+					((bytes[fromIdx+1] & 0xFF) << 0 )
+			);
+		}
+		return (
+				((bytes[fromIdx+1] & 0xFF) << 8 ) |
+				((bytes[fromIdx+0] & 0xFF) << 0 )
+		);
+	}
+	public static byte[] shortToBytes(short value) {
+		// BIG_ENDIAN
+		return  ByteBuffer.allocate(2).putShort(value).array();
+	}
+}

+ 216 - 0
src/main/java/com/its/app/utils/TimeUtils.java

@@ -0,0 +1,216 @@
+package com.its.app.utils;
+
+import java.text.ParseException;
+import java.text.SimpleDateFormat;
+import java.util.Calendar;
+import java.util.Date;
+
+public class TimeUtils {
+
+	public static final int TYPE_CURR_05MIN = 0;
+	public static final int TYPE_PRCS_05MIN = 1;
+	public static final int TYPE_PRCS_15MIN = 2;
+	public static final int TYPE_PRCS_30MIN = 3;
+	public static final int TYPE_PRCS_HOUR  = 4;
+	public static final int TYPE_PRCS_DAY   = 5;
+	public static final int TYPE_PRCS_MONTH = 6;
+	public static final int TYPE_PRCS_YEAR  = 7;
+
+	/* 현재 시각을 문자열로 리턴 */
+	public static String getCurrentTimeString() {
+		Calendar cal = Calendar.getInstance();
+		return new SimpleDateFormat("yyyyMMddHHmmss").format(cal.getTime());
+	}
+	public static String getCurrentTimeString(String parmaFmt) {
+		Calendar cal = Calendar.getInstance();
+		return new SimpleDateFormat(parmaFmt).format(cal.getTime());
+	}
+	public static Date getCurrentDate() {
+		Calendar cal = Calendar.getInstance();
+		return cal.getTime();
+	}
+
+	public static Date stringToDate(String paramTime) {
+		SimpleDateFormat transFormat = new SimpleDateFormat("yyyyMMddHHmmss");
+		Date to = null;
+		try {
+			to = transFormat.parse(paramTime);
+		} catch (ParseException e) {
+			e.printStackTrace();
+		}
+		return to;
+	}
+
+	public static String dateToString(Date paramDt, String paramFmt) {
+		Calendar cal = Calendar.getInstance();
+		cal.setTime(paramDt);
+		return new SimpleDateFormat(paramFmt).format(cal.getTime());
+	}
+	public static String dateToString(Date paramDt) {
+		Calendar cal = Calendar.getInstance();
+		cal.setTime(paramDt);
+		return new SimpleDateFormat("yyyyMMddHHmmss").format(cal.getTime());
+	}
+
+	/* 현재 시각을 second 로 리턴 */
+	public static long getCurrentTimeSeconds() {
+		Calendar cal = Calendar.getInstance();
+		return Math.round(cal.getTimeInMillis() / 1000.0);
+	}
+	/* 현재 시각을 milli second 로 리턴 */
+	public static long getCurrentTimeMilliSeconds() {
+		Calendar cal = Calendar.getInstance();
+		return cal.getTimeInMillis();
+	}
+
+	/* 정주기 현재 5분 시각 */
+	public static String getFiveMinString(Date paramDt) {
+		Calendar cal = Calendar.getInstance();
+		cal.setTime(paramDt);
+		cal.set(Calendar.SECOND, 0);
+		cal.set(Calendar.MILLISECOND, 0);
+		int min = cal.get(Calendar.MINUTE);
+		cal.add(Calendar.MINUTE, -(min % 5));
+		return new SimpleDateFormat("yyyyMMddHHmmss").format(cal.getTime());
+	}
+	public static String getFiveMinString() {
+		Calendar cal = Calendar.getInstance();
+		return getFiveMinString(cal.getTime());
+	}
+
+	private static String getItsTimeString(Date paramDt, int cycle, int period) {
+		Calendar cal = Calendar.getInstance();
+		cal.setTime(paramDt);
+		cal.set(Calendar.SECOND, 0);
+		cal.set(Calendar.MILLISECOND, 0);
+		int min = cal.get(Calendar.MINUTE);
+		cal.add(Calendar.MINUTE, -(min % cycle) - (cycle * period));
+		return new SimpleDateFormat("yyyyMMddHHmmss").format(cal.getTime());
+	}
+
+	private static String getItsTimeToString(Date paramDt, int type) {
+		Calendar cal = Calendar.getInstance();
+		cal.setTime(paramDt);
+		switch(type) {
+			case TYPE_CURR_05MIN:
+			case TYPE_PRCS_05MIN: cal.add(Calendar.MINUTE, 5); break;
+			case TYPE_PRCS_15MIN: cal.add(Calendar.MINUTE, 15); break;
+			case TYPE_PRCS_30MIN: cal.add(Calendar.MINUTE, 30); break;
+			case TYPE_PRCS_HOUR:  cal.add(Calendar.HOUR_OF_DAY, 1); break;
+			case TYPE_PRCS_DAY:   cal.add(Calendar.DATE, 1); break;
+			case TYPE_PRCS_MONTH: cal.add(Calendar.MONTH, 1); break;
+			case TYPE_PRCS_YEAR: cal.add(Calendar.YEAR, 1); break;
+		}
+		cal.add(Calendar.SECOND, -1);
+		return new SimpleDateFormat("yyyyMMddHHmmss").format(cal.getTime());
+	}
+
+	public static String getTime(int type) {
+		Calendar cal = Calendar.getInstance();
+		return getTime(cal.getTime(), type);
+	}
+	public static String getTime(String paramStr, int type) {
+		Calendar cal = Calendar.getInstance();
+		cal.setTime(stringToDate(paramStr));
+		return getTime(cal.getTime(), type);
+	}
+	public static String getTime(Date paramDt, int type) {
+		switch(type) {
+			case TYPE_CURR_05MIN: return getItsTimeString(paramDt, 5, 0);
+			case TYPE_PRCS_05MIN: return getItsTimeString(paramDt, 5, 1);
+			case TYPE_PRCS_15MIN: return getItsTimeString(paramDt, 15, 1);
+			case TYPE_PRCS_30MIN: return getItsTimeString(paramDt, 30, 1);
+			case TYPE_PRCS_HOUR:  return getItsTimeString(paramDt, 60, 1);
+			case TYPE_PRCS_DAY:   return getItsTimeString(paramDt, 60*24, 1).substring(0, 8) + "000000";
+			case TYPE_PRCS_MONTH: return getItsTimeString(paramDt, 60*24, 1).substring(0, 6) + "01000000";
+			case TYPE_PRCS_YEAR:  return getItsTimeString(paramDt, 60*24, 1).substring(0, 4) + "0101000000";
+		}
+		return "";
+	}
+	public static String getToTime(int type) {
+		String prcsTime = getTime(type);
+		return getToTime(prcsTime, type);
+	}
+	public static String getToTime(String paramStr, int type) {
+		Calendar cal = Calendar.getInstance();
+		cal.setTime(stringToDate(paramStr));
+		return getToTime(cal.getTime(), type);
+	}
+	public static String getToTime(Date paramDt, int type) {
+		return getItsTimeToString(paramDt, type);
+	}
+
+	public static String getCurrMin() {
+		Calendar cal = Calendar.getInstance();
+		return getItsTimeString(cal.getTime(), 5, 0);
+	}
+	public static String getCurrMin(String paramStr) {
+		return getItsTimeString(stringToDate(paramStr), 5, 0);
+	}
+	public static String getCurrMin(Date paramDt) {
+		return getItsTimeString(paramDt, 5, 0);
+	}
+
+	public static String get05Min() {
+		Calendar cal = Calendar.getInstance();
+		return getItsTimeString(cal.getTime(), 5, 1);
+	}
+	public static String get05Min(String paramStr) {
+		return getItsTimeString(stringToDate(paramStr), 5, 1);
+	}
+	public static String get05Min(Date paramDt) {
+		return getItsTimeString(paramDt, 5, 1);
+	}
+
+	public static String get15Min() {
+		Calendar cal = Calendar.getInstance();
+		return getItsTimeString(cal.getTime(), 15, 1);
+	}
+	public static String get15Min(String paramStr) {
+		return getItsTimeString(stringToDate(paramStr), 15, 1);
+	}
+	public static String get15Min(Date paramDt) {
+		return getItsTimeString(paramDt, 15, 1);
+	}
+
+	public static String getHour() {
+		Calendar cal = Calendar.getInstance();
+		return getItsTimeString(cal.getTime(), 60, 1);
+	}
+	public static String getHour(String paramStr) {
+		return getItsTimeString(stringToDate(paramStr), 60, 1);
+	}
+	public static String getHour(Date paramDt) {
+		return getItsTimeString(paramDt, 60, 1);
+	}
+
+	public static String getDay() {
+		Calendar cal = Calendar.getInstance();
+		return getItsTimeString(cal.getTime(), 60*24, 1).substring(0, 8) + "000000";
+	}
+	public static String getDay(String paramStr) {
+		return getItsTimeString(stringToDate(paramStr), 60*24, 1).substring(0, 8) + "000000";
+	}
+	public static String getDay(Date paramDt) {
+		return getItsTimeString(paramDt, 60*24, 1).substring(0, 8) + "000000";
+	}
+
+	public static String getToString(Date paramDt) {
+		Calendar cal = Calendar.getInstance();
+		cal.setTime(paramDt);
+		cal.add(Calendar.SECOND, -1);	/* 주어진 시각에서 1초를 뺀 시각 */
+		return new SimpleDateFormat("yyyyMMddHHmmss").format(cal.getTime());
+	}
+
+	public static String getFiveMinToString(Date paramDt) {
+		String strFiveMin = getFiveMinString(paramDt);
+		Date   dtFiveMin = stringToDate(strFiveMin);
+		return getToString(dtFiveMin);
+	}
+	public static String getFiveMinToString() {
+		Calendar cal = Calendar.getInstance();
+		return getFiveMinToString(cal.getTime());
+	}
+
+
+}

+ 210 - 0
src/main/java/com/its/vms/VmsCommServerApplication.java

@@ -0,0 +1,210 @@
+package com.its.vms;
+
+import com.its.app.AppUtils;
+import com.its.app.utils.OS;
+import com.its.app.utils.SysUtils;
+import com.its.vms.config.ApplicationConfig;
+import com.its.vms.entity.TbUnitSyst;
+import com.its.vms.process.DbmsDataProcess;
+import com.its.vms.service.*;
+import com.its.vms.ui.JTextAreaOutputStream;
+import com.its.vms.ui.MainUI;
+import com.its.vms.xnettcp.center.CenterTcpServerService;
+import com.its.vms.xnettcp.vms.VmsTcpCommServerService;
+import com.its.vms.xnettcp.vms.process.TcpServerDataProcess;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.beans.factory.DisposableBean;
+import org.springframework.beans.factory.InitializingBean;
+import org.springframework.boot.Banner;
+import org.springframework.boot.CommandLineRunner;
+import org.springframework.boot.SpringApplication;
+import org.springframework.boot.autoconfigure.SpringBootApplication;
+import org.springframework.boot.builder.SpringApplicationBuilder;
+import org.springframework.boot.context.ApplicationPidFileWriter;
+import org.springframework.context.ApplicationContext;
+import org.springframework.context.ApplicationListener;
+import org.springframework.context.annotation.ComponentScan;
+import org.springframework.context.annotation.Configuration;
+import org.springframework.context.event.ContextClosedEvent;
+import org.springframework.core.io.ClassPathResource;
+import org.springframework.scheduling.annotation.EnableAsync;
+
+import javax.swing.*;
+import java.awt.*;
+import java.awt.event.WindowAdapter;
+import java.awt.event.WindowEvent;
+import java.io.File;
+import java.io.IOException;
+import java.io.PrintStream;
+import java.lang.reflect.Field;
+import java.net.URL;
+import java.nio.charset.Charset;
+
+@Slf4j
+@EnableAsync
+@Configuration
+@SpringBootApplication
+@ComponentScan(basePackages = {"com.its.vms.config", "com.its.vms.dao.mapper", "com.its"})
+public class VmsCommServerApplication implements CommandLineRunner, ApplicationListener<ContextClosedEvent>, InitializingBean, DisposableBean {
+
+    private static String applicationName = "vms-comm-server";
+
+    public static void main(String[] args) {
+        System.setProperty("file.encoding","UTF-8");
+        try {
+            Field charset = Charset.class.getDeclaredField("defaultCharset");
+            charset.setAccessible(true);
+            charset.set(null,null);
+        } catch(Exception e){
+        }
+
+        File file1 = new File("./conf/" + applicationName + ".pid");
+        if (file1.exists()) {
+            System.out.println(System.getProperty("Program Already Running....."));
+            log.error("Program Already Running.....");
+        }
+
+        if (OS.isWindows()) {
+            ApplicationContext context = new SpringApplicationBuilder(VmsCommServerApplication.class)
+                    //.web(WebApplicationType.NONE)
+                    .listeners(new ApplicationPidFileWriter("./conf/" + applicationName + ".pid"))
+                    .headless(false)
+                    .bannerMode(Banner.Mode.OFF)
+                    .run(args);
+        } else {
+            SpringApplication application = new SpringApplicationBuilder()
+                    .sources(VmsCommServerApplication.class)
+                    .listeners(new ApplicationPidFileWriter("./conf/" + applicationName + ".pid"))
+                    .build();
+            application.setBannerMode(Banner.Mode.OFF);
+            application.run(args);
+        }
+    }
+
+    @Override
+    public void run(String... args) throws Exception {
+        if (OS.isWindows()) {
+            String sysTime = SysUtils.getSysTimeStr();
+            //JFrame.setDefaultLookAndFeelDecorated(true);
+            JFrame frame = new JFrame("VMS 통신 서버 - [" + sysTime + "]");
+            MainUI UI = new MainUI(frame);
+            SwingUtilities.invokeLater(() -> {
+                try {
+                    ClassPathResource file = new ClassPathResource("static/image/application.png");
+                    URL imgURL = file.getURL();
+                    frame.setIconImage(new ImageIcon(imgURL).getImage());
+                } catch (IOException e) {
+                    log.error("Not found application icon image");
+                }
+                frame.setModalExclusionType(Dialog.ModalExclusionType.APPLICATION_EXCLUDE);
+                frame.setContentPane(UI.getRootPanel());
+                frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
+                frame.addWindowListener(new WindowAdapter() {
+                    @Override
+                    public void windowClosing(WindowEvent e) {
+                        if (JOptionPane.showConfirmDialog(UI.getRootPanel(), "VMS 통신서버 프로그램을 종료 하시겠습니까?", "프로그램 종료", 0) == 0) {
+                            System.exit(0);
+                        } else {
+                            frame.setDefaultCloseOperation(JFrame.DO_NOTHING_ON_CLOSE);
+                        }
+                    }
+                });
+                frame.pack();
+                frame.setBounds(100, 100, 900, 600);
+                frame.setLocationRelativeTo(null);
+                frame.setVisible(true);
+
+                JTextArea logArea = UI.getTaLog();
+                logArea.setText(null);
+                JTextAreaOutputStream out = new JTextAreaOutputStream(logArea);
+                System.setOut(new PrintStream(out));
+            });
+        }
+
+        ApplicationConfig applicationConfig = (ApplicationConfig) AppUtils.getBean(ApplicationConfig.class);
+
+        log.info("");
+        log.info("");
+        log.info("************************************************************************************");
+        log.info("**                                                                                **");
+        log.info("**                         Intelligent Traffic System                             **");
+        log.info("**                      VMS Communication Server Program.                         **");
+        log.info("**                                                                                **");
+        log.info("**                                                                   [ver.1.0]    **");
+        log.info("**          {}", applicationConfig.getId());
+        log.info("** startup: {}", applicationConfig.getBootingDateTime());
+        log.info("************************************************************************************");
+
+        // init application
+        DbmsDataProcess dbmsDataProcess = (DbmsDataProcess)AppUtils.getBean(DbmsDataProcess.class);
+        dbmsDataProcess.run();
+
+        TcpServerDataProcess tcpServerDataProcess = (TcpServerDataProcess)AppUtils.getBean(TcpServerDataProcess.class);
+        tcpServerDataProcess.run();
+
+        UnitSystService unitSystService = (UnitSystService)AppUtils.getBean(UnitSystService.class);
+        unitSystService.loadMaster();
+        unitSystService.updateUnitSystStts(true);
+        TbUnitSyst unit = unitSystService.getUnitSystMap().get(applicationConfig.getId());
+        if (unit != null) {
+            applicationConfig.setListenPort(unit.getPrgmPort());
+        }
+
+        VmsCtlrService ctlrService = (VmsCtlrService)AppUtils.getBean(VmsCtlrService.class);
+        ctlrService.loadDb();
+        ctlrService.updateCtlrStts(true, null);
+
+        VmsFontService vmsFontService = (VmsFontService)AppUtils.getBean(VmsFontService.class);
+        vmsFontService.loadFontInfo();
+
+        VmsIfscService vmsIfscService = (VmsIfscService)AppUtils.getBean(VmsIfscService.class);
+        vmsIfscService.loadVmsIfscInfo();
+
+        // schedule enable
+        applicationConfig.setStartSchedule(true);
+
+        if (OS.isWindows()) {
+            MainUI UI = MainUI.getInstance();
+            if (UI != null) {
+                UI.loadControllerInfo();
+            }
+        }
+
+        VmsSymbService vmsSymbService = (VmsSymbService)AppUtils.getBean(VmsSymbService.class);
+        vmsSymbService.loadVmsSymbInfo();
+
+        VmsAtmpService vmsAtmpService = (VmsAtmpService)AppUtils.getBean(VmsAtmpService.class);
+        vmsAtmpService.loadAtmpInfo();
+
+        VmsTcpCommServerService vmsTcpCommServerService = (VmsTcpCommServerService)AppUtils.getBean(VmsTcpCommServerService.class);
+        vmsTcpCommServerService.run();
+
+        CenterTcpServerService centerService = (CenterTcpServerService)AppUtils.getBean(CenterTcpServerService.class);
+        centerService.run();
+    }
+
+    public void terminateApplication() {
+        UnitSystService unitSystService = (UnitSystService) AppUtils.getBean(UnitSystService.class);
+        unitSystService.updateUnitSystStts(false);
+        VmsCtlrService ctlrService = (VmsCtlrService) AppUtils.getBean(VmsCtlrService.class);
+        ctlrService.updateCtlrStts(false, null);
+
+        CenterTcpServerService centerService = (CenterTcpServerService)AppUtils.getBean(CenterTcpServerService.class);
+        centerService.stop();
+
+        VmsTcpCommServerService vmsTcpCommServerService = (VmsTcpCommServerService)AppUtils.getBean(VmsTcpCommServerService.class);
+        vmsTcpCommServerService.stop();
+    }
+    @Override
+    public void onApplicationEvent(ContextClosedEvent event) {
+        log.error("Application Terminated: {}", event.getTimestamp());
+        terminateApplication();
+    }
+    @Override
+    public void afterPropertiesSet() throws Exception {
+    }
+    @Override
+    public void destroy() throws Exception {
+    }
+
+}

+ 123 - 0
src/main/java/com/its/vms/config/ApplicationConfig.java

@@ -0,0 +1,123 @@
+package com.its.vms.config;
+
+import com.its.app.utils.SysUtils;
+import lombok.Getter;
+import lombok.Setter;
+import lombok.ToString;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.boot.context.properties.ConfigurationProperties;
+import org.springframework.context.annotation.Configuration;
+
+import javax.annotation.PostConstruct;
+import java.io.File;
+import java.nio.file.Path;
+import java.nio.file.Paths;
+
+@Slf4j
+@Getter
+@Setter
+@ToString
+@Configuration
+@ConfigurationProperties(prefix = "application")
+public class ApplicationConfig {
+
+    public static String FTP_FORM = "FORM";
+    public static String FTP_VIDEO = "VIDEO";
+    public static String FTP_STATIC = "STATIC";
+    public static String FTP_IMAGE = "IMAGE";
+
+    private String bootingDateTime;
+    private boolean startSchedule;
+
+    private String id = "VMS01";
+    private String name = "VMS Communication Server";
+    private boolean history = true;
+    private boolean statistics = true;
+
+    private String userId = "admin";
+    private String userPswd = "1234";
+
+    // Center Communication Config
+    private boolean centerCommEnable = true;
+    private int listenPort = 30200;
+    protected String bindingAddr = "0.0.0.0";
+    protected int backlog = 0;
+    protected int acceptThreads = 0;
+    protected int workerThreads = 0;
+    protected int rcvBuf = 0;
+    protected int sndBuf = 0;
+    protected int readerIdleTimeSeconds = 0;
+    protected int writerIdleTimeSeconds = 0;
+    protected int allIdleTimeSeconds = 0;
+    protected int connectTimeoutSeconds = 0;
+
+    private String ftpHomeDir = "./ftp";
+    private String ftpFormDir ;  // FTP Form Directory
+    private String ftpVideoDir;  // FTP Video Directory
+    private String ftpStaticDir; // FTP 정적폼 Directory
+    private String ftpImageDir;  // FTP Image Directory
+
+    @PostConstruct
+    private void init() {
+        this.startSchedule = false;
+
+        final int DEFAULT_EVENT_THREADS  = Runtime.getRuntime().availableProcessors() * 2;
+        if (this.bindingAddr.equals("")) {
+            this.bindingAddr = "0.0.0.0";
+        }
+        if (this.backlog == 0) {
+            this.backlog = 32;
+        }
+        if (this.acceptThreads == 0) {
+            this.acceptThreads = DEFAULT_EVENT_THREADS;
+        }
+        if (this.workerThreads == 0) {
+            this.workerThreads = DEFAULT_EVENT_THREADS;
+        }
+
+        if (this.rcvBuf == 0) {
+            this.rcvBuf = Short.MAX_VALUE / 2;
+        }
+        if (this.sndBuf == 0) {
+            this.sndBuf = Short.MAX_VALUE / 2;
+        }
+
+        this.bootingDateTime = SysUtils.getSysTimeStr();
+
+        if (this.ftpHomeDir == null || this.ftpHomeDir.trim().length() == 0) {
+            Path filePath = Paths.get(System.getProperty("user.dir"), "ftp");
+            this.ftpHomeDir = filePath.toFile().getAbsolutePath();
+        }
+        this.ftpHomeDir = this.ftpHomeDir.trim();
+
+        this.ftpFormDir  = this.ftpHomeDir + File.separator + FTP_FORM + File.separator;  // FTP Form Directory
+        this.ftpVideoDir = this.ftpHomeDir + File.separator + FTP_VIDEO + File.separator;  // FTP Video Directory
+        this.ftpStaticDir = this.ftpHomeDir + File.separator + FTP_STATIC + File.separator; // FTP 정적폼 Directory
+        this.ftpImageDir = this.ftpHomeDir + File.separator + FTP_IMAGE + File.separator;  // FTP Image Directory
+
+        makeDirectory(this.ftpHomeDir, "ftp Home directory");
+        makeDirectory(this.ftpFormDir, "ftp Form directory");
+        makeDirectory(this.ftpVideoDir, "ftp Video directory");
+        makeDirectory(this.ftpStaticDir, "ftp Static Form directory");
+        makeDirectory(this.ftpImageDir, "ftp Image directory");
+
+        log.info("{}", this);
+    }
+
+    public boolean makeDirectory(String path, String desc) {
+        boolean result = false;
+        File folder = new File(path);
+        log.error("{}, {}", folder.getAbsolutePath(), desc);
+        if (!folder.exists()) {
+            try {
+                result = folder.mkdir(); //폴더 생성합니다.
+                log.info("{}, ({}) created.", folder.getAbsolutePath(), desc);
+            }
+            catch(Exception e) {
+                log.error("{}, ({}) create failed. {}.", folder.getAbsolutePath(), desc, e.getMessage());
+            }
+        }
+        return result;
+    }
+
+}

+ 83 - 0
src/main/java/com/its/vms/config/CommunicationConfig.java

@@ -0,0 +1,83 @@
+package com.its.vms.config;
+
+import lombok.Getter;
+import lombok.Setter;
+import lombok.ToString;
+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
+@ToString
+@Configuration
+@ConfigurationProperties(prefix = "communication")
+public class CommunicationConfig {
+
+    private boolean logging = false;
+
+    private String bindingAddr = "";
+    private int listenPort = 30200;
+    private int backLog = 0;
+    private int acceptThreads = 0;
+    private int workerThreads = 0;
+    private int readerIdleTimeSeconds = 0;
+    private int writerIdleTimeSeconds = 0;
+    private int allIdleTimeSeconds = 0;
+
+    private int rcvBuf = 0;
+    private int sndBuf = 0;
+    private int connectTimeoutSeconds = 0;
+    private int maxConnection = 0;
+    private int retrySeconds = 10;
+
+    private boolean dumpRecv = false;
+    private boolean dumpSend = false;
+
+    private boolean subscriptionStatus = true;
+    private int subscriptionStatusCycle = 30;
+
+
+    @PostConstruct
+    private void init() {
+        int DEFAULT_EVENT_THREADS = Runtime.getRuntime().availableProcessors();
+        if (this.bindingAddr.equals("")) {
+            this.bindingAddr = "0.0.0.0";
+        }
+
+        if (this.backLog == 0) {
+            this.backLog = 64;
+        }
+
+        if (this.acceptThreads == 0) {
+            this.acceptThreads = DEFAULT_EVENT_THREADS * 2;
+        }
+
+        if (this.workerThreads == 0) {
+            this.workerThreads = DEFAULT_EVENT_THREADS * 2;
+        }
+
+        if (this.rcvBuf == 0) {
+            this.rcvBuf = 32768;
+        }
+        if (this.sndBuf == 0) {
+            this.sndBuf = 32768;
+        }
+
+        if (this.readerIdleTimeSeconds == 0) {
+            this.readerIdleTimeSeconds = 60;
+        }
+        if (this.connectTimeoutSeconds == 0) {
+            this.connectTimeoutSeconds = 10;
+        }
+
+        if (this.maxConnection == 0) {
+            this.maxConnection = 1024;
+        }
+
+        log.info("{}", this);
+    }
+}

+ 73 - 0
src/main/java/com/its/vms/config/DatabaseConfig.java

@@ -0,0 +1,73 @@
+package com.its.vms.config;
+
+import com.zaxxer.hikari.HikariDataSource;
+import lombok.ToString;
+import lombok.extern.slf4j.Slf4j;
+import org.apache.ibatis.session.SqlSessionFactory;
+import org.mybatis.spring.SqlSessionFactoryBean;
+import org.mybatis.spring.SqlSessionTemplate;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.beans.factory.annotation.Qualifier;
+import org.springframework.beans.factory.annotation.Value;
+import org.springframework.boot.context.properties.ConfigurationProperties;
+import org.springframework.boot.jdbc.DataSourceBuilder;
+import org.springframework.context.ApplicationContext;
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
+import org.springframework.context.annotation.Primary;
+import org.springframework.jdbc.datasource.DataSourceTransactionManager;
+import org.springframework.transaction.annotation.EnableTransactionManagement;
+
+import javax.annotation.PostConstruct;
+import javax.sql.DataSource;
+
+@Slf4j
+@ToString
+@Configuration
+@EnableTransactionManagement
+public class DatabaseConfig {
+
+    @Value("${spring.datasource.hikari.mapper-locations:classpath:mybatis/mapper/**/*.xml}")
+    String mapperLocations;// = "classpath:mybatis/mapper/**/*.xml";
+
+    @PostConstruct
+    private void init() {
+        if (this.mapperLocations.trim().equals("")) {
+            this.mapperLocations = "classpath:mybatis/mapper/**/*.xml";
+        }
+        log.info("mapperLocations: {}", this.mapperLocations);
+        log.info("{}", this);
+    }
+
+    @Primary
+    @Bean(name="dataSource")
+    @ConfigurationProperties(prefix="spring.datasource.hikari")
+    public DataSource dataSource() {
+        //return DataSourceBuilder.create().build();
+        return DataSourceBuilder.create().type(HikariDataSource.class).build();
+    }
+
+    @Primary
+    @Bean(name="sqlSessionFactory")
+    public SqlSessionFactory sqlSessionFactoryBean(@Autowired @Qualifier("dataSource") DataSource dataSource, ApplicationContext applicationContext)
+            throws Exception {
+        log.info("mapperLocations: {}", this.mapperLocations);
+        SqlSessionFactoryBean factoryBean = new SqlSessionFactoryBean();
+        factoryBean.setDataSource(dataSource);
+        //factoryBean.setConfigLocation(applicationContext.getResource("classpath:mybatis/mybatis-config.xml"));
+        factoryBean.setMapperLocations(applicationContext.getResources(this.mapperLocations));
+        return factoryBean.getObject();
+    }
+
+    @Primary
+    @Bean(name="sqlSession")
+    public SqlSessionTemplate sqlSession(@Autowired @Qualifier("sqlSessionFactory") SqlSessionFactory sqlSessionFactory) {
+        return new SqlSessionTemplate(sqlSessionFactory);
+    }
+
+    @Primary
+    @Bean(name="transactionManager")
+    public DataSourceTransactionManager transactionManager(@Autowired @Qualifier("dataSource") DataSource dataSource) {
+        return new DataSourceTransactionManager(dataSource);
+    }
+}

+ 55 - 0
src/main/java/com/its/vms/config/SwaggerConfig.java

@@ -0,0 +1,55 @@
+package com.its.vms.config;
+
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
+import org.springframework.http.HttpHeaders;
+import springfox.documentation.builders.ApiInfoBuilder;
+import springfox.documentation.builders.ParameterBuilder;
+import springfox.documentation.builders.PathSelectors;
+import springfox.documentation.builders.RequestHandlerSelectors;
+import springfox.documentation.schema.ModelRef;
+import springfox.documentation.service.ApiInfo;
+import springfox.documentation.service.Parameter;
+import springfox.documentation.spi.DocumentationType;
+import springfox.documentation.spring.web.plugins.Docket;
+import springfox.documentation.swagger2.annotations.EnableSwagger2;
+
+import java.util.ArrayList;
+import java.util.List;
+
+@Configuration
+@EnableSwagger2
+public class SwaggerConfig {
+
+    @Bean
+    public Docket commonApi() {
+        Parameter parameterBuilder = new ParameterBuilder()
+                .name(HttpHeaders.AUTHORIZATION)
+                .description("Access Token")
+                .modelRef(new ModelRef("string"))
+                .parameterType("header")
+                .required(false)
+                .build();
+
+        List<Parameter> globalParameters = new ArrayList<>();
+        globalParameters.add(parameterBuilder);
+        return new Docket(DocumentationType.SWAGGER_2)
+                .globalOperationParameters(globalParameters)
+                .groupName("rse-api")
+                .apiInfo(this.apiInfo())
+                .select()
+                .apis(RequestHandlerSelectors.basePackage("com.its.dsrc.api.controller"))
+                .paths(PathSelectors.any())
+                //.paths(PathSelectors.ant("/api/**"))
+                .build();
+    }
+
+    private ApiInfo apiInfo() {
+        return new ApiInfoBuilder()
+                .title("RSE(DSRC) Control API")
+                .description("RSE(DSRC) Communication Server API")
+                .version("0.0.1")
+                .build();
+    }
+
+}

+ 102 - 0
src/main/java/com/its/vms/config/ThreadPoolInitializer.java

@@ -0,0 +1,102 @@
+package com.its.vms.config;
+
+import lombok.Getter;
+import lombok.Setter;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.boot.context.properties.ConfigurationProperties;
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
+import org.springframework.scheduling.annotation.AsyncConfigurerSupport;
+import org.springframework.scheduling.annotation.EnableAsync;
+import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;
+
+import javax.annotation.PostConstruct;
+import java.util.concurrent.Executor;
+
+@Slf4j
+@Getter
+@Setter
+@EnableAsync
+@Configuration
+@ConfigurationProperties(prefix = "application.thread-pool")
+public class ThreadPoolInitializer extends AsyncConfigurerSupport {
+
+    private int comm = 0;
+    private int stat = 0;
+    private int work = 0;
+    private int dbms = 0;
+    private int ping = 0;
+
+    @PostConstruct
+    private void init() {
+        int MAX_CORE = Math.max(8, Runtime.getRuntime().availableProcessors());
+        if (this.comm <= 0) {
+            this.comm = MAX_CORE;
+        }
+        if (this.stat <= 0) {
+            this.stat = MAX_CORE;
+        }
+        if (this.work <= 0) {
+            this.work = MAX_CORE;
+        }
+        if (this.dbms <= 0) {
+            this.dbms = MAX_CORE;
+        }
+        if (this.ping <= 0) {
+            this.ping = MAX_CORE;
+        }
+
+        log.info("{}", this);
+    }
+
+    public ThreadPoolTaskExecutor getDefaultExecutor(int poolSize) {
+        ThreadPoolTaskExecutor threadPoolTaskExecutor = new ThreadPoolTaskExecutor();
+        threadPoolTaskExecutor.setCorePoolSize(poolSize);              // 인스턴스 되면서 기본적으로 띄울 스레드 개수.
+        // 아무작업이 없어도 corePoolSize 만큼 스레드가 생성
+        threadPoolTaskExecutor.setMaxPoolSize(poolSize*2);   // 풀 최대개수, Queue Capacity 까지 꽉차는 경우 maxPoolSize 만큼 넓혀감
+        threadPoolTaskExecutor.setQueueCapacity(1000);          // 스레드 대기큐, Queue Capacity 가 꽉차면 스레드가 추가로 생성됨. Async 처리시 Queue Size
+        // (설정하지 않으면 Integer.MAX 이기 때문에 성능에 문제가 발생함)
+        return threadPoolTaskExecutor;
+    }
+
+    @Bean(name="centerCommExecutor")
+    public Executor getCenterCommExecutor() {
+        ThreadPoolTaskExecutor threadPoolTaskExecutor = getDefaultExecutor(this.comm);
+        threadPoolTaskExecutor.setThreadNamePrefix("comm-pool-");
+        threadPoolTaskExecutor.initialize();
+        return threadPoolTaskExecutor;
+    }
+
+    @Bean(name="dbmsDataExecutor")
+    public Executor getDbmsDataExecutor() {
+        ThreadPoolTaskExecutor threadPoolTaskExecutor = getDefaultExecutor(this.dbms);
+        threadPoolTaskExecutor.setThreadNamePrefix("dbms-pool-");
+        threadPoolTaskExecutor.initialize();
+        return threadPoolTaskExecutor;
+    }
+
+    @Bean(name="workDataExecutor")
+    public Executor getWorkDataExecutor() {
+        ThreadPoolTaskExecutor threadPoolTaskExecutor = getDefaultExecutor(this.work);
+        threadPoolTaskExecutor.setThreadNamePrefix("work-pool-");
+        threadPoolTaskExecutor.initialize();
+        return threadPoolTaskExecutor;
+    }
+
+    @Bean(name="statisticsExecutor")
+    public Executor getStatisticsExecutor() {
+        ThreadPoolTaskExecutor threadPoolTaskExecutor = getDefaultExecutor(this.stat);
+        threadPoolTaskExecutor.setThreadNamePrefix("stat-pool-");
+        threadPoolTaskExecutor.initialize();
+        return threadPoolTaskExecutor;
+    }
+
+    @Bean(name="icmpPingExecutor")
+    public Executor getIcmpPingExecutor() {
+        ThreadPoolTaskExecutor threadPoolTaskExecutor = getDefaultExecutor(this.ping);
+        threadPoolTaskExecutor.setThreadNamePrefix("icmp-pool-");
+        threadPoolTaskExecutor.initialize();
+        return threadPoolTaskExecutor;
+    }
+
+}

+ 133 - 0
src/main/java/com/its/vms/dao/mapper/BatchDaoService.java

@@ -0,0 +1,133 @@
+package com.its.vms.dao.mapper;
+
+import com.its.app.utils.Elapsed;
+import lombok.Data;
+import lombok.extern.slf4j.Slf4j;
+import org.apache.ibatis.session.ExecutorType;
+import org.apache.ibatis.session.SqlSession;
+import org.apache.ibatis.session.SqlSessionFactory;
+
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+@Data
+@Slf4j
+public abstract class BatchDaoService {
+
+    protected final int MAX_BATCH_SIZE = 1000;
+
+    protected final SqlSessionFactory sqlSessionFactory;
+    protected String serviceName;
+    protected String mapperName;
+    protected String mapper;
+    protected int count;
+
+    public BatchDaoService(SqlSessionFactory sqlSessionFactory) {
+        this.sqlSessionFactory = sqlSessionFactory;
+    }
+
+    public int getCount() {
+        return this.count;
+    }
+    public String getMapper() {
+        return this.mapper;
+    }
+    public String getServiceName() {
+        return this.serviceName;
+    }
+    public String getMapperName() {
+        return this.mapperName;
+    }
+
+    public int execute(String mapper) {
+        log.info("{}.insertBatch: {}: START.", this.serviceName, mapper);
+
+        this.mapper = mapper;
+        String mapperName = this.mapperName + this.mapper;
+        Elapsed elapsed = new Elapsed();
+        int total = 0;
+        SqlSession sqlSession = null;
+        try {
+            sqlSession = this.sqlSessionFactory.openSession(ExecutorType.SIMPLE, false);
+            total = sqlSession.update(mapperName);
+        }
+        finally {
+            if (sqlSession != null) {
+                sqlSession.commit();
+                sqlSession.close();
+            }
+        }
+        log.info("{}.insertBatch: {}: ..END. {} EA. {} ms.", this.serviceName, mapper, total, elapsed.milliSeconds());
+        return total;
+    }
+
+    public int insertBatch(String mapper, List<HashMap<String, Object>> lists) {
+        //log.info("{}.insertBatch: {}: START.", this.serviceName, mapper);
+        this.mapper = mapper;
+        String mapperName = this.mapperName + this.mapper;
+        //Elapsed elapsed = new Elapsed();
+        int total = lists.size();
+        if (total == 0) {
+            log.info("{}.insertBatch: {}: Data size zero.", this.serviceName, mapper);
+            return 0;
+        }
+        int jobCnt = 0;
+        SqlSession sqlSession = null;
+        try {
+            sqlSession = this.sqlSessionFactory.openSession(ExecutorType.BATCH, false);
+            for (Map<String, Object> param : lists) {
+                sqlSession.insert(mapperName, param);
+                jobCnt++;
+                if (jobCnt % this.MAX_BATCH_SIZE == 0 || jobCnt == total) {
+                    sqlSession.flushStatements();
+                    sqlSession.clearCache();
+                }
+            }
+        }
+        finally {
+            if (sqlSession != null) {
+                sqlSession.commit();
+                sqlSession.close();
+            }
+        }
+        this.count = total;
+        //log.info("{}.insertBatch: {}: ..END. {} EA. {} ms.", this.serviceName, mapper, total, elapsed.milliSeconds());
+        return this.count;
+    }
+
+    public int updateBatch(String mapper, List<HashMap<String, Object>> lists) {
+        //log.info("{}.updateBatch: {}: START.", this.serviceName, mapper);
+        this.mapper = mapper;
+        String mapperName = this.mapperName + this.mapper;
+        //Elapsed elapsed = new Elapsed();
+        int total = lists.size();
+        if (total == 0) {
+            log.info("{}.updateBatch: {}: Data size zero.", this.serviceName, mapper);
+            return 0;
+        }
+        int jobCnt = 0;
+        SqlSession sqlSession = null;
+        try {
+            sqlSession = this.sqlSessionFactory.openSession(ExecutorType.BATCH, false);
+            for (Map<String, Object> param : lists) {
+                sqlSession.update(mapperName, param);
+                jobCnt++;
+                if (jobCnt % this.MAX_BATCH_SIZE == 0 || jobCnt == total) {
+                    sqlSession.flushStatements();
+                    sqlSession.clearCache();
+                }
+            }
+        }
+        finally {
+            if (sqlSession != null) {
+                sqlSession.commit();
+                sqlSession.close();
+            }
+        }
+        this.count = total;
+        //log.info("{}.updateBatch: {}: ..END. {} EA. {} ms.", this.serviceName, mapper, total, elapsed.milliSeconds());
+        return this.count;
+    }
+
+}

+ 12 - 0
src/main/java/com/its/vms/dao/mapper/RseObuClctMapper.java

@@ -0,0 +1,12 @@
+package com.its.vms.dao.mapper;
+
+import com.its.vms.entity.TbRseObuClct;
+import org.apache.ibatis.annotations.Mapper;
+import org.apache.ibatis.annotations.Param;
+
+@Mapper
+public interface RseObuClctMapper {
+
+    int insertRseObuClctHs(@Param("obj") TbRseObuClct obj);
+    int updateRseObuClctPnst(@Param("obj") TbRseObuClct obj);
+}

+ 21 - 0
src/main/java/com/its/vms/dao/mapper/RseOffrSectMapper.java

@@ -0,0 +1,21 @@
+package com.its.vms.dao.mapper;
+
+import com.its.vms.entity.TbRseOffrDrct;
+import com.its.vms.entity.TbRseOffrSect;
+import com.its.vms.entity.TbRseOffrSectTraf;
+import com.its.vms.dto.voDsrcOffrSectTraf;
+import org.apache.ibatis.annotations.Mapper;
+import org.apache.ibatis.annotations.Param;
+
+import java.util.List;
+
+@Mapper
+public interface RseOffrSectMapper {
+
+    List<TbRseOffrSect> selectRseOffrSectAll();
+    List<TbRseOffrDrct> selectRseOffrDrctAll();
+    List<voDsrcOffrSectTraf> selectRseOffrSectTraf();
+    List<voDsrcOffrSectTraf> selectRseOffrSectTrafMulti();  // Not Use
+    int updateRseOffrSectTraf(@Param("obj") TbRseOffrSectTraf obj);
+    int insertRseOffrSectTrafHs(@Param("obj") TbRseOffrSectTraf obj);
+}

+ 18 - 0
src/main/java/com/its/vms/dao/mapper/RseSectMapper.java

@@ -0,0 +1,18 @@
+package com.its.vms.dao.mapper;
+
+import com.its.vms.entity.TbRseSect;
+import com.its.vms.entity.TbRseSectPassHs;
+import com.its.vms.entity.TbRseSectTraf;
+import org.apache.ibatis.annotations.Mapper;
+import org.apache.ibatis.annotations.Param;
+
+import java.util.List;
+
+@Mapper
+public interface RseSectMapper {
+
+    List<TbRseSect> selectRseSectAll();
+    int updateRseSectTraf(@Param("obj") TbRseSectTraf obj);
+    int insertRseSectTrafHs(@Param("obj") TbRseSectTraf obj);
+    int insertRseSectPassHs(@Param("obj") TbRseSectPassHs obj);
+}

+ 13 - 0
src/main/java/com/its/vms/dao/mapper/RseStatMapper.java

@@ -0,0 +1,13 @@
+package com.its.vms.dao.mapper;
+
+import com.its.vms.dto.voStatisticsTime;
+import org.apache.ibatis.annotations.Mapper;
+import org.apache.ibatis.annotations.Param;
+
+@Mapper
+public interface RseStatMapper {
+
+    int CRT_TB_RSE_OBU_CLCT_STAT_HH(@Param("prcs") voStatisticsTime paramStat);
+    int CRT_TB_RSE_OBU_CLCT_STAT_DD(@Param("prcs") voStatisticsTime paramStat);
+    int CRT_TB_RSE_OD_STAT_HH(@Param("prcs") voStatisticsTime paramStat);
+}

+ 16 - 0
src/main/java/com/its/vms/dao/mapper/UnitSystMapper.java

@@ -0,0 +1,16 @@
+package com.its.vms.dao.mapper;
+
+import com.its.vms.entity.TbUnitSyst;
+import com.its.vms.entity.TbUnitSystStts;
+import org.apache.ibatis.annotations.Mapper;
+import org.apache.ibatis.annotations.Param;
+
+import java.util.List;
+
+@Mapper
+public interface UnitSystMapper {
+
+    List<TbUnitSyst> selectAll();
+    int updateUnitSystStts(@Param("obj") TbUnitSystStts obj);
+    int insertUnitSystSttsHs(@Param("obj") TbUnitSystStts obj);
+}

+ 12 - 0
src/main/java/com/its/vms/dao/mapper/VmsAtmpMapper.java

@@ -0,0 +1,12 @@
+package com.its.vms.dao.mapper;
+
+import com.its.vms.dto.TbVmsAtmpDto;
+import org.apache.ibatis.annotations.Mapper;
+
+import java.util.List;
+
+@Mapper
+public interface VmsAtmpMapper {
+
+    List<TbVmsAtmpDto> selectVmsAtmpInfo();
+}

+ 26 - 0
src/main/java/com/its/vms/dao/mapper/VmsCtlrMapper.java

@@ -0,0 +1,26 @@
+package com.its.vms.dao.mapper;
+
+import com.its.vms.dto.TbVmsCtlrDto;
+import com.its.vms.entity.TbRseCtlrCnncHs;
+import com.its.vms.dto.TbVmsCtlrSttsDto;
+import com.its.vms.entity.TbRseCtrlHs;
+import com.its.vms.entity.TbRseObuNonCrypt;
+import org.apache.ibatis.annotations.Mapper;
+import org.apache.ibatis.annotations.Param;
+
+import java.util.List;
+
+@Mapper
+public interface VmsCtlrMapper {
+
+    List<TbVmsCtlrDto> selectAll();
+
+    List<TbVmsCtlrSttsDto> selectCtlrStts();
+    List<TbRseObuNonCrypt> selectRseObuNonCryptList();
+    int updateCtlrStts(@Param("obj") TbVmsCtlrSttsDto obj);
+    int insertCtlrSttsHs(@Param("obj") TbVmsCtlrSttsDto obj);
+    int insertRseCtlrCnncHs(@Param("obj") TbRseCtlrCnncHs obj);     // 접속이력
+    int insertRseCtrlHs(@Param("obj") TbRseCtrlHs obj);             // 제어이력
+
+    int updateRseCtrlHs(@Param("obj") TbRseCtrlHs obj);
+}

+ 14 - 0
src/main/java/com/its/vms/dao/mapper/VmsFontMapper.java

@@ -0,0 +1,14 @@
+package com.its.vms.dao.mapper;
+
+import com.its.vms.dto.TbVmsFontColrDto;
+import com.its.vms.dto.TbVmsFontNameDto;
+import org.apache.ibatis.annotations.Mapper;
+
+import java.util.List;
+
+@Mapper
+public interface VmsFontMapper {
+
+    List<TbVmsFontNameDto> selectFontName();
+    List<TbVmsFontColrDto> selectFontColr();
+}

+ 14 - 0
src/main/java/com/its/vms/dao/mapper/VmsIfscMapper.java

@@ -0,0 +1,14 @@
+package com.its.vms.dao.mapper;
+
+import com.its.vms.dto.TbVmsRltnIfscDto;
+import com.its.vms.dto.TbVmsIfscTrafDto;
+import org.apache.ibatis.annotations.Mapper;
+
+import java.util.List;
+
+@Mapper
+public interface VmsIfscMapper {
+
+    List<TbVmsRltnIfscDto> selectVmsRltnIfsc();
+    List<TbVmsIfscTrafDto> selectVmsIfscTrafInfo();
+}

+ 14 - 0
src/main/java/com/its/vms/dao/mapper/VmsSymbMapper.java

@@ -0,0 +1,14 @@
+package com.its.vms.dao.mapper;
+
+import com.its.vms.dto.TbVmsSymbIfscDto;
+import com.its.vms.dto.TbVmsSymbLibDto;
+import org.apache.ibatis.annotations.Mapper;
+
+import java.util.List;
+
+@Mapper
+public interface VmsSymbMapper {
+
+    List<TbVmsSymbLibDto> selectVmsSymbLib();
+    List<TbVmsSymbIfscDto> selectVmsSymbCellInfo();
+}

+ 98 - 0
src/main/java/com/its/vms/dao/mapper/batch/VmsCtlrDao.java

@@ -0,0 +1,98 @@
+package com.its.vms.dao.mapper.batch;
+
+import com.its.app.utils.Elapsed;
+import com.its.vms.dao.mapper.BatchDaoService;
+import com.its.vms.dto.TbVmsCtlrSttsDto;
+import lombok.extern.slf4j.Slf4j;
+import org.apache.ibatis.session.ExecutorType;
+import org.apache.ibatis.session.SqlSession;
+import org.apache.ibatis.session.SqlSessionFactory;
+import org.springframework.stereotype.Repository;
+
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+
+@Slf4j
+@Repository
+public class VmsCtlrDao extends BatchDaoService {
+
+    public VmsCtlrDao(SqlSessionFactory sqlSessionFactory) {
+        super(sqlSessionFactory);
+        this.serviceName = "VmsCtlrDao";
+        this.mapperName  = "";
+    }
+
+    public List<HashMap<String, Object>> getSttsList(List<TbVmsCtlrSttsDto> req) {
+        List<HashMap<String, Object>> lists = new ArrayList<>();
+        req.forEach(obj -> {
+            HashMap<String, Object> param = new HashMap<>();
+
+            param.put("vmsCtlrNmbr",  obj.getVmsCtlrNmbr());
+            param.put("updtDt",        obj.getUpdtDt());
+            param.put("cmncSttsCd",   obj.getCmncSttsCd());
+            param.put("pwerSttsCd", obj.getPwerSttsCd());
+            param.put("modlSttsCd",     obj.getModlSttsCd());
+            param.put("cboxDoorSttsCd",     obj.getCboxDoorSttsCd());
+            param.put("fanSttsCd",     obj.getFanSttsCd());
+            param.put("hetrSttsCd",     obj.getHetrSttsCd());
+            param.put("cboxTmpr",     obj.getCboxTmpr());
+            param.put("brghVal",     obj.getBrghVal());
+            param.put("commSttsCd",     obj.getCommSttsCd());
+            param.put("modlStts",     obj.getModlStts());
+            param.put("pwerStts",  obj.getPwerStts());
+
+            lists.add(param);
+        });
+        return lists;
+    }
+
+    public int updateStts(List<TbVmsCtlrSttsDto> req, boolean isHistory) {
+        log.info("{}.updateStts: START. {} EA. History {}", this.serviceName, req.size(), isHistory);
+        Elapsed elapsed = new Elapsed();
+        int total = 0;
+        SqlSession sqlSession = null;
+        try {
+            sqlSession = this.sqlSessionFactory.openSession(ExecutorType.BATCH, false);
+
+            this.mapper = this.mapperName + "batchUpdateCtlrStts";
+            total += updateBatch(this.mapper, getSttsList(req));
+
+            sqlSession.commit();
+        } catch(Exception e) {
+            log.error("updateStts: Exception, {}, {}", req, e.getMessage());
+        }
+        finally {
+            if (sqlSession != null) {
+                sqlSession.close();
+            }
+        }
+        log.info("{}.updateStts: ..END. {} EA. {} ms.", this.serviceName, total, elapsed.milliSeconds());
+        return total;
+    }
+
+    public int insertStts(List<TbVmsCtlrSttsDto> req) {
+        log.info("{}.insertStts: START. {} EA.", this.serviceName, req.size());
+        Elapsed elapsed = new Elapsed();
+        int total = 0;
+        SqlSession sqlSession = null;
+        try {
+            sqlSession = this.sqlSessionFactory.openSession(ExecutorType.BATCH, false);
+
+            this.mapper = this.mapperName + "batchInsertCtlrSttsHs";
+            total += insertBatch(this.mapper, getSttsList(req));
+
+            sqlSession.commit();
+        } catch(Exception e) {
+            log.error("insertStts: Exception, {}, {}", req, e.getMessage());
+        }
+        finally {
+            if (sqlSession != null) {
+                sqlSession.close();
+            }
+        }
+        log.info("{}.insertStts: ..END. {} EA. {} ms.", this.serviceName, total, elapsed.milliSeconds());
+        return total;
+    }
+
+}

+ 7 - 0
src/main/java/com/its/vms/dto/NET.java

@@ -0,0 +1,7 @@
+package com.its.vms.dto;
+
+public class NET {
+    public final static int CLOSED		= 0;
+    public final static int LOGIN_REQ  	= 1;
+    public final static int LOGINED		= 2;
+}

+ 75 - 0
src/main/java/com/its/vms/dto/TbVmsAtmpDto.java

@@ -0,0 +1,75 @@
+package com.its.vms.dto;
+
+import com.its.vms.entity.TbVmsAtmp;
+import lombok.Builder;
+import lombok.Data;
+
+import java.io.Serializable;
+
+/**
+ *  DTO Class
+ */
+@Data
+@Builder
+public class TbVmsAtmpDto implements Serializable {
+    private static final long serialVersionUID = 1L;
+
+    private Long atmpSttnNmbr;
+    private String atmpSttnNm;
+    private String vmsDispNm;
+    private String delYn;
+
+    private String msrmDt;
+    private String msrmSystNm;
+    private String coVal;
+    private String so2Val;
+    private String no2Val;
+    private String o3Val;
+    private String pm10Val;
+    private String pm1024hhVal;
+    private String pm25Val;
+    private String pm2524hhVal;
+    private String intgAtmpVal;
+    private String intgAtmpGrad;
+    private String so2Grad;
+    private String coGrad;
+    private String o3Grad;
+    private String no2Grad;
+    private String pm1024hhGrad;
+    private String pm2524hhGrad;
+    private String pm101hhGrad;
+    private String pm251hhGrad;
+    private String updtDt;
+
+    public TbVmsAtmp toEntity() {
+        return TbVmsAtmp.builder()
+                .atmpSttnNmbr(this.atmpSttnNmbr)
+                .atmpSttnNm(this.atmpSttnNm)
+                .vmsDispNm(this.vmsDispNm)
+                .delYn(this.delYn)
+                .msrmDt(this.msrmDt)
+                .msrmSystNm(this.msrmSystNm)
+                .coVal(this.coVal)
+                .so2Val(this.so2Val)
+                .no2Val(this.no2Val)
+                .o3Val(this.o3Val)
+                .pm10Val(this.pm10Val)
+                .pm1024hhVal(this.pm1024hhVal)
+                .pm25Val(this.pm25Val)
+                .pm2524hhVal(this.pm2524hhVal)
+                .intgAtmpVal(this.intgAtmpVal)
+                .intgAtmpGrad(this.intgAtmpGrad)
+                .so2Grad(this.so2Grad)
+                .coGrad(this.coGrad)
+                .o3Grad(this.o3Grad)
+                .no2Grad(this.no2Grad)
+                .pm1024hhGrad(this.pm1024hhGrad)
+                .pm2524hhGrad(this.pm2524hhGrad)
+                .pm101hhGrad(this.pm101hhGrad)
+                .pm251hhGrad(this.pm251hhGrad)
+                .updtDt(this.updtDt)
+                .isSuccess(true)
+                .build();
+    }
+
+}

+ 145 - 0
src/main/java/com/its/vms/dto/TbVmsCtlrDto.java

@@ -0,0 +1,145 @@
+package com.its.vms.dto;
+
+import com.its.vms.entity.TbVmsCtlr;
+import io.swagger.annotations.ApiModel;
+import lombok.Builder;
+import lombok.Data;
+
+import java.io.Serializable;
+
+/**
+ *  DTO Class
+ */
+@Data
+@Builder
+public class TbVmsCtlrDto implements Serializable {
+    private static final long serialVersionUID = 1L;
+
+    private Long vmsCtlrNmbr;
+    private String vmsCtlrLocalNo;
+    private String vmsCtlrId;
+    private String vmsNm;
+    private String vmsCtlrIp;
+    private String vmsUsagTypeCd;
+    private String vmsFrmTypeCd;
+    private String vmsTypeCd;
+    private String vmsModlTypeCd;
+    private String vmsCtlrPort;
+    private String operMode;
+    private Integer cmncFailRate;
+    private Integer brghNghtStep;
+    private Integer brghWeekStep;
+    private Integer defPhseChngCycl;
+    private Integer modlErrRate;
+    private Integer cmncfailSlotNmbr;
+    private Integer pwerFailSlotNmbr;
+    private String cmtrinfrCnctYn;
+    private String wthrinfrCnctYn;
+    private String envrinfrCnctYn;
+    private Integer vmsMaxPhseNum;
+    private String panlOnTime;
+    private String panlOffTime;
+    private String panlPwerMode;
+    private String brghMode;
+    private String istlLctnNm;
+    private String trfcStrgUseYn;
+    private Long vmsLocIfscId;
+    private Double fanRunTmpr;
+    private Double hetrRunTmpr;
+    private Integer fanMode;
+    private Integer hetrMode;
+    private Integer brghCurrStep;
+    private String istlLctnAddr;
+    private Integer protocolVer;
+    private String delYn;
+
+    private int vmsWidth;
+    private int vmsHeight;
+    private int modlRowNum;
+    private int modlColNum;
+    private int powrRowNum;
+    private int powrColNum;
+
+    public TbVmsCtlr toEntity() {
+        if (this.vmsCtlrIp == null) this.vmsCtlrIp = "";
+        this.vmsCtlrIp = this.vmsCtlrIp.trim();
+
+        if (this.cmncFailRate == null) this.cmncFailRate = 10;
+        if (this.brghNghtStep == null) this.brghNghtStep = 0;
+        if (this.brghWeekStep == null) this.brghWeekStep = 10;
+        if (this.defPhseChngCycl == null) this.defPhseChngCycl = 10;
+        if (this.modlErrRate == null) this.modlErrRate = 10;
+        if (this.cmncfailSlotNmbr == null) this.cmncfailSlotNmbr = 0;
+        if (this.pwerFailSlotNmbr == null) this.pwerFailSlotNmbr = 0;
+        if (this.vmsMaxPhseNum == null) this.vmsMaxPhseNum = 10;
+        if (this.vmsLocIfscId == null) this.vmsLocIfscId = 0L;
+        if (this.fanRunTmpr == null) this.fanRunTmpr = 0.;
+        if (this.hetrRunTmpr == null) this.hetrRunTmpr = 0.;
+        if (this.fanMode == null) this.fanMode = 10;
+        if (this.hetrMode == null) this.hetrMode = 10;
+        if (this.brghCurrStep == null) this.brghCurrStep = 10;
+        if (this.protocolVer == null) this.protocolVer = 0;
+        if (!"A".equals(this.operMode) && !"F".equals(this.operMode) && !"B".equals(this.operMode)) {
+            this.operMode = "A";
+        }
+
+        if (this.panlOnTime == null) this.panlOnTime = "9999";
+        if (this.panlOffTime == null) this.panlOffTime = "9999";
+        if ("9999".equals(this.panlOnTime) || this.panlOnTime.length()  != 4) {
+            this.panlOnTime  = "0000";
+        }
+        if ("9999".equals(this.panlOffTime) || this.panlOffTime.length()  != 4) {
+            this.panlOffTime  = "0000";
+        }
+
+        TbVmsCtlr obj = TbVmsCtlr.builder()
+                .ctlrNmbr(this.vmsCtlrNmbr)
+                .ctlrLocalNo(this.vmsCtlrLocalNo)
+                .ctlrId(this.vmsCtlrId)
+                .name(this.vmsNm)
+                .ctlrIp(this.vmsCtlrIp)
+                .usagTypeCd(this.vmsUsagTypeCd)
+                .frmTypeCd(this.vmsFrmTypeCd)
+                .typeCd(this.vmsTypeCd)
+                .modlTypeCd(this.vmsModlTypeCd)
+                .ctlrPort(this.vmsCtlrPort)
+                .operMode(this.operMode)
+                .cmncFailRate(this.cmncFailRate)
+                .brghNghtStep(this.brghNghtStep)
+                .brghWeekStep(this.brghWeekStep)
+                .defPhseChngCycl(this.defPhseChngCycl)
+                .modlErrRate(this.modlErrRate)
+                .cmncfailSlotNmbr(this.cmncfailSlotNmbr)
+                .pwerFailSlotNmbr(this.pwerFailSlotNmbr)
+                 .cmtrinfrCnctYn(this.cmtrinfrCnctYn)
+                .wthrinfrCnctYn(this.wthrinfrCnctYn)
+                .envrinfrCnctYn(this.envrinfrCnctYn)
+                .maxPhseNum(this.vmsMaxPhseNum)
+                .panlOnTime(this.panlOnTime)
+                .panlOffTime(this.panlOffTime)
+                .panlPwerMode(this.panlPwerMode)
+                .brghMode(this.brghMode)
+                .istlLctnNm(this.istlLctnNm)
+                .trfcStrgUseYn(this.trfcStrgUseYn)
+                .locIfscId(this.vmsLocIfscId)
+                .fanRunTmpr(this.fanRunTmpr)
+                .hetrRunTmpr(this.hetrRunTmpr)
+                .fanMode(this.fanMode)
+                .hetrMode(this.hetrMode)
+                .brghCurrStep(this.brghCurrStep)
+                .istlLctnAddr(this.istlLctnAddr)
+                .protocolVer(this.protocolVer)
+                .delYn(this.delYn)
+                .vmsWidth(this.vmsWidth)
+                .vmsHeight(this.vmsHeight)
+                .modlRowNum(this.modlRowNum)
+                .modlColNum(this.modlColNum)
+                .powrRowNum(this.powrRowNum)
+                .powrColNum(this.powrColNum)
+                .build();
+
+        obj.init();
+        return obj;
+    }
+
+}

+ 86 - 0
src/main/java/com/its/vms/dto/TbVmsCtlrSttsDto.java

@@ -0,0 +1,86 @@
+package com.its.vms.dto;
+
+import com.its.app.utils.SysUtils;
+import io.swagger.annotations.ApiModel;
+import lombok.Data;
+
+import java.io.Serializable;
+
+/**
+ *  DTO Class
+ */
+@Data
+public class TbVmsCtlrSttsDto implements Serializable {
+    private static final long serialVersionUID = 1L;
+
+    private Long vmsCtlrNmbr;
+    private String updtDt;
+    private String cmncSttsCd;
+    private String pwerSttsCd;
+    private String modlSttsCd;
+    private String cboxDoorSttsCd;
+    private String fanSttsCd;
+    private String hetrSttsCd;
+    private Integer cboxTmpr;
+    private Integer brghVal;
+    private String commSttsCd;
+    private String modlStts;
+    private String pwerStts;
+
+    public TbVmsCtlrSttsDto(Long vmsCtlrNmbr) {
+        this.vmsCtlrNmbr = vmsCtlrNmbr;
+        initUnknown();
+    }
+
+    public TbVmsCtlrSttsDto clone() {
+        TbVmsCtlrSttsDto dto = new TbVmsCtlrSttsDto(this.vmsCtlrNmbr);
+        dto.setUpdtDt(this.updtDt);
+        dto.setCmncSttsCd(this.cmncSttsCd);
+        dto.setPwerSttsCd(this.pwerSttsCd);
+        dto.setModlSttsCd(this.modlSttsCd);
+        dto.setCboxDoorSttsCd(this.cboxDoorSttsCd);
+        dto.setFanSttsCd(this.fanSttsCd);
+        dto.setHetrSttsCd(this.hetrSttsCd);
+        dto.setCboxTmpr(this.cboxTmpr);
+        dto.setBrghVal(this.brghVal);
+        dto.setCommSttsCd(this.commSttsCd);
+        dto.setModlStts(this.modlStts);
+        dto.setPwerStts(this.pwerStts);
+        return dto;
+    }
+    public void initStts(boolean isConnected) {
+        if (isConnected) {
+            initUnknown();
+        } else {
+            initError();
+        }
+    }
+    public void initUnknown() {
+        this.updtDt = SysUtils.getSysTime();
+        this.cmncSttsCd = "CMS2";
+        this.pwerSttsCd = "MOS2";
+        this.modlSttsCd = "MOS2";
+        this.cboxDoorSttsCd = "CDS2";
+        this.fanSttsCd = "PAS2";
+        this.hetrSttsCd = "HTS2";
+        this.cboxTmpr = 0;
+        this.brghVal = 0;
+        this.commSttsCd = "CMS2";
+        this.modlStts = "11111111111111111111";
+        this.pwerStts = "11111111111111111111";
+    }
+    public void initError() {
+        initUnknown();
+        this.cmncSttsCd = "CMS1";
+        this.commSttsCd = "CMS1";
+    }
+
+    public void initNormal() {
+        initUnknown();
+        this.cmncSttsCd = "CMS0";
+        this.commSttsCd = "CMS0";
+    }
+
+    public void setStts(int frontDoor, int backDoor, int fan, int hetr, int rtu, int tmpr, int hmdt) {
+    }
+}

+ 32 - 0
src/main/java/com/its/vms/dto/TbVmsFontColrDto.java

@@ -0,0 +1,32 @@
+package com.its.vms.dto;
+
+import com.its.vms.entity.TbVmsFontColr;
+import io.swagger.annotations.ApiModel;
+import lombok.Builder;
+import lombok.Data;
+
+import java.io.Serializable;
+
+/**
+ *  DTO Class
+ */
+@Data
+@Builder
+public class TbVmsFontColrDto implements Serializable {
+    private static final long serialVersionUID = 1L;
+
+    private Integer vmsFontColrCd;
+    private String vmsFontColrNm;
+    private Long vmsFontColrVal;
+    private String useYn;
+
+    public TbVmsFontColr toEntity() {
+        return TbVmsFontColr.builder()
+                .vmsFontColrCd(this.vmsFontColrCd)
+                .vmsFontColrNm(this.vmsFontColrNm)
+                .vmsFontColrVal(this.vmsFontColrVal)
+                .useYn(this.useYn)
+                .build();
+    }
+
+}

+ 30 - 0
src/main/java/com/its/vms/dto/TbVmsFontNameDto.java

@@ -0,0 +1,30 @@
+package com.its.vms.dto;
+
+import com.its.vms.entity.TbVmsFontName;
+import io.swagger.annotations.ApiModel;
+import lombok.Builder;
+import lombok.Data;
+
+import java.io.Serializable;
+
+/**
+ *  DTO Class
+ */
+@Data
+@Builder
+public class TbVmsFontNameDto implements Serializable {
+    private static final long serialVersionUID = 1L;
+
+    private Integer vmsFontNameCd;
+    private String vmsFontNameNm;
+    private String useYn;
+
+    public TbVmsFontName toEntity() {
+        return TbVmsFontName.builder()
+                .vmsFontNameCd(this.vmsFontNameCd)
+                .vmsFontNameNm(this.vmsFontNameNm)
+                .useYn(this.useYn)
+                .build();
+    }
+
+}

+ 69 - 0
src/main/java/com/its/vms/dto/TbVmsIfscTrafDto.java

@@ -0,0 +1,69 @@
+package com.its.vms.dto;
+
+import com.its.vms.entity.TbVmsIfscTraf;
+import io.swagger.annotations.ApiModel;
+import lombok.AllArgsConstructor;
+import lombok.Builder;
+import lombok.Getter;
+import lombok.NoArgsConstructor;
+
+import java.io.Serializable;
+
+/**
+ *  Entity Class
+ */
+@Getter
+@Builder
+@NoArgsConstructor//(access = AccessLevel.PROTECTED)
+@AllArgsConstructor
+public class TbVmsIfscTrafDto implements Serializable {
+    private static final long serialVersionUID = 1L;
+
+    private Long vmsIfscId;
+    private String vmsIfscNm;
+    private String dsplStrtNodeNm;
+    private String dsplEndNodeNm;
+    private Long detrId;
+    private String roadNm;
+    private String spotNm;
+    private String axisYn;
+    private Integer cngstSpd;
+    private String useYn;
+
+    private String prcnDt;
+    private String cmtrGradCd;
+    private Integer sped;
+    private Integer trvlHh;
+
+    public TbVmsIfscTraf toEntity() {
+        return TbVmsIfscTraf.builder()
+                .vmsIfscId(this.vmsIfscId)
+                .vmsIfscNm(this.vmsIfscNm)
+                .dsplStrtNodeNm(this.dsplStrtNodeNm)
+                .dsplEndNodeNm(this.dsplEndNodeNm)
+                .detrId(this.detrId)
+                .roadNm(this.roadNm)
+                .spotNm(this.spotNm)
+                .axisYn(this.axisYn)
+                .prcnDt(this.prcnDt)
+                .cmtrGradCd(this.cmtrGradCd)
+                .sped(this.sped)
+                .trvlHh(this.trvlHh)
+                .cngstCnt(0)
+                .cngstDt("")
+                .build();
+    }
+
+    public void trafCopy(TbVmsIfscTraf traf) {
+        traf.setDsplStrtNodeNm(this.dsplStrtNodeNm);
+        traf.setDsplEndNodeNm(this.dsplEndNodeNm);
+        traf.setDetrId(this.detrId);
+        traf.setRoadNm(this.roadNm);
+        traf.setSpotNm(this.spotNm);
+        traf.setAxisYn(this.axisYn);
+        traf.setPrcnDt(this.prcnDt);
+        traf.setCmtrGradCd(this.cmtrGradCd);
+        traf.setSped(this.sped);
+        traf.setTrvlHh(this.trvlHh);
+    }
+}

+ 52 - 0
src/main/java/com/its/vms/dto/TbVmsRltnIfscDto.java

@@ -0,0 +1,52 @@
+package com.its.vms.dto;
+
+import com.its.vms.entity.TbVmsRltnIfsc;
+import io.swagger.annotations.ApiModel;
+import lombok.AllArgsConstructor;
+import lombok.Builder;
+import lombok.Getter;
+import lombok.NoArgsConstructor;
+
+import java.io.Serializable;
+
+/**
+ *  Entity Class
+ */
+@Getter
+@Builder
+@NoArgsConstructor//(access = AccessLevel.PROTECTED)
+@AllArgsConstructor
+public class TbVmsRltnIfscDto implements Serializable {
+    private static final long serialVersionUID = 1L;
+
+    private Long vmsCtlrNmbr;
+    private Long vmsIfscId;
+    private Integer dsplPrrt;
+    private String axisYn;
+    private Integer cngstSped;
+    private Integer cngstCnfmSped;
+    private String cngstCnfmYn;
+
+    public TbVmsRltnIfsc toEntity() {
+        return TbVmsRltnIfsc.builder()
+                .vmsCtlrNmbr(this.vmsCtlrNmbr)
+                .vmsIfscId(this.vmsIfscId)
+                .dsplPrrt(this.dsplPrrt)
+                .axisYn(this.axisYn)
+                .cngstSped(this.cngstSped)
+                .cngstCnfmYn("Y".equals(this.cngstCnfmYn))
+                .cngstCnfmSped(this.cngstCnfmSped)
+                .isUsed(true)
+                .cngstCnt(0)
+                .cngstDt("")
+                .build();
+    }
+
+    public void rltnIfscCopy(TbVmsRltnIfsc rltnIfsc) {
+        rltnIfsc.setDsplPrrt(this.dsplPrrt);
+        rltnIfsc.setAxisYn(this.axisYn);
+        rltnIfsc.setCngstSped(this.cngstSped);
+        rltnIfsc.setCngstCnfmYn("Y".equals(this.cngstCnfmYn));
+        rltnIfsc.setCngstCnfmSped(this.cngstCnfmSped);
+    }
+}

+ 36 - 0
src/main/java/com/its/vms/dto/TbVmsSymbIfscDto.java

@@ -0,0 +1,36 @@
+package com.its.vms.dto;
+
+import com.its.vms.entity.TbVmsSymbIfsc;
+import lombok.Builder;
+import lombok.Data;
+
+import java.io.Serializable;
+
+/**
+ *  DTO Class
+ */
+@Data
+@Builder
+public class TbVmsSymbIfscDto implements Serializable {
+    private static final long serialVersionUID = 1L;
+
+    private Integer symbLibNmbr;
+    private Integer cellId;
+    private Integer posX;
+    private Integer posY;
+    private Long vmsIfscId;
+    private String updtDt;
+
+    public TbVmsSymbIfsc toEntity() {
+        return TbVmsSymbIfsc.builder()
+                .symbLibNmbr(this.symbLibNmbr)
+                .cellId(this.cellId)
+                .posX(this.posX)
+                .posY(this.posY)
+                .vmsIfscId(this.vmsIfscId == null ? 0 : this.vmsIfscId)
+                .updtDt(this.updtDt)
+                .isDup(false)
+                .build();
+    }
+
+}

+ 96 - 0
src/main/java/com/its/vms/dto/TbVmsSymbLibDto.java

@@ -0,0 +1,96 @@
+package com.its.vms.dto;
+
+import com.its.vms.entity.TbVmsSymbLib;
+import com.its.vms.entity.eVmsImageType;
+import lombok.Builder;
+import lombok.Data;
+
+import java.io.Serializable;
+import java.util.ArrayList;
+import java.util.HashMap;
+
+/**
+ *  DTO Class
+ */
+@Data
+@Builder
+public class TbVmsSymbLibDto implements Serializable {
+    private static final long serialVersionUID = 1L;
+
+    private Integer symbLibNmbr;
+    private String rgstDt;
+    private byte[] redData;
+    private byte[] greenData;
+    private String symbExpl;
+    private byte[] imagData;
+    private String vmsTypeCd;
+    private String symbImagType;
+    private String symbFileNm;
+    private String symbType;
+    private byte[] aviData;
+    private Long imagSize;
+    private Long playTm;
+    private String delYn;
+    private String updtDt;
+    private Integer posX;
+    private Integer posY;
+
+    public TbVmsSymbLib toEntity() {
+        // 소통정보이미지 때문에 이미지번호에 "0" 을 추가하여 이미지번호로 사용함
+
+        TbVmsSymbLib obj = TbVmsSymbLib.builder()
+                .symbLibNmbr(this.symbLibNmbr+"0")
+                .orgSymbLibNmbr(this.symbLibNmbr)
+                .rgstDt(this.rgstDt)
+                .redData(this.redData)
+                .greenData(this.greenData)
+                .symbExpl(this.symbExpl)
+                .imagData(this.imagData)
+                .vmsTypeCd(this.vmsTypeCd)
+                .symbImagType(this.symbImagType)
+                .symbFileNm(this.symbFileNm)
+                .symbType(this.symbType)
+                .aviData(this.aviData)
+                .imagSize(this.imagSize)
+                .playTm(this.playTm)
+                .delYn(this.delYn)
+                .updtDt(this.updtDt)
+                .posX(this.posX)
+                .posY(this.posY)
+                .gradSymbLibNmbrList(new ArrayList<>())
+                .cellMap(new HashMap<>())
+                .build();
+
+        TbVmsSymbLibDto.setSymbInfo(obj);
+
+        return obj;
+    }
+
+    public static void setSymbInfo(TbVmsSymbLib obj) {
+        obj.setImagType(eVmsImageType.vms_image_type_bmp);
+
+        String symbFileName = "";
+        if ("SBT3".equals(obj.getSymbType())) {
+            symbFileName = obj.getSymbFileNm();
+            obj.setImagType(eVmsImageType.vms_image_type_video);
+        }
+        else {
+            switch(obj.getImagType()) {
+                case vms_image_type_bmp: symbFileName = obj.getSymbLibNmbr()+".bmp"; break;
+                case vms_image_type_gif: symbFileName = obj.getSymbLibNmbr()+".gif"; break;
+                case vms_image_type_jpg: symbFileName = obj.getSymbLibNmbr()+".jpg"; break;
+                case vms_image_type_png: symbFileName = obj.getSymbLibNmbr()+".png"; break;
+                default:
+                    if (obj.getSymbFileNm() == null || obj.getSymbFileNm().trim().length() == 0) {
+                        symbFileName = obj.getSymbLibNmbr()+".avi";
+                    }
+                    else {
+                        symbFileName = obj.getSymbFileNm().trim();
+                    }
+                    break;
+            }
+        }
+        obj.setSymbFileNm(symbFileName);
+        obj.setLocalFileName(symbFileName);
+    }
+}

+ 15 - 0
src/main/java/com/its/vms/dto/voDsrcObuPassInfo.java

@@ -0,0 +1,15 @@
+package com.its.vms.dto;
+
+import lombok.Getter;
+import lombok.Setter;
+import lombok.extern.slf4j.Slf4j;
+
+@Slf4j
+@Getter
+@Setter
+public class voDsrcObuPassInfo {
+
+    private String obuId;
+    private String startDsrcPassTm;
+    private String endDsrcPassTm;
+}

+ 19 - 0
src/main/java/com/its/vms/dto/voDsrcOffrSectTraf.java

@@ -0,0 +1,19 @@
+package com.its.vms.dto;
+
+import lombok.Getter;
+import lombok.Setter;
+import lombok.ToString;
+
+@Getter
+@Setter
+@ToString
+public class voDsrcOffrSectTraf {
+    private String OFFR_SECT_ID;
+    private String OFFR_DRCT_NM;
+    private String OBU_ENTR_DRCT_NMBR;
+    private String IFSC_ID;
+    private String CMTR_GRAD_CD;
+    private String CMTR_GRAD_NM;
+    private int    SPED;
+    private int    TRVL_HH;
+}

+ 26 - 0
src/main/java/com/its/vms/dto/voStatisticsTime.java

@@ -0,0 +1,26 @@
+package com.its.vms.dto;
+
+import lombok.Getter;
+import lombok.Setter;
+import lombok.ToString;
+
+@Getter
+@Setter
+@ToString
+public class voStatisticsTime {
+
+	private String STAT_DT;
+	private String FROM_DT;
+	private String TO_DT;
+	private String DAY_TYPE_CD;
+	private String B_FROM_DT;
+	private String B_TO_DT;
+
+	public voStatisticsTime(String sTAT_DT, String fROM_DT, String tO_DT) {
+		this.STAT_DT = sTAT_DT;
+		this.FROM_DT = fROM_DT;
+		this.TO_DT = tO_DT;
+	}
+
+}
+

+ 26 - 0
src/main/java/com/its/vms/entity/TbRseCtlrCnncHs.java

@@ -0,0 +1,26 @@
+package com.its.vms.entity;
+
+import lombok.Getter;
+import lombok.Setter;
+import lombok.ToString;
+import lombok.extern.slf4j.Slf4j;
+
+@Slf4j
+@Getter
+@Setter
+@ToString
+public class TbRseCtlrCnncHs {
+
+    public static int LOG_TYPE_LOGIN = 0;
+    public static int LOG_TYPE_LOGOUT = 1;
+    public static int LOG_TYPE_INVALID_USER = 2;
+    public static int LOG_TYPE_OTHER = 3;
+    public static int LOG_TYPE_DUP_LOGIN = 4;
+
+    private String RSE_CTLR_NMBR;   //	N	VARCHAR2(3)	    N			아이디
+    private String CLCT_DT;         //	N	VARCHAR2(14)	N			수집 일시
+    private String LOG_TYPE;        //	N	VARCHAR2(7)	    Y			로그 유형
+    private String LOG_ID;          //	N	VARCHAR2(64)	Y			로그 ID
+    private String LOG_ADDRESS;     //	N	VARCHAR2(20)	Y			로그 ADDRESS
+
+}

+ 18 - 0
src/main/java/com/its/vms/entity/TbRseCtrlHs.java

@@ -0,0 +1,18 @@
+package com.its.vms.entity;
+
+import lombok.Getter;
+import lombok.Setter;
+import lombok.ToString;
+
+@Getter
+@Setter
+@ToString
+public class TbRseCtrlHs {
+    private Long ctrlSeq;
+    private Long rseCtlrNmbr;
+    private String cntlDt;
+    private String devcType;
+    private String cntlType;
+    private String rspsType;
+    private String userId;
+}

+ 18 - 0
src/main/java/com/its/vms/entity/TbRseObuClct.java

@@ -0,0 +1,18 @@
+package com.its.vms.entity;
+
+import lombok.AllArgsConstructor;
+import lombok.Getter;
+import lombok.Setter;
+import lombok.ToString;
+
+@Getter
+@Setter
+@ToString
+@AllArgsConstructor
+public class TbRseObuClct {
+    private String RSE_CTLR_NMBR;   //	N	NUMBER(10)	    N			RSE 제어기 번호
+    private String CLCT_DT;         //	N	VARCHAR2(14)	N			수집 일시
+    private String OBU_IDNT_NMBR;   //	N	VARCHAR2(200)	N			OBU 인식 번호
+    private String CTYP;            //	N	VARCHAR2(7)	    Y			차종
+    private String OBU_KIND;        //	N	VARCHAR2(7)	    Y			OBU 종류
+}

+ 15 - 0
src/main/java/com/its/vms/entity/TbRseObuNonCrypt.java

@@ -0,0 +1,15 @@
+package com.its.vms.entity;
+
+import lombok.Getter;
+import lombok.Setter;
+import lombok.ToString;
+
+@Getter
+@Setter
+@ToString
+public class TbRseObuNonCrypt {
+
+    private String OBU_ID;          //	N	VARCHAR2(200)	N			OBU 아이디
+    private String OBU_IDNT_NMBR;   //	N	VARCHAR2(200)	N			OBU 인식 번호
+
+}

+ 15 - 0
src/main/java/com/its/vms/entity/TbRseOffrDrct.java

@@ -0,0 +1,15 @@
+package com.its.vms.entity;
+
+import lombok.Getter;
+import lombok.Setter;
+import lombok.ToString;
+
+@Getter
+@Setter
+@ToString
+public class TbRseOffrDrct {
+    private String RSE_CTLR_NMBR;       //	N	NUMBER(10)	    N			RSE 제어기 번호
+    private String PRE_RSE_CTLR_NMBR;   //	N	NUMBER(10)	    N			이전 RSE 제어기 번호
+    private String OBU_ENTR_DRCT_NMBR;  //	N	NUMBER(1)       N			OBU 진입 방향 번호
+    private String IXR_DRCT_NUM;        //	N	NUMBER(1)       N			교차로 방향 개수
+}

+ 18 - 0
src/main/java/com/its/vms/entity/TbRseOffrSect.java

@@ -0,0 +1,18 @@
+package com.its.vms.entity;
+
+import lombok.Getter;
+import lombok.Setter;
+import lombok.ToString;
+
+@Getter
+@Setter
+@ToString
+public class TbRseOffrSect {
+    private String OFFR_SECT_ID;        //	N	NUMBER(10)	    N			제공 구간 아이디
+    private String OFFR_DRCT_NM;        //	N	VARCHAR2(30)	Y			제공 방향 명
+    private int    CNGS_BASI_SPED;      //	N	NUMBER(3)	    Y			정체 기준 속도
+    private int    DELY_BASI_SPED;      //	N	NUMBER(3)	    Y			지체 기준 속도
+    private String RSE_CTLR_NMBR;       //	N	NUMBER(10)	    N			아이디
+    private String OBU_ENTR_DRCT_NMBR;  //	N	NUMBER(1)       N			OBU 진입 방향 번호
+
+}

+ 16 - 0
src/main/java/com/its/vms/entity/TbRseOffrSectTraf.java

@@ -0,0 +1,16 @@
+package com.its.vms.entity;
+
+import lombok.AllArgsConstructor;
+import lombok.Getter;
+import lombok.Setter;
+import lombok.ToString;
+
+@Getter
+@Setter
+@ToString
+@AllArgsConstructor
+public class TbRseOffrSectTraf {
+    private String OFFR_SECT_ID;
+    private String PRCN_DT;
+    private String OFFR_CONT;
+}

+ 27 - 0
src/main/java/com/its/vms/entity/TbRseSect.java

@@ -0,0 +1,27 @@
+package com.its.vms.entity;
+
+import lombok.Getter;
+import lombok.Setter;
+import lombok.ToString;
+
+@Getter
+@Setter
+@ToString
+public class TbRseSect {
+    private String RSE_SECT_ID;         //	N	NUMBER(10)	    N			RSE 구간 아이디
+    private int    SECT_LNGT;           //	N	NUMBER(5)	    Y			거리
+    private String RSE_SECT_NM;         //	N	VARCHAR2(30)	Y			RSE 구간 명
+    private String STRT_SPOT_NM;        //	N	VARCHAR2(60)	Y			시작 지점 명
+    private String END_SPOT_NM;         //	N	VARCHAR2(60)	Y			종료 지점 명
+    private String STRT_RSE_CTLR_NMBR;  //	N	NUMBER(10)	    N			시작 RSE 제어기 번호
+    private String END_RSE_CTLR_NMBR;   //	N	NUMBER(10)	    N			종료 RSE 제어기 번호
+    private String DEL_YN;              //	N	CHAR(1)	        Y	'N'		삭제 여부
+
+    public String getSTRT_ID() {
+        return this.STRT_RSE_CTLR_NMBR;
+    }
+
+    public String getEND_ID() {
+        return this.END_RSE_CTLR_NMBR;
+    }
+}

+ 16 - 0
src/main/java/com/its/vms/entity/TbRseSectPassHs.java

@@ -0,0 +1,16 @@
+package com.its.vms.entity;
+
+import lombok.Getter;
+import lombok.Setter;
+import lombok.ToString;
+
+@Getter
+@Setter
+@ToString
+public class TbRseSectPassHs {
+    private String RSE_SECT_ID;         //	N	VARCHAR2(8)	    N			RSE 구간 아이디
+    private String CRTN_DT;             //	N	VARCHAR2(14)	N			생성 일시
+    private String OBU_IDNT_NMBR;       //	N	VARCHAR2(200)	N			OBU 인식 번호
+    private String STRT_SPOT_PASS_DT;   //	N	VARCHAR2(14)	N			시작 지점 통과 일시
+    private String END_SPOT_PASS_DT;    //	N	VARCHAR2(14)	N			종료 지점 통과 일시
+}

+ 16 - 0
src/main/java/com/its/vms/entity/TbRseSectTraf.java

@@ -0,0 +1,16 @@
+package com.its.vms.entity;
+
+import lombok.Getter;
+import lombok.Setter;
+import lombok.ToString;
+
+@Getter
+@Setter
+@ToString
+public class TbRseSectTraf {
+    private String RSE_SECT_ID; //	N	NUMBER(10)	    N			RSE 구간 아이디
+    private String PRCN_DT;     //	N	VARCHAR2(14)	N			생성 일시
+    private int    TFVL;        //	N	NUMBER(6)	    Y	0		교통량
+    private int    TRVL_SPED;   //	N	NUMBER(3)	    Y	0		통행 속도
+    private int    TRVL_HH;     //	N	NUMBER(6)	    Y	0		통행 시간
+}

+ 22 - 0
src/main/java/com/its/vms/entity/TbUnitSyst.java

@@ -0,0 +1,22 @@
+package com.its.vms.entity;
+
+import lombok.Builder;
+import lombok.Getter;
+import lombok.Setter;
+
+import java.io.Serializable;
+
+@Getter
+@Setter
+@Builder
+public class TbUnitSyst implements Serializable {
+    private static final long serialVersionUID = 1L;
+
+    private String systId;      //	N	VARCHAR2(30)	N			시스템 ID
+    private String systType;    //	N	VARCHAR2(7)	    Y			시스템 유형
+    private String systNm;      //	N	VARCHAR2(100)	Y			시스템 명
+    private String systIp1;     //	N	VARCHAR2(20)	Y			시스템 IP_1
+    private String systIp2;     //	N	VARCHAR2(20)	Y			시스템 IP_2
+    private int prgmPort;       //	N	VARCHAR2(5)	    Y			프로그램 포트
+    private String delYn;
+}

+ 17 - 0
src/main/java/com/its/vms/entity/TbUnitSystStts.java

@@ -0,0 +1,17 @@
+package com.its.vms.entity;
+
+import lombok.Builder;
+import lombok.Getter;
+import lombok.Setter;
+
+import java.io.Serializable;
+
+@Getter
+@Setter
+@Builder
+public class TbUnitSystStts implements Serializable {
+    private static final long serialVersionUID = 1L;
+    private String SYST_ID;         //	N	VARCHAR2(30)	N			시스템 ID
+    private String UPDT_DT;         //	N	VARCHAR2(14)	Y			갱신 일시
+    private String SYST_STTS_CD;    //	N	VARCHAR2(7)	    Y			시스템 상태 코드
+}

+ 183 - 0
src/main/java/com/its/vms/entity/TbVmsAtmp.java

@@ -0,0 +1,183 @@
+package com.its.vms.entity;
+
+import lombok.AllArgsConstructor;
+import lombok.Builder;
+import lombok.Data;
+import lombok.NoArgsConstructor;
+
+import java.io.Serializable;
+
+/**
+ *  Entity Class
+ */
+@Data
+@Builder
+@NoArgsConstructor//(access = AccessLevel.PROTECTED)
+@AllArgsConstructor
+public class TbVmsAtmp implements Serializable {
+    private static final long serialVersionUID = 1L;
+
+    private Long atmpSttnNmbr;
+    private String atmpSttnNm;
+    private String vmsDispNm;
+    private String delYn;
+
+    private String msrmDt;
+    private String msrmSystNm;
+    private String coVal;
+    private String so2Val;
+    private String no2Val;
+    private String o3Val;
+    private String pm10Val;
+    private String pm1024hhVal;
+    private String pm25Val;
+    private String pm2524hhVal;
+    private String intgAtmpVal;
+    private String intgAtmpGrad;
+    private String so2Grad;
+    private String coGrad;
+    private String o3Grad;
+    private String no2Grad;
+    private String pm1024hhGrad;
+    private String pm2524hhGrad;
+    private String pm101hhGrad;
+    private String pm251hhGrad;
+    private String updtDt;
+
+    private boolean isSuccess;
+
+    public void correct(TbVmsAtmp obj) {
+        obj.setMsrmDt(this.msrmDt);
+        obj.setMsrmSystNm(this.msrmSystNm);
+        obj.setCoVal(this.coVal);
+        obj.setSo2Val(this.so2Val);
+        obj.setNo2Val(this.no2Val);
+        obj.setO3Val(this.o3Val);
+        obj.setPm10Val(this.pm10Val);
+        obj.setPm1024hhVal(this.pm1024hhVal);
+        obj.setPm25Val(this.pm25Val);
+        obj.setPm2524hhVal(this.pm2524hhVal);
+        obj.setIntgAtmpVal(this.intgAtmpVal);
+        obj.setIntgAtmpGrad(this.intgAtmpGrad);
+        obj.setSo2Grad(this.so2Grad);
+        obj.setCoGrad(this.coGrad);
+        obj.setO3Grad(this.o3Grad);
+        obj.setNo2Grad(this.no2Grad);
+        obj.setPm1024hhGrad(this.pm1024hhGrad);
+        obj.setPm2524hhGrad(this.pm2524hhGrad);
+        obj.setPm101hhGrad(this.pm101hhGrad);
+        obj.setPm251hhGrad(this.pm251hhGrad);
+        obj.setUpdtDt(this.updtDt);
+        obj.setSuccess(this.isSuccess);
+    }
+
+    public String getPM10_VAL(boolean AUnit) {
+        // 미세먼지
+        if (this.isSuccess) {
+            if (AUnit)
+                return this.pm10Val + " ㎍/㎥";
+            else
+                return this.pm10Val;
+        }
+        return (AUnit) ? "- ㎍/㎥" : "-";
+    }
+    
+    public String getPM25_VAL(boolean AUnit) {
+        //초미세먼지
+        if (this.isSuccess) {
+            if (AUnit)
+                return this.pm25Val + " ㎍/㎥";
+            else
+                return this.pm25Val;
+        }
+        return (AUnit) ? "- ㎍/㎥" : "-";
+    }
+    
+    public String getATMP_VAL() {
+        //통합대기환경수치
+        if (this.isSuccess) {
+            return this.intgAtmpVal;
+        }
+        return "-";
+    }
+    
+    public String GetO3_VAL(boolean AUnit) {
+        //오존농도
+        if (this.isSuccess) {
+            if (AUnit)
+                return this.o3Val + " ppm";
+            else
+                return this.o3Val;
+        }
+        return (AUnit) ? "- ppm" : "-";
+    }
+    
+    public String getGradeDesc(int AGrad) {
+        if (!this.isSuccess) return "-";
+
+        switch(AGrad) {
+            case 1: return "좋음";
+            case 2: return "보통";
+            case 3: return "나쁨";
+            case 4: return "매우나쁨";
+        }
+        return "-";
+    }
+    
+    public String getPM10_GRAD() {
+        return getGradeDesc(parseDefInt(this.pm101hhGrad, 0));
+    }
+    
+    public String getPM25_GRAD() {
+        return getGradeDesc(parseDefInt(this.pm251hhGrad, 0));
+    }
+    
+    public String getATMP_GRAD() {
+        return getGradeDesc(parseDefInt(this.intgAtmpGrad, 0));
+    }
+    
+    public String getO3_GRAD() {
+        return getGradeDesc(parseDefInt(this.o3Grad, 0));
+    }
+    
+    public int getGradeColor(int AGrad) {
+        if (!this.isSuccess) return 3;//Color.GREEN.getRGB();
+
+        switch(AGrad)
+        {
+            case 1: return 2;//밝은녹색(Lime)
+            case 2: return 5;//하늘색(Aqua)
+            case 3: return 4;//주황색(Orange)
+            case 4: return 1;//적색(Red)
+        }
+        return 3;
+    }
+    
+    public int getPM10_CLR() {
+        return getGradeColor(parseDefInt(this.pm101hhGrad, 0));
+    }
+    
+    public int getPM25_CLR() {
+        return getGradeColor(parseDefInt(this.pm251hhGrad, 0));
+    }
+    
+    public int getATMP_CLR() {
+        return getGradeColor(parseDefInt(this.intgAtmpGrad, 0));
+    }
+    
+    public int getO3_CLR() {
+        return getGradeColor(parseDefInt(this.o3Grad, 0));
+    }
+
+    private int parseDefInt(String value, int defValue) {
+        if (value == null || value.length() == 0)
+            return defValue;
+
+        String strValue = value.trim();
+        for (int i = 0; i < strValue.length(); i++) {
+            if (!Character.isDigit(strValue.charAt(i)))
+                return defValue;
+        }
+        return Integer.parseInt(strValue);
+    }
+}

+ 358 - 0
src/main/java/com/its/vms/entity/TbVmsCtlr.java

@@ -0,0 +1,358 @@
+package com.its.vms.entity;
+
+import com.its.app.utils.SysUtils;
+import com.its.vms.dto.NET;
+import com.its.vms.dto.TbVmsCtlrSttsDto;
+import com.its.vms.xnettcp.vms.handler.VmsServerIdleStateHandler;
+import com.its.vms.xnettcp.vms.protocol.VmsFrameSequence;
+import com.its.vms.xnettcp.vms.protocol.enums.eControlCommand;
+import com.its.vms.xnettcp.vms.protocol.enums.eControlDeviceId;
+import com.its.vms.xnettcp.vms.task.VmsTimeoutTask;
+import io.netty.channel.Channel;
+import io.netty.channel.ChannelFuture;
+import io.netty.channel.ChannelHandlerContext;
+import lombok.*;
+import lombok.extern.slf4j.Slf4j;
+
+import java.io.Serializable;
+import java.net.InetSocketAddress;
+import java.nio.ByteBuffer;
+import java.text.SimpleDateFormat;
+import java.util.Map;
+import java.util.Timer;
+import java.util.TimerTask;
+import java.util.concurrent.ConcurrentHashMap;
+
+@Slf4j
+@Getter
+@Setter
+@ToString
+@Builder
+@NoArgsConstructor//(access = AccessLevel.PROTECTED)
+@AllArgsConstructor
+public class TbVmsCtlr implements Serializable {
+    private static final long serialVersionUID = 1L;
+
+    private int  index;
+    private Long ctlrNmbr;
+    private String ctlrLocalNo;
+    private String ctlrId;
+    private String name;
+    private String ctlrIp;
+    private String ctlrPort;
+    private String usagTypeCd;
+    private String frmTypeCd;
+    private String typeCd;
+    private String modlTypeCd;
+    private String operMode;
+    private Integer cmncFailRate;
+    private Integer brghNghtStep;
+    private Integer brghWeekStep;
+    private Integer defPhseChngCycl;
+    private Integer modlErrRate;
+    private Integer cmncfailSlotNmbr;
+    private Integer pwerFailSlotNmbr;
+    private String cmtrinfrCnctYn;
+    private String wthrinfrCnctYn;
+    private String envrinfrCnctYn;
+    private Integer maxPhseNum;
+    private String panlOnTime;
+    private String panlOffTime;
+    private String panlPwerMode;
+    private String brghMode;
+    private String istlLctnNm;
+    private String trfcStrgUseYn;
+    private Long locIfscId;
+    private Double fanRunTmpr;
+    private Double hetrRunTmpr;
+    private Integer fanMode;
+    private Integer hetrMode;
+    private Integer brghCurrStep;
+    private String istlLctnAddr;
+    private Integer protocolVer;
+    private String delYn;
+
+    private int vmsWidth;
+    private int vmsHeight;
+    private int modlRowNum;
+    private int modlColNum;
+    private int powrRowNum;
+    private int powrColNum;
+
+    private String localFormDir;
+    private String ftpFormDir;
+    private boolean isFtpDownload;
+    private boolean isSymbolDownload;
+
+
+    private TbVmsCtlrSttsDto stts;
+    private int 			  netState;
+    private boolean           isDupCon;
+    private boolean           isDupLogin;
+    private String 		      dstIpAddr;
+    private Channel channel;
+    private Channel           dupChannel;
+    private InetSocketAddress cliReq;
+    private long              syncTime;
+    private VmsFrameSequence seq;
+
+    private ConcurrentHashMap<Long, TbVmsRltnIfsc> rltnIfscMap = null;
+
+    //private ConcurrentHashMap<Long, C2CAuthenticatedMessage> registeredCommands = null;
+    private ConcurrentHashMap<Long, Timer> registeredCommandsTimer = null;
+    private ConcurrentHashMap<Long, TbRseCtrlHs> userCommands = null;
+    private ConcurrentHashMap<String, TbRseOffrSect> offrSectMap = null;
+
+    private int connectCount;
+    private String connectTm;
+    private String disConnectTm;
+    private long lastRecvTime;
+
+    public void init() {
+        this.stts = new TbVmsCtlrSttsDto(this.ctlrNmbr);
+        this.seq  = new VmsFrameSequence();
+        this.registeredCommandsTimer = new ConcurrentHashMap<>();
+        this.userCommands = new ConcurrentHashMap<>();
+        this.offrSectMap = new ConcurrentHashMap<>();
+        this.rltnIfscMap = new ConcurrentHashMap<>();
+
+        this.connectCount = 0;
+        this.connectTm = "-";
+        this.disConnectTm = "-";
+        this.lastRecvTime = 0;
+
+        this.isFtpDownload = false;
+        this.isSymbolDownload = false;
+
+        initNet();
+    }
+
+    public synchronized void connected(ChannelHandlerContext ctx) {
+        this.netState = NET.LOGIN_REQ;
+        this.connectTm = SysUtils.getSysTimeStr();
+        this.channel = ctx.channel();
+        this.lastRecvTime = System.currentTimeMillis();
+        this.connectCount++;
+        this.stts.initNormal();
+    }
+
+    public synchronized void disconnected() {
+        this.netState = NET.CLOSED;
+        //this.registeredCommands.clear();
+        this.registeredCommandsTimer.clear();
+        this.channel = null;
+        this.stts.initError();
+        this.disConnectTm = SysUtils.getSysTimeStr();
+        this.stts.initError();
+    }
+
+    public String getLogKey() {
+        return this.ctlrId;
+    }
+
+    public String getLastRecvTimeFmt() {
+        SimpleDateFormat sdfDate = new SimpleDateFormat("MM-dd HH:mm:ss");
+        return sdfDate.format(lastRecvTime);
+    }
+
+    public void resetConnectCount() {
+        if (this.netState == NET.CLOSED)
+            this.connectCount = 0;
+        else
+            this.connectCount = 1;
+    }
+
+    void initNet() {
+        this.netState   = NET.CLOSED;
+        this.isDupCon   = false;
+        this.isDupLogin = false;
+        this.dstIpAddr  = "";
+        this.channel    = null;
+        this.dupChannel = null;
+        this.cliReq     = null;
+        this.syncTime   = 0;
+    }
+
+    public synchronized void channelLogin(Channel channel) {
+        this.channel = channel;
+
+        //this.registeredCommands.clear();
+        for (Map.Entry<Long, Timer> e : this.registeredCommandsTimer.entrySet()) {
+            Timer task = e.getValue();
+            task.cancel();
+        }
+        this.registeredCommandsTimer.clear();
+
+        this.netState = NET.LOGINED;
+    }
+    public synchronized void channelLoginInit() {
+        //this.registeredCommands.clear();
+        for (Map.Entry<Long, Timer> e : this.registeredCommandsTimer.entrySet()) {
+            Timer task = e.getValue();
+            task.cancel();
+        }
+        this.registeredCommandsTimer.clear();
+
+        this.netState = NET.LOGINED;
+    }
+
+    public void sleep(long milliSeconds) {
+        try {
+            Thread.sleep(milliSeconds);
+        } catch (InterruptedException e) {
+            log.error("sleep: InterruptedException");
+        }
+    }
+
+    /**
+     * Channel Send Data
+     * @param sendBuffer
+     * @param delayMilliSeconds
+     * @param packetDesc
+     * @return
+     */
+    public boolean sendData(ByteBuffer sendBuffer, int delayMilliSeconds, String packetDesc) {
+        boolean result = false;
+        if (this.channel != null) {
+            ChannelFuture f = this.channel.writeAndFlush(sendBuffer);
+            f.awaitUninterruptibly();
+            if (f.isDone() || f.isSuccess()) {
+                result = true;
+                if (delayMilliSeconds > 0) {
+                    sleep(delayMilliSeconds);
+                }
+            } else {
+                log.error("[{}]. sendData: Failed. {}, {} Bytes.", this.ctlrNmbr, packetDesc, sendBuffer.array().length);
+            }
+        } else {
+            log.error("[{}]. sendData: Failed. Not Connected. {}, {} Bytes.", this.ctlrNmbr, packetDesc, sendBuffer.array().length);
+        }
+        return result;
+    }
+
+    public boolean channelClose() {
+        if (getChannel() == null || getNetState() == NET.CLOSED) {
+            log.error("Close Request: channel not connected: [{}]", this);
+            return false;
+        }
+        VmsServerIdleStateHandler.disconnectChannel(this, getChannel());
+        return true;
+    }
+
+    public int reset(int devcType, int cntlType, TbRseCtrlHs ctrlHs) {
+        if (getChannel() == null || getNetState() == NET.CLOSED) {
+            log.error("Reset Request: channel not connected: [{}]", this);
+            return 1;
+        }
+        eControlDeviceId controlDeviceId = eControlDeviceId.getByValue(devcType);
+        eControlCommand commandType = eControlCommand.getByValue(cntlType);
+        if (controlDeviceId == null || commandType == null) {
+            log.error("Reset Request: control type missMatched: [{}], {}, {}", this, controlDeviceId, commandType);
+            return 2;
+        }
+
+        log.warn("[{}] [{},{}], controlDeviceId: {}, commandType: {}", this.ctlrNmbr, devcType, cntlType, controlDeviceId.toString(), commandType.toString());
+//		boolean res = ControlDeviceService.getInstance().requestResetCommand(true, this, getChannel());
+//		if (res) {
+//			log.info("RSE REQ CONTROL SEND OK: [{}] [{},{}]", this.RSE_CTLR_NMBR, devcType, cntlType);
+//			return 0;
+//		}
+        log.error("RSE REQ CONTROL SEND Error: [{}] [{},{}]", this.ctlrNmbr, devcType, cntlType);
+        return 3;
+    }
+
+    public synchronized boolean addUserCommands(Long packetNmbr, TbRseCtrlHs command) {
+
+        this.userCommands.put(packetNmbr, command);
+        return addCommandTimer(packetNmbr);
+    }
+
+    public synchronized boolean removeUserCommands(Long packetNmbr) {
+
+        TbRseCtrlHs command = this.userCommands.get(packetNmbr);
+        if (command != null) {
+            this.userCommands.remove(packetNmbr);
+            return true;
+        }
+        return false;
+    }
+
+    public synchronized TbRseCtrlHs getUserCommands(Long packetNmbr) {
+
+        TbRseCtrlHs command = this.userCommands.get(packetNmbr);
+        return command;
+    }
+
+    private boolean addCommandTimer(Long packetNmbr) {
+
+        long timeoutSec = 10;//this.login.getDatexLoginResponseTimeOutQty().value.longValue();
+        if (timeoutSec == 0L || timeoutSec > 30L) {
+            timeoutSec = 30L;
+        }
+        if (timeoutSec < 5L)
+            timeoutSec = 5L;
+
+        timeoutSec = 1000L * timeoutSec;
+        Timer timer = new Timer();
+        timer.schedule((TimerTask)new VmsTimeoutTask(this, packetNmbr), timeoutSec);
+        this.registeredCommandsTimer.put(packetNmbr, timer);
+
+        log.info("addCommandTimer: [{}], packetNmbr: {}, timeoutSec: {} ms, {}", this.ctlrNmbr, packetNmbr, timeoutSec, timer);
+        return true;
+    }
+
+//	public synchronized boolean putRegisteredCommands(C2CAuthenticatedMessage c2c) {
+//
+//		if (this.login == null || this.headerOptions == null) {
+//			return false;
+//		}
+//		PDUs pdUs = c2c.getPdu();
+//		if (pdUs.getSubscription() == null && pdUs.getPublication() == null) {
+//			// Subscription 또는 Publication 요청에 대해서만 타임아웃 체크
+//			return false;
+//		}
+//
+//		Long packetNmbr = c2c.getDatexDataPacketNumber().value.longValue();
+//		this.registeredCommands.put(packetNmbr, c2c);
+//		return addCommandTimer(packetNmbr);
+//	}
+
+    public synchronized boolean removeRegisteredCommandsTimer(int packetNmbr) {
+
+        Timer timer = this.registeredCommandsTimer.get(Integer.valueOf(packetNmbr));
+        if (timer != null) {
+            this.registeredCommandsTimer.remove(Integer.valueOf(packetNmbr));
+        }
+        return true;
+    }
+
+    public synchronized boolean removeRegisteredCommands(Long packetNmbr, boolean cancelTimer) {
+
+        Timer timer = this.registeredCommandsTimer.get(packetNmbr);
+        if (timer != null) {
+            if (cancelTimer)
+                timer.cancel();
+            this.registeredCommandsTimer.remove(packetNmbr);
+        }
+
+//		C2CAuthenticatedMessage c2c = this.registeredCommands.get(packetNmbr);
+//		if (c2c != null) {
+//			this.registeredCommands.remove(packetNmbr);
+//		}
+        return false;
+    }
+
+//	public synchronized C2CAuthenticatedMessage getRegisteredCommands(int packetNmbr) {
+//		C2CAuthenticatedMessage c2c = this.registeredCommands.get(packetNmbr);
+//		return c2c;
+//	}
+
+    public synchronized boolean sendFrED() {
+        if (getChannel() == null || getNetState() == NET.CLOSED) {
+            log.error("sendFrED Request: channel not connected: [{}]", this);
+            return false;
+        }
+        return true;
+        //return FredResponse.sendFrED(this, getChannel());
+    }
+}

+ 26 - 0
src/main/java/com/its/vms/entity/TbVmsFontColr.java

@@ -0,0 +1,26 @@
+package com.its.vms.entity;
+
+import io.swagger.annotations.ApiModel;
+import lombok.AllArgsConstructor;
+import lombok.Builder;
+import lombok.Getter;
+import lombok.NoArgsConstructor;
+
+import java.io.Serializable;
+
+/**
+ *  Entity Class
+ */
+@Getter
+@Builder
+@NoArgsConstructor//(access = AccessLevel.PROTECTED)
+@AllArgsConstructor
+public class TbVmsFontColr implements Serializable {
+    private static final long serialVersionUID = 1L;
+
+    private Integer vmsFontColrCd;
+    private String vmsFontColrNm;
+    private Long vmsFontColrVal;
+    private String useYn;
+
+}

+ 25 - 0
src/main/java/com/its/vms/entity/TbVmsFontName.java

@@ -0,0 +1,25 @@
+package com.its.vms.entity;
+
+import io.swagger.annotations.ApiModel;
+import lombok.AllArgsConstructor;
+import lombok.Builder;
+import lombok.Getter;
+import lombok.NoArgsConstructor;
+
+import java.io.Serializable;
+
+/**
+ *  Entity Class
+ */
+@Getter
+@Builder
+@NoArgsConstructor//(access = AccessLevel.PROTECTED)
+@AllArgsConstructor
+public class TbVmsFontName implements Serializable {
+    private static final long serialVersionUID = 1L;
+
+    private Integer vmsFontNameCd;
+    private String vmsFontNameNm;
+    private String useYn;
+
+}

+ 40 - 0
src/main/java/com/its/vms/entity/TbVmsIfsc.java

@@ -0,0 +1,40 @@
+package com.its.vms.entity;
+
+import io.swagger.annotations.ApiModel;
+import lombok.AllArgsConstructor;
+import lombok.Builder;
+import lombok.Getter;
+import lombok.NoArgsConstructor;
+
+import java.io.Serializable;
+
+/**
+ *  Entity Class
+ */
+@Getter
+@Builder
+@NoArgsConstructor//(access = AccessLevel.PROTECTED)
+@AllArgsConstructor
+public class TbVmsIfsc implements Serializable {
+    private static final long serialVersionUID = 1L;
+
+    private Long vmsIfscId;
+    private String vmsIfscNm;
+    private String dsplStrtNodeNm;
+    private String dsplEndNodeNm;
+    private Long detrId;
+
+    private String roadNm;
+    private String spotNm;
+    private String axisYn;
+
+    private String useYn;
+    private Integer cngsSpd;
+
+    // 교통정보
+    private String prcnDt;
+    private String cmtrGradCd;
+    private Integer sped;
+    private Integer trvlHh;
+
+}

+ 36 - 0
src/main/java/com/its/vms/entity/TbVmsIfscTraf.java

@@ -0,0 +1,36 @@
+package com.its.vms.entity;
+
+import lombok.AllArgsConstructor;
+import lombok.Builder;
+import lombok.Data;
+import lombok.NoArgsConstructor;
+
+import java.io.Serializable;
+
+/**
+ *  Entity Class
+ */
+@Data
+@Builder
+@NoArgsConstructor//(access = AccessLevel.PROTECTED)
+@AllArgsConstructor
+public class TbVmsIfscTraf implements Serializable {
+    private static final long serialVersionUID = 1L;
+
+    private Long vmsIfscId;
+    private String vmsIfscNm;
+    private String dsplStrtNodeNm;
+    private String dsplEndNodeNm;
+    private Long detrId;
+    private String roadNm;
+    private String spotNm;
+    private String axisYn;
+
+    private String prcnDt;
+    private String cmtrGradCd;
+    private Integer sped;
+    private Integer trvlHh;
+
+    private Integer cngstCnt;
+    private String cngstDt;
+}

+ 28 - 0
src/main/java/com/its/vms/entity/TbVmsRltnIfsc.java

@@ -0,0 +1,28 @@
+package com.its.vms.entity;
+
+import lombok.*;
+
+import java.io.Serializable;
+
+/**
+ *  Entity Class
+ */
+@Data
+@Builder
+@NoArgsConstructor
+@AllArgsConstructor
+public class TbVmsRltnIfsc implements Serializable {
+    private static final long serialVersionUID = 1L;
+
+    private Long vmsCtlrNmbr;
+    private Long vmsIfscId;
+    private Integer dsplPrrt;
+    private String axisYn;
+    private Integer cngstSped;
+    private boolean cngstCnfmYn;
+    private Integer cngstCnfmSped;
+
+    private boolean isUsed;
+    private int cngstCnt;
+    private String cngstDt;
+}

+ 30 - 0
src/main/java/com/its/vms/entity/TbVmsSymbIfsc.java

@@ -0,0 +1,30 @@
+package com.its.vms.entity;
+
+import io.swagger.annotations.ApiModel;
+import lombok.AllArgsConstructor;
+import lombok.Builder;
+import lombok.Data;
+import lombok.NoArgsConstructor;
+
+import java.io.Serializable;
+
+/**
+ *  Entity Class
+ */
+@Data
+@Builder
+@NoArgsConstructor//(access = AccessLevel.PROTECTED)
+@AllArgsConstructor
+public class TbVmsSymbIfsc implements Serializable {
+    private static final long serialVersionUID = 1L;
+
+    private Integer symbLibNmbr;
+    private Integer cellId;
+    private Integer posX;
+    private Integer posY;
+    private Long vmsIfscId;
+    private String updtDt;
+
+    private boolean isDup;
+
+}

+ 104 - 0
src/main/java/com/its/vms/entity/TbVmsSymbLib.java

@@ -0,0 +1,104 @@
+package com.its.vms.entity;
+
+import com.its.vms.dto.TbVmsSymbLibDto;
+import lombok.AllArgsConstructor;
+import lombok.Builder;
+import lombok.Data;
+import lombok.NoArgsConstructor;
+import lombok.extern.slf4j.Slf4j;
+
+import javax.imageio.ImageIO;
+import java.awt.*;
+import java.io.ByteArrayInputStream;
+import java.io.IOException;
+import java.io.Serializable;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+
+/**
+ *  Entity Class
+ */
+@Slf4j
+@Data
+@Builder
+@NoArgsConstructor//(access = AccessLevel.PROTECTED)
+@AllArgsConstructor
+public class TbVmsSymbLib implements Serializable {
+    private static final long serialVersionUID = 1L;
+
+    private String symbLibNmbr;
+    private Integer orgSymbLibNmbr;
+    private String rgstDt;
+    private byte[] redData;
+    private byte[] greenData;
+    private String symbExpl;
+    private byte[] imagData;
+    private String vmsTypeCd;
+    private String symbImagType;
+    private String symbFileNm;
+    private String symbType;
+    private byte[] aviData;
+    private Long imagSize;
+    private Long playTm;
+    private String delYn;
+    private String updtDt;
+    private Integer posX;
+    private Integer posY;
+
+    private eVmsImageType imagType;
+    private String localFileName;
+    private String ftpFileName;
+
+    private List<String> gradSymbLibNmbrList = new ArrayList<>();
+    private HashMap<Integer, TbVmsSymbIfsc> cellMap = new HashMap<>();
+
+    public Image getImage() {
+        if (this.imagData == null || this.imagData.length == 0) {
+            log.error("getImage: Image Data null: {}", this.orgSymbLibNmbr);
+            return null;
+        }
+
+        try (
+                ByteArrayInputStream bis = new ByteArrayInputStream(this.imagData);
+        ) {
+            return ImageIO.read(bis);
+        } catch (IOException e) {
+            log.error("getImage: IOException: {}", this.orgSymbLibNmbr);
+        }
+        return null;
+    }
+
+    public TbVmsSymbLib clone(String symbLibNmbr) {
+        TbVmsSymbLib obj = TbVmsSymbLib.builder()
+                .symbLibNmbr(symbLibNmbr)
+                .orgSymbLibNmbr(this.orgSymbLibNmbr)
+                .rgstDt(this.rgstDt)
+                .redData(this.redData)
+                .greenData(this.greenData)
+                .symbExpl(this.symbExpl)
+                .imagData(this.imagData)
+                .vmsTypeCd(this.vmsTypeCd)
+                .symbImagType(this.symbImagType)
+                .symbFileNm(this.symbFileNm)
+                .symbType(this.symbType)
+                .aviData(this.aviData)
+                .imagSize(this.imagSize)
+                .playTm(this.playTm)
+                .delYn(this.delYn)
+                .updtDt(this.updtDt)
+                .posX(this.posX)
+                .posY(this.posY)
+                .imagType(this.imagType)
+                .localFileName(this.localFileName)
+                .ftpFileName(this.ftpFileName)
+                .gradSymbLibNmbrList( new ArrayList<>())
+                .cellMap(new HashMap<>())
+                .build();
+
+        TbVmsSymbLibDto.setSymbInfo(obj);
+
+        return obj;
+    }
+
+}

+ 44 - 0
src/main/java/com/its/vms/entity/eVmsImageType.java

@@ -0,0 +1,44 @@
+package com.its.vms.entity;
+
+import java.util.HashMap;
+import java.util.Map;
+
+public enum eVmsImageType {
+
+    vms_image_type_bmp(0, "bmp"),			/* 0:비트맵 */
+    vms_image_type_gif(1, "gif"),			/* 1:GIF */
+    vms_image_type_jpg(2, "jpg"),			/* 2:JPG */
+    vms_image_type_png(3, "png"),			/* 3:PNG */
+    vms_image_type_video(4, "avi"); 		/* 4:동영상 비디오 */
+
+    private final int value;
+    private final String string;
+
+    private static final Map<Integer, eVmsImageType> map;
+    static {
+        map = new HashMap<>();
+        for (eVmsImageType e : values()) {
+            map.put(Integer.valueOf(e.value), e);
+        }
+    }
+
+    public static eVmsImageType getByValue(int value) {
+        return map.get(value);
+    }
+    public static eVmsImageType getByValue(byte value) {
+        int intValue = (value & 0x0F);
+        return map.get(intValue);
+    }
+
+    eVmsImageType(int value, String string) {
+        this.value  = value;
+        this.string = string;
+    }
+
+    public int getValue() {
+        return this.value;
+    }
+    public String toString() {
+        return this.string;
+    }
+}

+ 67 - 0
src/main/java/com/its/vms/global/AppRepository.java

@@ -0,0 +1,67 @@
+package com.its.vms.global;
+
+import com.google.common.collect.HashMultimap;
+import com.google.common.collect.Multimap;
+import com.google.common.collect.Multimaps;
+import com.its.vms.entity.*;
+import io.netty.channel.Channel;
+import lombok.Getter;
+import lombok.Setter;
+import lombok.extern.slf4j.Slf4j;
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+import java.util.concurrent.ConcurrentHashMap;
+
+@Getter
+@Setter
+@Slf4j
+public class AppRepository {
+    private static AppRepository _instance = null;
+
+    public ConcurrentHashMap<Long, TbVmsCtlr> ctlrMap = null;
+    public ConcurrentHashMap<String, TbVmsCtlr> ctlrIpMap = null;
+    public ConcurrentHashMap<Channel, TbVmsCtlr> ctlrChannelMap = null;
+
+    // RSE_SECT 정보관리, RSE Sect 관리(sect_id, start_rsd_id, end_rse_id, ...)
+    public ConcurrentHashMap<String, TbRseSect> rseSectMap = null;
+    // 시작 RSE 를 키로 하는 SECT_ID 목록, { STRT_ID, [SECT_ID, SECT_ID, ...] }
+    public Multimap<String, String> rseSectStartMap = null;
+    // 종료 RSE 를 키로 하는 SECT_ID 목록, { END_ID, [SECT_ID, SECT_ID, ...] }
+    public Multimap<String, String> rseSectEndMap = null;
+
+    public List<TbRseObuNonCrypt> rseObuNonCryptList = null;
+    public List<TbRseOffrDrct> rseOffrDrctList = null;
+
+    public static AppRepository getInstance() {
+        if (_instance == null) {
+            synchronized (AppRepository.class) {
+                if (_instance == null)
+                    _instance = new AppRepository();
+            }
+        }
+        return _instance;
+    }
+
+    public AppRepository() {
+        this.ctlrMap = new ConcurrentHashMap<>();
+        this.ctlrIpMap = new ConcurrentHashMap<>();
+        this.ctlrChannelMap = new ConcurrentHashMap<>();
+        this.rseSectMap = new ConcurrentHashMap<>();
+        this.rseSectStartMap = Multimaps.synchronizedMultimap((Multimap)HashMultimap.create());
+        this.rseSectEndMap = Multimaps.synchronizedMultimap((Multimap)HashMultimap.create());
+        this.rseObuNonCryptList = Collections.synchronizedList(new ArrayList<>());
+        this.rseOffrDrctList = Collections.synchronizedList(new ArrayList<>());
+    }
+
+    public List<TbRseOffrDrct> getRseOffrDrctList(String rseId) {
+        List<TbRseOffrDrct> list = Collections.synchronizedList(new ArrayList<>());
+        for (TbRseOffrDrct vo : this.rseOffrDrctList) {
+            if (vo.getRSE_CTLR_NMBR().equals(rseId))
+                list.add(vo);
+        }
+        return list;
+    }
+
+}

+ 20 - 0
src/main/java/com/its/vms/process/DbmsData.java

@@ -0,0 +1,20 @@
+package com.its.vms.process;
+
+import lombok.Getter;
+import lombok.Setter;
+
+@Getter
+@Setter
+public class DbmsData {
+
+    private DbmsDataType type;
+    private boolean      isHistory;
+    private Object       data;
+
+    public DbmsData(DbmsDataType type, boolean isHistory, Object data) {
+        this.type      = type;
+        this.isHistory = isHistory;
+        this.data      = data;
+    }
+
+}

+ 16 - 0
src/main/java/com/its/vms/process/DbmsDataAsyncTask.java

@@ -0,0 +1,16 @@
+package com.its.vms.process;
+
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.scheduling.annotation.Async;
+import org.springframework.stereotype.Service;
+
+@Slf4j
+@Service
+public class DbmsDataAsyncTask {
+
+    @Async("dbmsDataExecutor")
+    public void run(DbmsDataProcess process, DbmsData data) {
+        process.runJob(data);
+    }
+
+}

+ 152 - 0
src/main/java/com/its/vms/process/DbmsDataProcess.java

@@ -0,0 +1,152 @@
+package com.its.vms.process;
+
+import com.its.app.AppUtils;
+import com.its.vms.config.ThreadPoolInitializer;
+import com.its.vms.dao.mapper.VmsCtlrMapper;
+import com.its.vms.dao.mapper.UnitSystMapper;
+import com.its.vms.dao.mapper.batch.VmsCtlrDao;
+import com.its.vms.dto.TbVmsCtlrSttsDto;
+import com.its.vms.entity.*;
+import com.its.vms.service.MultimediaService;
+import com.its.vms.service.RseObuClctService;
+import lombok.RequiredArgsConstructor;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.stereotype.Service;
+
+import javax.annotation.PostConstruct;
+import java.util.List;
+import java.util.concurrent.Executors;
+import java.util.concurrent.LinkedBlockingQueue;
+import java.util.concurrent.ThreadPoolExecutor;
+
+@Slf4j
+@RequiredArgsConstructor
+@Service
+public class DbmsDataProcess {
+
+    private final LinkedBlockingQueue<DbmsData> DBMS_DATA_QUEUE = new LinkedBlockingQueue<>(1000);
+    private final ThreadPoolExecutor taskExecutor = (ThreadPoolExecutor) Executors.newFixedThreadPool(1);
+
+    private final DbmsDataAsyncTask asyncTask;
+    private final VmsCtlrDao vmsCtlrDao;
+
+    private final UnitSystMapper unitSystMapper;
+    private final VmsCtlrMapper vmsCtlrMapper;
+
+    private final RseObuClctService rseObuClctService;
+    private final MultimediaService multimediaService;
+
+    int MAX_CORE = Runtime.getRuntime().availableProcessors();
+
+    @PostConstruct
+    void init() {
+    }
+
+    public void run() {
+        log.info("DbmsDataProcess.run: Start.");
+        if (this.MAX_CORE < 8) {
+            this.MAX_CORE = 8;
+        }
+        ThreadPoolInitializer poolInitializer = (ThreadPoolInitializer) AppUtils.getBean(ThreadPoolInitializer.class);
+        int executePool = Math.max(this.MAX_CORE, poolInitializer.getWork());
+        for (int ii = 0; ii < executePool; ii++) {
+            log.info("DbmsDataProcess.Task: {}", ii);
+            this.taskExecutor.execute(() -> {
+                while (true) {
+                    try {
+                        DbmsData data = DBMS_DATA_QUEUE.take();
+                        if (data != null) {
+                            asyncTask.run(this, data);
+                        }
+                        else {
+                            log.error("DbmsDataProcess.Task: Received data null");
+                        }
+                    }
+                    catch (Exception e) {
+                        log.error("DbmsDataProcess.Task: Exception: {}", e.getMessage(), e);
+                    }
+                }
+            });
+        }
+
+        log.info("DbmsDataProcess.run: ..End.");
+    }
+
+    /**
+     * 비동기 타스크에서 실행되는 함수.
+     * 클래스가 달라야 비동기 타스크로 실행된다.
+     * @param data
+     */
+    public void runJob(DbmsData data) {
+        if (data.getType() == DbmsDataType.DBMS_DATA_UNIT_SYST_STTS) {
+            TbUnitSystStts stts = (TbUnitSystStts) data.getData();
+            this.unitSystMapper.updateUnitSystStts(stts);       // 상태정보 업데이트
+            if (data.isHistory()) {
+                this.unitSystMapper.insertUnitSystSttsHs(stts); // 상태정보 이력저장
+            }
+        }
+        else {
+            process(data);
+        }
+    }
+
+    public void process(DbmsData data) {
+        try {
+            DbmsDataType type = data.getType();
+            switch(type) {
+                case DBMS_DATA_CTLR_STTS:
+                    TbVmsCtlrSttsDto ctlrStts = (TbVmsCtlrSttsDto)data.getData();
+                    this.vmsCtlrMapper.updateCtlrStts(ctlrStts);
+                    break;
+                case DBMS_DATA_CTLR_STTS_LIST:
+                    List<TbVmsCtlrSttsDto> ctlrSttsList = (List<TbVmsCtlrSttsDto>)data.getData();
+                    this.vmsCtlrDao.updateStts(ctlrSttsList, data.isHistory());
+                    if (data.isHistory()) {
+                        this.vmsCtlrDao.insertStts(ctlrSttsList);
+                    }
+                    ctlrSttsList.clear();
+                    break;
+                case DBMS_DATA_OBU_GATHER_LOG:
+                    List<TbRseObuClct> obuGatherInfos = (List<TbRseObuClct>)data.getData();
+                    this.rseObuClctService.insertOBUGatherInfoHs(obuGatherInfos);
+                    break;
+                case DBMS_DATA_SECT_TRAF_HS:
+                    List<TbRseSectTraf> sectTrafInfos = (List<TbRseSectTraf>)data.getData();
+                    this.rseObuClctService.insertDsrcSectTraf(sectTrafInfos);
+                    break;
+                case DBMS_DATA_SECT_PASS_HS:
+                    List<TbRseSectPassHs> sectPassInfos = (List<TbRseSectPassHs>)data.getData();
+                    this.rseObuClctService.insertDsrcSectPassHs(sectPassInfos);
+                    break;
+                case DBMS_DATA_LOG_HS:
+                    this.vmsCtlrMapper.insertRseCtlrCnncHs((TbRseCtlrCnncHs)data.getData());
+                    break;
+                case DBMS_DATA_CTRL_HS:
+                    this.vmsCtlrMapper.insertRseCtrlHs((TbRseCtrlHs)data.getData());
+                    break;
+            }
+        } catch (Exception e) {
+            log.error("DbmsJobProcess.process: Exception: {}", e.toString());
+        }
+    }
+
+    /*
+     *  작업큐에 데이터 추가
+     */
+    public boolean add(DbmsData data) {
+        boolean offer = false;
+        try {
+            //offer => full -> return
+            //add   => full -> wait
+            //큐가 차더라도 바로 리턴함.
+            offer = DBMS_DATA_QUEUE.offer(data);
+            if (!offer) {
+                log.error("DbmsDataProcess.add: Queue Full Error, Size: {} EA", DBMS_DATA_QUEUE.size());
+            }
+        } catch (Exception e) {
+            log.error("DbmsDataProcess.add: Exception: {}", e.getMessage(), e);
+        }
+        return offer;
+    }
+
+}

+ 15 - 0
src/main/java/com/its/vms/process/DbmsDataType.java

@@ -0,0 +1,15 @@
+package com.its.vms.process;
+
+public enum DbmsDataType {
+
+    DBMS_DATA_UNIT_SYST_STTS,
+    DBMS_DATA_CTLR_STTS,
+    DBMS_DATA_CTLR_STTS_LIST,
+    DBMS_DATA_OBU_GATHER_LOG,
+    DBMS_DATA_SECT_TRAF_HS,
+    DBMS_DATA_SECT_PASS_HS,
+    DBMS_DATA_LOG_HS,
+    DBMS_DATA_MULTIMEDIA_HS,
+    DBMS_DATA_CTRL_HS,
+
+}

+ 112 - 0
src/main/java/com/its/vms/scheduler/SchedulerTask.java

@@ -0,0 +1,112 @@
+package com.its.vms.scheduler;
+
+import com.its.app.utils.Elapsed;
+import com.its.app.utils.StatisticsTime;
+import com.its.vms.config.ApplicationConfig;
+import com.its.vms.config.CommunicationConfig;
+import com.its.vms.service.VmsCtlrService;
+import com.its.vms.service.RseSectService;
+import com.its.vms.service.StatisticsServices;
+import com.its.vms.service.UnitSystService;
+import lombok.AllArgsConstructor;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.scheduling.annotation.EnableScheduling;
+import org.springframework.scheduling.annotation.Scheduled;
+import org.springframework.stereotype.Component;
+
+import javax.annotation.PreDestroy;
+
+@Slf4j
+@AllArgsConstructor
+@EnableScheduling
+@Component
+public class SchedulerTask {
+
+    private final ApplicationConfig applicationConfig;
+    private final CommunicationConfig communicationConfig;
+    private final UnitSystService unitSystService;
+    private final VmsCtlrService vmsCtlrService;
+    private final RseSectService rseSectService;
+    private final StatisticsServices statisticsServices;
+
+    @PreDestroy
+    public void onShutDown() {
+         this.unitSystService.updateUnitSystStts(false);
+    }
+
+    @Scheduled(cron = "5 * * * * *")  // 1분주기 작업 실행
+    public void scheduleUnitSystStts() {
+        if (!this.applicationConfig.isStartSchedule()) {
+            return;
+        }
+        Elapsed elapsed = new Elapsed();
+        log.info("unitSystStts: start. {}", Thread.currentThread().getName());
+        // 1. 프로세스 상태정보 업데이트
+        this.unitSystService.updateUnitSystStts(true);
+        // 1. 제어기 상태정보 업데이트(제어기/프로세스 상태정보 UDP 전송)
+        this.vmsCtlrService.updateCtlrStts(true, null);
+        log.info("unitSystStts: ..end. {} ms. {}", elapsed.milliSeconds(), Thread.currentThread().getName());
+    }
+
+    //@Scheduled(cron = "1 0/5 * * * ?")  // 5분주기 작업 실행(DSRC 구간 소통정보 생성)
+    @Scheduled(cron = "50 4,9,14,19,24,29,34,39,44,49,54,59 * * * *")  // 5분주기 작업 실행(DSRC 구간 소통정보 생성)
+    public void scheduleMakeSectTraf() {
+        if (!this.applicationConfig.isStartSchedule()) {
+            return;
+        }
+        Elapsed elapsed = new Elapsed();
+        log.info("makeSectTraf: start. {}", Thread.currentThread().getName());
+        this.rseSectService.makeDsrcSectTraffic();
+        log.info("makeSectTraf: ..end. {} ms. {}", elapsed.milliSeconds(), Thread.currentThread().getName());
+    }
+
+    @Scheduled(cron = "30 0/5 * * * *")  // DSRC Multimedia 작업 실행 ==> 교통정보 가공이 완료된 후에 실행
+    public void scheduleMultimedia() {
+        if (!this.applicationConfig.isStartSchedule()) {
+            return;
+        }
+
+//        if (this.runningConfig.isPublicationMultimedia()) {
+//            Elapsed elapsed = new Elapsed();
+//            log.info("multimedia..: start. {}", Thread.currentThread().getName());
+//            MultiMediaDataService.getInstance().makeMultimediaData();
+//            log.info("multimedia..: ..end. {} ms. {}", elapsed.milliSeconds(), Thread.currentThread().getName());
+//        }
+    }
+
+    @Scheduled(cron = "40 0/5 * * * *")    // 정주기 5분 40초에 스케쥴 실행
+    public void schedule5M() {
+        if (!this.applicationConfig.isStartSchedule()) {
+            return;
+        }
+        Elapsed elapsed = new Elapsed();
+        log.info("schedule5M..: start. {}", Thread.currentThread().getName());
+        if (this.applicationConfig.isStatistics()) {
+            StatisticsTime its = new StatisticsTime();
+            its.init();
+            its.setProcessing(true);
+
+            if (its.isStatHour()) {
+                // 매시 5분 가공완료후 1시간 통계
+                this.statisticsServices.CRT_TB_RSE_OBU_CLCT_STAT_HH(its.getStatHourTime(), its.getStatHourTime(), its.getStatHourTo());
+                this.statisticsServices.CRT_TB_RSE_OD_STAT_HH(its.getStatHourTime(), its.getStatHourTime(), its.getStatHourTo());
+            }
+
+            if (its.isStatDay()) {
+                // 00시 10분 가공이 끝나면 이전일의 통계 정보를 가공.
+                this.statisticsServices.CRT_TB_RSE_OBU_CLCT_STAT_DD(its.getStatDayFrom(), its.getStatDayFrom(), its.getStatDayTo());
+            }
+            its.setProcessing(false);
+        }
+        log.info("schedule5M..: ..end. {} ms. {}", elapsed.milliSeconds(), Thread.currentThread().getName());
+    }
+
+    @Scheduled(cron = "0/10 * * * * *")  // 10초 주기 작업 실행
+    public void scheduleFrED() {
+        if (!this.applicationConfig.isStartSchedule()) {
+            return;
+        }
+//        this.rseCtlrService.monitoringSession();
+    }
+
+}

+ 116 - 0
src/main/java/com/its/vms/service/MultimediaService.java

@@ -0,0 +1,116 @@
+package com.its.vms.service;
+
+import com.its.app.AppUtils;
+import com.its.vms.dao.mapper.RseOffrSectMapper;
+import com.its.vms.dto.voDsrcOffrSectTraf;
+import com.its.vms.entity.TbRseOffrSect;
+import com.its.vms.entity.TbRseOffrSectTraf;
+import com.its.vms.entity.TbVmsCtlr;
+import com.its.vms.global.AppRepository;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.stereotype.Service;
+import org.springframework.transaction.annotation.Transactional;
+
+import javax.annotation.PostConstruct;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+import java.util.Map;
+import java.util.concurrent.ConcurrentHashMap;
+
+@Slf4j
+@Service
+@Transactional(rollbackFor = {Exception.class})
+public class MultimediaService {
+
+    private RseOffrSectMapper rseOffrSectMapper;
+
+    private ConcurrentHashMap<String, TbRseOffrSect> offrSectInfoMap = null;
+    private ConcurrentHashMap<String, voDsrcOffrSectTraf> offrSectTrafMap = null;
+    private List<TbRseOffrSectTraf> offrInfrHsList = null;
+
+    @PostConstruct
+    private void init() {
+        log.info("MultimediaService.init: Start.");
+        this.rseOffrSectMapper = (RseOffrSectMapper) AppUtils.getBean(RseOffrSectMapper.class);
+        this.offrSectInfoMap = new ConcurrentHashMap<String, TbRseOffrSect>();
+        this.offrSectTrafMap = new ConcurrentHashMap<String, voDsrcOffrSectTraf>();
+        this.offrInfrHsList = Collections.synchronizedList(new ArrayList<>());
+
+        //loadMaster();
+        log.info("MultimediaService.init: ..End.");
+    }
+
+    public void loadMaster() {
+        // DSRC 정보제공구간 목록 조회
+        loadOffrSectInfo();
+
+        // DSRC 정보제공구간 소통정보 조회
+        // DSRC 제공구간정보에 포함된 기본정보를 소통정보 조회하면서 함께 조회하기 때문에
+        // DSRC 정보제공구간정보는 조회하지 않는다.
+        loadOffrSectTraf();
+    }
+
+    /*
+     *  DSRC 제공구간 정보를 조회하고 DSRC 제어기에 설정한다.
+     *  기존에 존재하는 설정정보를 삭제하고 다시 설정
+     *  (데이터가 너무 많아 Delay 가 생길경우 최초에 한번만 실행하고 주기적으로 업데이트 하는 방법으로 수정가능)
+     */
+    private boolean loadOffrSectInfo() {
+        // DSRC 제공구간 목록을 조회해서 DSRC 제어기에 설정한다.
+        // 기존 제어기의 목록을 삭제한다.
+        for (Map.Entry<Long, TbVmsCtlr> obj : AppRepository.getInstance().getCtlrMap().entrySet()) {
+            obj.getValue().getOffrSectMap().clear();    // 제공구간 목록 초기화
+            this.offrInfrHsList.clear();                // 제공이력 목록 삭제
+        }
+        try {
+            List<TbRseOffrSect> list = this.rseOffrSectMapper.selectRseOffrSectAll();
+            this.offrSectInfoMap.clear();
+            for (TbRseOffrSect vo : list) {
+                this.offrSectInfoMap.put(vo.getOFFR_SECT_ID(), vo);
+                TbVmsCtlr obj = AppRepository.getInstance().getCtlrMap().get(vo.getRSE_CTLR_NMBR());
+                if (obj == null) {
+                    log.error("loadOffrSectInfo, DSRC Not Found: {}", vo.getRSE_CTLR_NMBR());
+                }
+                else {
+                    obj.getOffrSectMap().put(vo.getOFFR_SECT_ID(), vo);
+                }
+            }
+        }
+        catch(Exception e) {
+            log.error("loadOffrSectInfo Error: {}", e);
+        }
+        log.info("loadOffrSectInfo: {} EA.", this.offrSectInfoMap.size());
+        return true;
+    }
+
+    /*
+     *  DSRC 제공구간 소통정보를 조회한다.
+     */
+    private boolean loadOffrSectTraf() {
+        try {
+            List<voDsrcOffrSectTraf> list = this.rseOffrSectMapper.selectRseOffrSectTraf();
+            this.offrSectTrafMap.clear();
+            for (voDsrcOffrSectTraf vo : list) {
+                this.offrSectTrafMap.put(vo.getOFFR_SECT_ID(), vo);
+            }
+        }
+        catch(Exception e) {
+            log.error("loadOffrSectTraf Error: {}", e);
+        }
+        log.info("loadOffrSectTraf: {} EA.", this.offrSectTrafMap.size());
+        return true;
+    }
+
+    public int insertDsrcOffrInfrHs(List<TbRseOffrSectTraf> list) {
+        // TODO: Transaction 으로 처리하자
+        // 모든 제어기의 제공이력이 리스트에 들어가 있음
+        for (TbRseOffrSectTraf vo : list) {
+            this.rseOffrSectMapper.insertRseOffrSectTrafHs(vo);
+        }
+        int jobCnt = list.size();
+        list.clear();
+        return jobCnt;
+    }
+
+}

+ 87 - 0
src/main/java/com/its/vms/service/RseObuClctService.java

@@ -0,0 +1,87 @@
+package com.its.vms.service;
+
+import com.its.app.AppUtils;
+import com.its.vms.dao.mapper.RseSectMapper;
+import com.its.vms.dao.mapper.RseObuClctMapper;
+import com.its.vms.entity.TbRseSectPassHs;
+import com.its.vms.entity.TbRseSectTraf;
+import com.its.vms.entity.TbRseObuClct;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.stereotype.Service;
+import org.springframework.transaction.annotation.Transactional;
+
+import javax.annotation.PostConstruct;
+import java.util.List;
+
+@Slf4j
+@Service
+@Transactional(rollbackFor = {Exception.class})
+public class RseObuClctService {
+
+    private RseObuClctMapper rseObuClctMapper;
+    private RseSectMapper rseSectMapper;
+
+    @PostConstruct
+    private void init() {
+        log.info("OBUGatherService.init: Start.");
+        this.rseObuClctMapper = (RseObuClctMapper) AppUtils.getBean(RseObuClctMapper.class);
+        this.rseSectMapper = (RseSectMapper) AppUtils.getBean(RseSectMapper.class);
+        log.info("OBUGatherService.init: ..End.");
+    }
+
+    public int insertOBUGatherInfoHs(List<TbRseObuClct> list) {
+        // TODO: Transaction 으로 처리하자
+        TbRseObuClct pnst = null;
+        for (TbRseObuClct vo : list) {
+            this.rseObuClctMapper.insertRseObuClctHs(vo);
+            pnst = vo;
+        }
+        if (pnst != null) {
+            this.rseObuClctMapper.updateRseObuClctPnst(pnst);
+        }
+        int jobCnt = list.size();
+        list.clear();
+        return jobCnt;
+    }
+
+    public int insertDsrcSectTraf(List<TbRseSectTraf> list) {
+        // TODO: Transaction 으로 처리하자
+        for (TbRseSectTraf vo : list) {
+            this.rseSectMapper.updateRseSectTraf(vo);
+            this.rseSectMapper.insertRseSectTrafHs(vo);
+        }
+        int jobCnt = list.size();
+        list.clear();
+        return jobCnt;
+    }
+
+    public int insertDsrcSectPassHs(List<TbRseSectPassHs> list) {
+        // TODO: Transaction 으로 처리하자
+        for (TbRseSectPassHs vo : list) {
+            this.rseSectMapper.insertRseSectPassHs(vo);
+        }
+        int jobCnt = list.size();
+        list.clear();
+        return jobCnt;
+    }
+    /*
+    List<AccountDto> accouts = new ArrayList<>();
+    accounts.add(new AccountDto("wedul", 123);
+    accounts.add(new AccountDto("cjung", 456);
+
+    accountDao.insertAccounts(accounts);
+
+<insert id="insert" parameterType="java.util.List">
+    INSERT INTO account(
+            id,
+            age
+            ) VALUES
+<foreach item="item" index="index" collection="list">
+            (
+            #{item.id}
+ ,#{item.age}
+)
+</foreach>
+</insert>
+    */
+}

+ 456 - 0
src/main/java/com/its/vms/service/RseSectService.java

@@ -0,0 +1,456 @@
+package com.its.vms.service;
+
+import com.its.app.AppUtils;
+import com.its.app.utils.SysUtils;
+import com.its.vms.config.CommunicationConfig;
+import com.its.vms.dao.mapper.RseSectMapper;
+import com.its.vms.entity.TbRseSect;
+import com.its.vms.entity.TbRseSectPassHs;
+import com.its.vms.entity.TbRseSectTraf;
+import com.its.vms.global.AppRepository;
+import com.its.vms.process.DbmsData;
+import com.its.vms.process.DbmsDataProcess;
+import com.its.vms.process.DbmsDataType;
+import com.its.vms.dto.voDsrcObuPassInfo;
+import lombok.Getter;
+import lombok.RequiredArgsConstructor;
+import lombok.extern.slf4j.Slf4j;
+import org.apache.commons.lang3.time.FastDateFormat;
+import org.springframework.stereotype.Service;
+import org.springframework.transaction.annotation.Transactional;
+
+import javax.annotation.PostConstruct;
+import java.text.ParseException;
+import java.util.*;
+import java.util.concurrent.ConcurrentHashMap;
+
+@Slf4j
+@Getter
+@RequiredArgsConstructor
+@Service
+@Transactional(rollbackFor = {Exception.class})
+public class RseSectService {
+
+    private RseSectMapper rseSectMapper;
+    private final CommunicationConfig communicationConfig;
+    private final DbmsDataProcess dbmsDataProcess;
+
+    // OBU DSRC 차량통과정보, { SECT_ID, [OBU_ID/passinfo, OBU_ID/passinfo, ...] }
+    private Map<String, Map<String, voDsrcObuPassInfo>> dsrcObuPassMap = null;
+    // OBU Travel Time History, { SECT_ID, [seconds/endpasstime, ...] }
+    private Map<String, SortedMap<Integer, String>> travelTimeHistoryMap = null;
+
+    @PostConstruct
+    private void init() {
+        log.info("RseSectService.init: Start.");
+        this.rseSectMapper = (RseSectMapper) AppUtils.getBean(RseSectMapper.class);
+        //this.dbmsJobProcess = (DbmsJobProcess) AppUtils.getBean(DbmsJobProcess.class);
+        this.dsrcObuPassMap = Collections.synchronizedMap(new ConcurrentHashMap<>());
+        this.travelTimeHistoryMap = Collections.synchronizedMap(new ConcurrentHashMap<>());
+        //loadMaster();
+        log.info("RseSectService.init: ..End.");
+    }
+
+    public void loadMaster() {
+        try {
+            List<TbRseSect> objList = this.rseSectMapper.selectRseSectAll();
+            log.info("RseSectService.selectAll(), {} EA", objList.size());
+            //RseRepository.getInstance().dsrcSectMap.clear();
+            for (TbRseSect obj : objList) {
+                AppRepository.getInstance().rseSectMap.put(obj.getRSE_SECT_ID(), obj);
+            }
+            setDsrcSectStartMap(objList);
+            setDsrcSectEndMap(objList);
+        }
+        catch (Exception e) {
+            log.error("dsrcCtlrMap.selectAll: {}", e);
+        }
+
+        // DSRC 통과 정보 저장 맵을 초기화한다.
+        initDsrcObuPassMap();
+
+        for (Map.Entry<String, TbRseSect> obj : AppRepository.getInstance().rseSectMap.entrySet()) {
+            log.info(obj.toString());
+        }
+    }
+
+    public void setDsrcSectStartMap(List<TbRseSect> dsrcSectList) {
+        if (AppRepository.getInstance().rseSectStartMap == null) {
+            log.error("setDsrcSectStartMap: DsrcRepository.getInstance().dsrcSectStartMap is NULL");
+            return;
+        }
+        if (dsrcSectList == null) {
+            log.error("setDsrcSectStartMap: dsrcSectList is NULL");
+            return;
+        }
+
+        AppRepository.getInstance().rseSectStartMap.clear();
+        for (TbRseSect vo : dsrcSectList) {
+            String startDsrcId = vo.getSTRT_ID();
+            String sectId = vo.getRSE_SECT_ID();
+            AppRepository.getInstance().rseSectStartMap.put(startDsrcId, sectId);
+        }
+        log.info("setDsrcSectStartMap: {}", AppRepository.getInstance().rseSectStartMap.toString());
+    }
+
+    public void setDsrcSectEndMap(List<TbRseSect> dsrcSectList) {
+        if (AppRepository.getInstance().rseSectEndMap == null) {
+            log.error("setDsrcSectEndMap: DsrcRepository.getInstance().dsrcSectEndMap is NULL");
+            return;
+        }
+        if (dsrcSectList == null) {
+            log.error("setDsrcSectEndMap: dsrcSectList is NULL");
+            return;
+        }
+
+        AppRepository.getInstance().rseSectEndMap.clear();
+        for (TbRseSect vo : dsrcSectList) {
+            String endDsrcId = vo.getEND_ID();
+            String sectId = vo.getRSE_SECT_ID();
+            AppRepository.getInstance().rseSectEndMap.put(endDsrcId, sectId);
+        }
+        log.info("setDsrcSectEndMap: {}", AppRepository.getInstance().rseSectEndMap.toString());
+    }
+
+    public void initDsrcObuPassMap() {
+
+        this.dsrcObuPassMap.clear();
+        this.travelTimeHistoryMap.clear();
+        String currTime = SysUtils.getSysTime();
+        for (Map.Entry<String, TbRseSect> obj : AppRepository.getInstance().rseSectMap.entrySet()) {
+            //<obuId, passInfo>
+            Map<String, voDsrcObuPassInfo> temp = Collections.synchronizedMap(new ConcurrentHashMap<>());
+            this.dsrcObuPassMap.put(obj.getValue().getRSE_SECT_ID(), temp);
+            SortedMap<Integer, String> temp2 = Collections.synchronizedSortedMap(new TreeMap<>());
+            temp2.put(Integer.valueOf(240), currTime);
+            this.travelTimeHistoryMap.put(obj.getValue().getRSE_SECT_ID(), temp2);
+        }
+    }
+
+     /**
+     * DSRC 구간 소통정보 생성
+     * 스케쥴러에 의해 실행됨, 매 5분 정주기
+     */
+    public void makeDsrcSectTraffic() {
+
+        log.info("makeDsrcSectTraffic: Start...");
+
+        int historyMinute = 0;//this.runningConfig.getFilteringHistoryMinute();
+        float minSpeed = 0.0f;//(float)this.runningConfig.getFilteringMinSpeed();
+        float maxSpeed = 0.0f;//(float)this.runningConfig.getFilteringMaxSpeed();
+        String currentTm = SysUtils.getSysTime();
+
+        // 필터링 초기화(, )OBU 통과 수집 이력 목록 초기화)
+        for (Map.Entry<String, TbRseSect> obj : AppRepository.getInstance().rseSectMap.entrySet()) {
+            String dsrcSectId = obj.getValue().getRSE_SECT_ID();
+            log.debug("makeDsrcSectTraffic: initFiltering, SECT_ID: {}", dsrcSectId);
+
+            initFiltering(dsrcSectId, historyMinute);
+        }
+
+        // OBU 구간 통행정보 목록
+        List<TbRseSectPassHs> sectPassList = Collections.synchronizedList(new ArrayList<>());
+        // 구간 소통정보 목록
+        List<TbRseSectTraf> sectTrafList = Collections.synchronizedList(new ArrayList<>());
+
+        // OBU 구간 통과 목록을 이용하여 교통정보 생성
+        for (String dsrcSectId : this.dsrcObuPassMap.keySet()) {
+            // 구간 ID로 구간정보 조회
+            TbRseSect dsrcSect = AppRepository.getInstance().rseSectMap.get(dsrcSectId);
+            if (dsrcSect == null) {
+                log.error("makeDsrcSectTraffic: SECT_ID: {}, not found", dsrcSectId);
+                continue;
+            }
+
+            log.debug("makeDsrcSectTraffic: SECT_ID: {}", dsrcSectId);
+
+            int distance = 0;
+            int totalCount = 0;
+            int missMatchCount = 0;
+            int totalSeconds = 0;
+            int calcCount = 0;
+            int avgSpeed = 0;
+
+            // 구간 거리 체크
+            distance = dsrcSect.getSECT_LNGT();
+            if (distance <= 0) {
+                log.error("makeDsrcSectTraffic: SECT_ID: {}, distance: {}, distance error", dsrcSectId, distance);
+                continue;
+            }
+
+            // 구간 통과 차량 목록 조회
+            Map<String, voDsrcObuPassInfo> obuPassInfoMap = this.dsrcObuPassMap.get(dsrcSectId);
+            if (obuPassInfoMap == null) {
+                log.warn("makeDsrcSectTraffic: SECT_ID: {}, not found", dsrcSectId);
+                continue;
+            }
+
+            // 전체 통과 차량
+            totalCount = obuPassInfoMap.size();
+            if (totalCount <= 0) {
+                log.error("makeDsrcSectTraffic: SECT_ID: {}, total pass volume zero", dsrcSectId);
+                continue;
+            }
+
+            log.info("makeDsrcSectTraffic: SECT_ID: {}, pass obu: {} EA", dsrcSectId, totalCount);
+
+            // 구간을 통과한 차량목록을 이용하여 구간 소통정보 생성
+            for (String obuId : obuPassInfoMap.keySet()) {
+                try {
+                    voDsrcObuPassInfo dsrcObuPassInfo = obuPassInfoMap.get(obuId);
+                    if (dsrcObuPassInfo == null) {
+                        log.error("makeDsrcSectTraffic: SECT_ID: {}, obuId: {}, sect passing car get error", dsrcSectId, obuId);
+                        missMatchCount++;
+                        continue;
+                    }
+
+                    // 종점 DSRC 를 통과한 시각이 없으면 맷칭이 안된것임
+                    if (dsrcObuPassInfo.getEndDsrcPassTm() == null) {
+                        missMatchCount++;
+                        if (dsrcObuPassInfo.getStartDsrcPassTm() != null) {
+                            // 시점 통과시각과 현재시각이 기준값 이상 차이나면 리스트에서 삭제
+                            if (gapTime(dsrcObuPassInfo.getStartDsrcPassTm(), currentTm, Calendar.MINUTE) > historyMinute) {
+                                log.error("makeDsrcSectTraffic: Miss Matching, Old Pass Info delete: sect[{}], obu[{}]", dsrcSectId, dsrcObuPassInfo.toString());
+                                this.dsrcObuPassMap.get(dsrcSectId).remove(obuId);
+                            }
+                        }
+                        //log.error("makeDsrcSectTraffic: SECT_ID: {}, obuId: {}, end dsrc pass time null", dsrcSectId, obuId);
+                        continue;   // 종료시각이 없으므로 사용하지 않음
+                    }
+
+                    // 시점 DSRC 를 통과한 시각이 없으면 DSRC 통과시 정보를 수집 못한것임(리스트에서 삭제)
+                    if (dsrcObuPassInfo.getStartDsrcPassTm() == null) {
+                        missMatchCount++;
+                        this.dsrcObuPassMap.get(dsrcSectId).remove(obuId);
+                        //log.error("makeDsrcSectTraffic: SECT_ID: {}, obuId: {}, start dsrc pass time null", dsrcSectId, obuId);
+                        continue;   // 이상 수집정보로 사용하지 않음
+                    }
+
+                    // 시점 및 종점 통과시각이 존재하는 경우 소통정보에 사용
+                    int passSeconds = gapTime(dsrcObuPassInfo.getStartDsrcPassTm(), dsrcObuPassInfo.getEndDsrcPassTm(), Calendar.SECOND);
+                    if (passSeconds <= 0) {
+                        // 구간 운행시각이 이상일 경우 목록에서 삭제
+                        missMatchCount++;
+                        this.dsrcObuPassMap.get(dsrcSectId).remove(obuId);
+                        log.error("makeDsrcSectTraffic: SECT_ID: {}, obuId: {}, start/end passSeconds error: {} sec.", dsrcSectId, obuId, passSeconds);
+                        continue;   // 사용하지 않음
+                    }
+
+                    // 통행속도 계산(최소/최대 속도값 확인)
+                    float speed = (float)((distance * 3600) / (passSeconds * 1000L));
+                    if (minSpeed > speed || maxSpeed < speed) {
+                        missMatchCount++;
+                        this.dsrcObuPassMap.get(dsrcSectId).remove(obuId);
+                        log.error("makeDsrcSectTraffic: SECT_ID: {}, obuId: {}, calc speed error: spd: {}, min: {}, max: {}.", dsrcSectId, obuId, speed, minSpeed, maxSpeed);
+                        continue;
+                    }
+
+                    if (!doFiltering(dsrcSectId, passSeconds, dsrcObuPassInfo.getEndDsrcPassTm(), obuId)) {
+                        missMatchCount++;
+                        this.dsrcObuPassMap.get(dsrcSectId).remove(obuId);
+                        //log.error("makeDsrcSectTraffic: SECT_ID: {}, obuId: {}, doFiltering failed.", dsrcSectId, obuId);
+                        continue;
+                    }
+
+                    totalSeconds = (totalSeconds + passSeconds);
+                    calcCount++;
+
+                    // 처리된 통과정보를 목록에서 삭제
+                    this.dsrcObuPassMap.get(dsrcSectId).remove(obuId);
+
+                    // OBU 구간 통행 정보를 저장
+                    TbRseSectPassHs passVo = new TbRseSectPassHs();
+                    passVo.setRSE_SECT_ID(dsrcSectId);
+                    passVo.setCRTN_DT(currentTm);
+                    passVo.setOBU_IDNT_NMBR(obuId);
+                    passVo.setSTRT_SPOT_PASS_DT(dsrcObuPassInfo.getStartDsrcPassTm());
+                    passVo.setEND_SPOT_PASS_DT(dsrcObuPassInfo.getEndDsrcPassTm());
+                    sectPassList.add(passVo);
+                    log.info("makeDsrcSectTraffic: SECT_ID: {}, obuId: {}, totalSeconds: {}, calcCount: {}, passSeconds: {}.", dsrcSectId, obuId, totalSeconds, calcCount, passSeconds);
+                }
+                catch(Exception e) {
+                    missMatchCount++;
+                    this.dsrcObuPassMap.get(dsrcSectId).remove(obuId);
+                    log.error("makeDsrcSectTraffic: SECT_ID: {}, obuId: {}, Exception: {}.", dsrcSectId, obuId, e.toString());
+                }
+            } // 구간 통과 차량 목록
+
+            if (totalCount <= missMatchCount) {
+                log.error("makeDsrcSectTraffic: SECT_ID: {}, make traffic error, total: {} EA, missMatchCount: {} EA.", dsrcSectId, totalCount, missMatchCount);
+                continue;
+            }
+
+            // 구간을 통과한 모든 OBU를 이용하여 소통정보 생성
+            int matchedCount = totalCount - missMatchCount;
+            int trvlSeconds = totalSeconds / matchedCount;
+            if (matchedCount <= 0) {
+                continue;   // 여기들어올일은 없음....
+            }
+            try {
+                float fSpeed = (float)((distance*3600) / (trvlSeconds*1000L));
+                avgSpeed = Math.round(fSpeed);
+            }
+            catch(Exception e) {
+                log.error("makeDsrcSectTraffic: SECT_ID: {}, calc speed, Exception: {}.", dsrcSectId, e.toString());
+                continue;
+            }
+
+            // 구간 소통정보 저장
+            TbRseSectTraf sectTraf = new TbRseSectTraf();
+            sectTraf.setRSE_SECT_ID(dsrcSectId);
+            sectTraf.setPRCN_DT(currentTm);
+            sectTraf.setTFVL(matchedCount);
+            sectTraf.setTRVL_SPED(avgSpeed);
+            sectTraf.setTRVL_HH(trvlSeconds);
+            sectTrafList.add(sectTraf);
+
+            log.info("makeDsrcSectTraffic: SECT_ID: {}, make traffic: {}", dsrcSectId, sectTraf.toString());
+        } // 구간 목록
+
+        // 구간소통정보 목록을 데이터베이스에 저장
+        if (sectTrafList.size() > 0) {
+            this.dbmsDataProcess.add(new DbmsData(DbmsDataType.DBMS_DATA_SECT_TRAF_HS, false, sectTrafList));
+        }
+
+        // OBU 구간 통행 정보를 데이터베이스에 저장
+        if (sectPassList.size() > 0) {
+            this.dbmsDataProcess.add(new DbmsData(DbmsDataType.DBMS_DATA_SECT_PASS_HS, false, sectPassList));
+        }
+
+        log.info("makeDsrcSectTraffic: End.....");
+    }
+
+    /**
+     * 사분위편차를 활용하여 이상치를 제거한다.
+     * 사분위편차 및 관리도 모형에 의한 GPS 수집기반 구간통행속도 데이터 이상치 제거방안 연구, 한국ITS학회논문지, 제7권, 제6호 (2008년 12월)
+     *
+     * 관측값을 순서대로 정렬한 후
+     * 25% 위치한 값을 1사분위수(Q1)
+     * 75% 위치한 값을 3사분위수(Q3)
+     * 3사분위수와 1사분위수의 차이를 사분위편차(IQR)
+     * 이상치제거: 1사분위수에서 사분위편차의 1.5배만큼을 뺀 값보다 작거나 3사분위수에서 사분위편차의 1.5배만큼을 더한 값보다 큰 값을 이상치로 판단함
+     * 하한 기준값 : Q1 – 1.5ⅹIQR
+     * 상한 기준값 : Q3 + 1.5ⅹIQR
+     */
+    boolean doFiltering(String dsrcSectId, int travelSeconds, String endDateTime, String obuId) {
+        SortedMap<Integer, String> travelHistoryMap = this.travelTimeHistoryMap.get(dsrcSectId);
+        List<Integer> list = Collections.synchronizedList(new ArrayList<>());
+
+        Iterator<Integer> it = travelHistoryMap.keySet().iterator();
+        while (it.hasNext()) {
+            try {
+                int travelTime = ((Integer) it.next()).intValue();
+                if (travelTime > 0)
+                {
+                    list.add(travelTime);
+                }
+            }
+            catch(Exception e) {
+                log.error("doFiltering: dsrcSectId: {}, {}", dsrcSectId, e.toString());
+            }
+        }
+
+        int size = list.size();
+        if (size < 3) {
+            this.travelTimeHistoryMap.get(dsrcSectId).put(travelSeconds, endDateTime);
+            log.warn("doFiltering: failed, ==> list size small: {} EA. SECT_ID: {}, obuId: {}", size, dsrcSectId, obuId);
+            return false;
+        }
+
+        int Q1Index = (int)(size * (1.0F / 4.0F));  // 1사분위 인덱스
+        int Q3Index = (int)(size * (3.0F / 4.0F));  // 3사분위 인덱스
+
+        int Q1 = list.get(Q1Index).intValue();      // 1사분위 값
+        int Q3 = list.get(Q3Index).intValue();      // 3사분위 값
+        int IQR = Math.abs(Q3 - Q1);
+        double lowerBoundD = Q1 - 1.5D * IQR;
+        double upperBoundD = Q3 + 1.5D * IQR;
+
+        if (lowerBoundD <= 0.0D)
+            lowerBoundD = 0;
+
+        long lowerBound = Math.round(lowerBoundD);
+        long upperBound = Math.round(upperBoundD);
+
+        this.travelTimeHistoryMap.get(dsrcSectId).put(Integer.valueOf(travelSeconds), endDateTime);
+
+        log.debug("doFiltering: Q1: {}, Q3: {}, IQR: {}, travelSeconds: {}, LOWER: {}, UPPER: {}",
+                Integer.valueOf(Q1), Integer.valueOf(Q3), Integer.valueOf(IQR), Integer.valueOf(travelSeconds), Long.valueOf(lowerBound), Long.valueOf(upperBound));
+
+        if (travelSeconds >= lowerBound && travelSeconds <= upperBound) {
+            return true;
+        }
+        return false;
+    }
+
+    /**
+     * 필터링(이상치제거)를 수행하기 전에 이상치제거 초기화 작업을 수행한다.
+     * OBU 통행 이력 맵에서 가공시각 이전 수집된 정보를 모두 삭제한다.
+     */
+    void initFiltering(String dsrcSectId, int historyMinute) {
+        SortedMap<Integer, String> travelHistoryMap = this.travelTimeHistoryMap.get(dsrcSectId);
+        SortedMap<Integer, String> tempMap = Collections.synchronizedSortedMap(new TreeMap<>());
+        tempMap.putAll(travelHistoryMap);
+
+        String currentTime = SysUtils.getSysTime();
+        Iterator<Integer> it = tempMap.keySet().iterator();
+        while (it.hasNext()) {
+            try {
+                int travelTime = ((Integer) it.next()).intValue();
+                if (travelTime == 0)
+                    continue;
+
+                String endDateTime = tempMap.get(Integer.valueOf(travelTime));
+                if (endDateTime == null || endDateTime.equals(""))
+                    continue;
+
+                if (gapTime(endDateTime, currentTime, Calendar.MINUTE) > historyMinute) {
+                    // 기준시간 이상 된 이력정보를 리스트에서 삭제
+                    this.travelTimeHistoryMap.get(dsrcSectId).remove(Integer.valueOf(travelTime));
+                }
+            }
+            catch(Exception e) {
+                log.error("initFiltering: dsrcSectId: {}, {}", dsrcSectId, e.toString());
+            }
+        }
+    }
+
+    public int gapTime(String startTm, String endTm, int calcType) {
+
+        if (startTm == null || startTm.equals("") || startTm.length() != 14) {
+            return -1;
+        }
+        if (endTm == null || endTm.equals("") || endTm.length() != 14) {
+            return -1;
+        }
+
+        FastDateFormat fastDateFormat = FastDateFormat.getInstance("yyyyMMddHHmmss", new Locale("ko_KR")); //Locale.getDefault());
+
+        Date startDateTime, endDateTime;
+        try {
+            startDateTime = fastDateFormat.parse(startTm);
+            endDateTime = fastDateFormat.parse(endTm);
+        } catch (ParseException e) {
+            e.printStackTrace();
+            return -1;
+        }
+
+        GregorianCalendar gcStartDateTime = new GregorianCalendar();
+        GregorianCalendar gcEndDateTime = new GregorianCalendar();
+        gcStartDateTime.setTime(startDateTime);
+        gcEndDateTime.setTime(endDateTime);
+
+        long gap = gcEndDateTime.getTimeInMillis() - gcStartDateTime.getTimeInMillis();
+        long hour = gap / 1000L / 60L / 60L;
+        long min = gap / 1000L / 60L;
+        long second = gap / 1000L;
+        if (Calendar.HOUR == calcType)
+            return (int)hour;
+        if (Calendar.MINUTE == calcType)
+            return (int)min;
+        if (Calendar.SECOND == calcType)
+            return (int)second;
+        return -1;
+    }
+
+}

+ 98 - 0
src/main/java/com/its/vms/service/StatisticsServices.java

@@ -0,0 +1,98 @@
+package com.its.vms.service;
+
+import com.its.app.AppUtils;
+import com.its.app.utils.Elapsed;
+import com.its.app.utils.TimeUtils;
+import com.its.vms.dao.mapper.RseStatMapper;
+import com.its.vms.dto.voStatisticsTime;
+import lombok.extern.slf4j.Slf4j;
+import org.slf4j.MDC;
+import org.springframework.scheduling.annotation.Async;
+import org.springframework.stereotype.Service;
+import org.springframework.transaction.annotation.Transactional;
+
+import javax.annotation.PostConstruct;
+import javax.annotation.PreDestroy;
+import java.util.Calendar;
+import java.util.Date;
+
+@Slf4j
+@Service
+@Transactional(rollbackFor = {Exception.class})
+public class StatisticsServices {
+
+    private RseStatMapper statMapper;
+    private final String logKey = "statistics";
+
+    @PostConstruct
+    private void init() {
+        this.statMapper = (RseStatMapper) AppUtils.getBean(RseStatMapper.class);
+    }
+
+    @PreDestroy
+    public void destroyService() {
+    }
+
+    @Async("statisticsExecutor")
+    public void CRT_TB_RSE_OBU_CLCT_STAT_HH(String statDt, String fromDt, String toDt) {
+        MDC.put("id", logKey);
+        Elapsed elapsed = new Elapsed();
+        voStatisticsTime statTime = new voStatisticsTime(statDt, fromDt, toDt);
+        log.info("CRT_RSE_OBU_CLCT_STAT_HH: start. [{}], {}", statTime, Thread.currentThread().getName());
+        this.statMapper.CRT_TB_RSE_OBU_CLCT_STAT_HH(statTime);
+        log.info("CRT_RSE_OBU_CLCT_STAT_HH: ..end. [{}], {} ms. {}", statTime, elapsed.milliSeconds(), Thread.currentThread().getName());
+        MDC.remove(logKey);
+        MDC.clear();
+    }
+
+    @Async("statisticsExecutor")
+    public void CRT_TB_RSE_OBU_CLCT_STAT_DD(String statDt, String fromDt, String toDt) {
+        MDC.put("id", logKey);
+        Elapsed elapsed = new Elapsed();
+        voStatisticsTime statTime = new voStatisticsTime(statDt, fromDt, toDt);
+        log.info("CRT_RSE_OBU_CLCT_STAT_DD: start. [{}], {}", statTime, Thread.currentThread().getName());
+        this.statMapper.CRT_TB_RSE_OBU_CLCT_STAT_DD(statTime);
+        log.info("CRT_RSE_OBU_CLCT_STAT_DD: ..end. [{}], {} ms. {}", statTime, elapsed.milliSeconds(), Thread.currentThread().getName());
+        MDC.remove(logKey);
+        MDC.clear();
+    }
+
+    public static int getDayWeek(Date paramDt) {
+        Calendar cal = Calendar.getInstance();
+        cal.setTime(paramDt);
+        return cal.get(Calendar.DAY_OF_WEEK);		/* DAY_OF_WEEK 리턴값이 일요일(1), 월요일(2), 화요일(3) ~~ 토요일(7)을 반환합니다. */
+    }
+
+    public String getDayWeekCd(int week) {
+        String sWeek = "DTW0";
+        switch(week) {
+            case 1: sWeek = "DTW7";	break;
+            case 2: sWeek = "DTW1";	break;
+            case 3: sWeek = "DTW2";	break;
+            case 4: sWeek = "DTW3";	break;
+            case 5: sWeek = "DTW4";	break;
+            case 6: sWeek = "DTW5";	break;
+            case 7: sWeek = "DTW6"; break;
+        }
+        return sWeek;
+    }
+
+    @Async("statisticsExecutor")
+    public void CRT_TB_RSE_OD_STAT_HH(String statDt, String fromDt, String toDt) {
+        MDC.put("id", logKey);
+        Elapsed elapsed = new Elapsed();
+        Date dtStat = TimeUtils.stringToDate(statDt);
+        String weekCd = getDayWeekCd(getDayWeek(dtStat));
+        voStatisticsTime statTime = new voStatisticsTime(statDt, fromDt, toDt);
+        statTime.setDAY_TYPE_CD(weekCd);
+        statTime.setB_FROM_DT(TimeUtils.getTime(dtStat, TimeUtils.TYPE_PRCS_30MIN));
+        statTime.setB_TO_DT(TimeUtils.getToTime(statTime.getB_FROM_DT(), TimeUtils.TYPE_PRCS_30MIN));
+        //log.info("{}", statTime);
+        log.info("------CRT_RSE_OD_STAT_HH: start. [{}], {}", statTime, Thread.currentThread().getName());
+        this.statMapper.CRT_TB_RSE_OD_STAT_HH(statTime);
+        log.info("------CRT_RSE_OD_STAT_HH: ..end. [{}], {} ms. {}", statTime, elapsed.milliSeconds(), Thread.currentThread().getName());
+        MDC.remove(logKey);
+        MDC.clear();
+    }
+
+}

+ 132 - 0
src/main/java/com/its/vms/service/UnitSystService.java

@@ -0,0 +1,132 @@
+package com.its.vms.service;
+
+import com.its.app.AppUtils;
+import com.its.app.utils.SysUtils;
+import com.its.vms.config.ApplicationConfig;
+import com.its.vms.dao.mapper.UnitSystMapper;
+import com.its.vms.entity.TbUnitSyst;
+import com.its.vms.entity.TbUnitSystStts;
+import com.its.vms.process.DbmsData;
+import com.its.vms.process.DbmsDataProcess;
+import com.its.vms.process.DbmsDataType;
+import lombok.Getter;
+import lombok.RequiredArgsConstructor;
+import lombok.extern.slf4j.Slf4j;
+import org.slf4j.MDC;
+import org.springframework.stereotype.Service;
+import org.springframework.transaction.annotation.Transactional;
+
+import javax.annotation.PostConstruct;
+import javax.annotation.PreDestroy;
+import java.net.InetAddress;
+import java.net.UnknownHostException;
+import java.util.Calendar;
+import java.util.List;
+import java.util.Map;
+import java.util.concurrent.ConcurrentHashMap;
+
+@Slf4j
+@Getter
+@Service
+@RequiredArgsConstructor
+@Transactional(rollbackFor = {Exception.class})
+public class UnitSystService {
+
+    private final DbmsDataProcess dbmsDataProcess;
+    private final UnitSystMapper unitSystMapper;
+    private final ConcurrentHashMap<String, TbUnitSyst> unitSystMap = new ConcurrentHashMap<>();
+    private final TbUnitSystStts unitSystStts = TbUnitSystStts.builder().build();
+
+    private String processId;
+    private int historyMin;
+    public static String _srcIpAddr;
+
+    @PostConstruct
+    private void init() {
+        log.info("UnitSystService.init: start.");
+        ApplicationConfig applicationConfig = (ApplicationConfig) AppUtils.getBean(ApplicationConfig.class);
+        this.processId = applicationConfig.getId();
+        this.historyMin = -1;
+
+        try {
+            InetAddress local = InetAddress.getLocalHost();
+            String localIp = local.getHostAddress();
+            long ipAddr = SysUtils.ipToLong(localIp);
+            UnitSystService._srcIpAddr = String.format("%03d.%03d.%03d.%03d-", (ipAddr>>24)&0xFF, (ipAddr>>16)&0xFF, (ipAddr>>8)&0xFF, (ipAddr)&0xFF);
+        } catch (UnknownHostException e) {
+            UnitSystService._srcIpAddr = "127.000.000.001-";
+            log.error("UnitSystService.init: UnknownHostException");
+        }
+
+        log.info("UnitSystService.init. _srcIpAddr: {}", UnitSystService._srcIpAddr);
+        log.info("UnitSystService.init. processId: {}", this.processId);
+        log.info("UnitSystService.init: ..end.");
+    }
+
+    @PreDestroy
+    public void destroyService() {
+        log.error("UnitSystService.destroy. system terminated.......");
+        updateUnitSystStts(false);
+    }
+
+    public void loadMaster() {
+        try {
+            // 초기화, 기존 정보 삭제로 초기화
+            for (Map.Entry<String, TbUnitSyst> e : this.unitSystMap.entrySet()) {
+                e.getValue().setDelYn("Y");
+            }
+
+            List<TbUnitSyst> systList = this.unitSystMapper.selectAll();
+            log.info("UnitSystService.selectAll(), {} EA", systList.size());
+            for (TbUnitSyst unit : systList) {
+                if (unit.getSystId().equals(this.processId)) {
+                    this.unitSystStts.setSYST_ID(this.processId);
+                    String localIp = unit.getSystIp1().trim();
+                    long ipAddr = SysUtils.ipToLong(localIp);
+                    UnitSystService._srcIpAddr = String.format("%03d.%03d.%03d.%03d-", (ipAddr>>24)&0xFF, (ipAddr>>16)&0xFF, (ipAddr>>8)&0xFF, (ipAddr>>0)&0xFF);
+                    log.info("UnitSystService.loadMaster: _srcIpAddr: {}", UnitSystService._srcIpAddr);
+                }
+
+                if (unit.getSystType().contentEquals("UOT")) {
+                    unit.setSystIp1(unit.getSystIp1().trim());
+                    this.unitSystMap.put(unit.getSystId(), unit);
+                }
+            }
+        }
+        catch (Exception e) {
+            log.error("UnitSystService.selectAll: Exception: {}", e.toString());
+        }
+    }
+
+    public void updateUnitSystStts(boolean isRun) {
+        String keyData = "unit";
+        MDC.put("id", keyData);
+        boolean insHs = false;
+        Calendar cal = Calendar.getInstance();
+        int min = cal.get(Calendar.MINUTE);
+        if ((min % 5) == 0 && this.historyMin != min) {
+            insHs = true;
+            this.historyMin = min;
+        }
+
+        String SYST_STTS_CD = isRun ? "SPS1" : "SPS3";
+        this.unitSystStts.setSYST_ID(this.processId);
+        this.unitSystStts.setUPDT_DT(SysUtils.getSysTime());
+        this.unitSystStts.setSYST_STTS_CD(SYST_STTS_CD);
+
+        if (!isRun) {
+           this.unitSystMapper.updateUnitSystStts(this.unitSystStts);
+            if (insHs) {
+                this.unitSystMapper.insertUnitSystSttsHs(this.unitSystStts);
+            }
+        }
+        else {
+            this.dbmsDataProcess.add(new DbmsData(DbmsDataType.DBMS_DATA_UNIT_SYST_STTS, insHs, this.unitSystStts));
+            if (insHs) {
+                loadMaster();
+            }
+        }
+        MDC.remove(keyData);
+        MDC.clear();
+    }
+}

+ 85 - 0
src/main/java/com/its/vms/service/VmsAtmpService.java

@@ -0,0 +1,85 @@
+package com.its.vms.service;
+
+import com.its.vms.config.ApplicationConfig;
+import com.its.vms.dao.mapper.VmsAtmpMapper;
+import com.its.vms.dto.TbVmsAtmpDto;
+import com.its.vms.entity.TbVmsAtmp;
+import lombok.RequiredArgsConstructor;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.stereotype.Service;
+
+import java.util.List;
+import java.util.Map;
+import java.util.concurrent.ConcurrentHashMap;
+import java.util.concurrent.atomic.AtomicInteger;
+
+@Slf4j
+@Service
+@RequiredArgsConstructor
+public class VmsAtmpService {
+
+    private final ApplicationConfig config;
+    private final VmsAtmpMapper vmsAtmpMapper;
+
+    public ConcurrentHashMap<Long, TbVmsAtmp> atmpMap = new ConcurrentHashMap<>();
+
+    public void loadAtmpInfo() {
+        loadVmsAtmpInfo();
+    }
+
+    public void loadVmsAtmpInfo() {
+        AtomicInteger nFailed = new AtomicInteger();
+        AtomicInteger nSuccess = new AtomicInteger();
+        try {
+            List<TbVmsAtmpDto> infoList  = this.vmsAtmpMapper.selectVmsAtmpInfo();
+            log.info("VmsAtmpService.loadVmsAtmpInfo(), {} EA", infoList.size());
+            infoList.forEach(dto -> {
+                TbVmsAtmp obj = dto.toEntity();
+                this.atmpMap.put(obj.getAtmpSttnNmbr(), obj);
+                if (obj.getMsrmDt() == null) {
+                    obj.setSuccess(false);
+                    nFailed.getAndIncrement();
+                    return;
+                }
+                if ("0".equals(obj.getPm101hhGrad()) &&
+                    "0".equals(obj.getPm251hhGrad()) &&
+                    "0".equals(obj.getIntgAtmpGrad())) {
+                    obj.setSuccess(false);
+                    nFailed.getAndIncrement();
+                    return;
+                }
+                log.error("{}", obj);
+                nSuccess.getAndIncrement();
+            });
+        }
+        catch (Exception e) {
+            log.error("VmsAtmpService.loadVmsAtmpInfo: {}", e.toString());
+        }
+
+        if (nFailed.intValue() > 0 && nSuccess.intValue() > 0) {
+            // 성공 데이터가 존재하고 실패 데이터가 존재하는 경우 데이터 보정
+            correctVmsAtmpInfo();
+        }
+    }
+
+    public void correctVmsAtmpInfo() {
+        /**
+         * 측정 데이터가 없는 경우 정상적인 측정 데이터를 가지고 보정한다.
+         */
+        TbVmsAtmp vmsAtmp = null;
+        for (Map.Entry<Long, TbVmsAtmp > obj : this.atmpMap.entrySet()) {
+            if (obj.getValue().isSuccess()) {
+                vmsAtmp = obj.getValue();
+                break;
+            }
+        }
+        if (vmsAtmp == null) {
+            return;
+        }
+        for (Map.Entry<Long, TbVmsAtmp > obj : this.atmpMap.entrySet()) {
+            if (!obj.getValue().isSuccess()) {
+                vmsAtmp.correct(obj.getValue());
+            }
+        }
+    }
+}

+ 160 - 0
src/main/java/com/its/vms/service/VmsCtlrService.java

@@ -0,0 +1,160 @@
+package com.its.vms.service;
+
+import com.its.app.AppUtils;
+import com.its.app.utils.SysUtils;
+import com.its.vms.config.ApplicationConfig;
+import com.its.vms.dao.mapper.VmsCtlrMapper;
+import com.its.vms.dto.NET;
+import com.its.vms.dto.TbVmsCtlrDto;
+import com.its.vms.dto.TbVmsCtlrSttsDto;
+import com.its.vms.entity.TbVmsCtlr;
+import com.its.vms.global.AppRepository;
+import com.its.vms.process.DbmsData;
+import com.its.vms.process.DbmsDataProcess;
+import com.its.vms.process.DbmsDataType;
+import lombok.RequiredArgsConstructor;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.stereotype.Service;
+import org.springframework.transaction.annotation.Transactional;
+
+import javax.annotation.PostConstruct;
+import java.io.File;
+import java.util.*;
+
+@Slf4j
+@Service
+@RequiredArgsConstructor
+@Transactional(rollbackFor = {Exception.class})
+public class VmsCtlrService {
+
+    private final ApplicationConfig config;
+    private final VmsCtlrMapper vmsCtlrMapper;
+    private int historyMin;
+
+    @PostConstruct
+    private void init() {
+        log.info("VmsCtlrService.init: Start.");
+        this.historyMin = -1;
+        log.info("VmsCtlrService.init: ..End.");
+    }
+
+    public void loadDb() {
+        loadCtlrInfo();
+    }
+
+    public void initCtlrInfo() {
+        try {
+            for (Map.Entry<Long, TbVmsCtlr> e : AppRepository.getInstance().getCtlrMap().entrySet()) {
+                TbVmsCtlr obj = e.getValue();
+                obj.setDelYn("Y");
+            }
+        }
+        catch (Exception e) {
+            log.error("VmsCtlrService.initCtlrInfo: Exception: {}", e.toString());
+        }
+    }
+
+    public void loadCtlrInfo() {
+        initCtlrInfo();
+        try {
+            List<TbVmsCtlrDto> infoList  = this.vmsCtlrMapper.selectAll();
+            log.info("VmsCtlrService.loadCtlrInfo(), {} EA", infoList.size());
+            for (TbVmsCtlrDto dto : infoList) {
+                log.info("VmsCtlrService.loadCtlrInfo: {}", dto);
+                TbVmsCtlr obj = dto.toEntity();
+                if (obj.getCtlrId().trim().equals("")) {
+                    log.error("VmsCtlrService.loadCtlrInfo: Controller Ip Address Error: {}", obj);
+                    continue;
+                }
+
+                AppRepository.getInstance().getCtlrMap().put(obj.getCtlrNmbr(), obj);
+                AppRepository.getInstance().getCtlrIpMap().put(obj.getCtlrIp(), obj);
+                obj.getStts().initUnknown();
+
+                obj.setLocalFormDir(this.config.getFtpFormDir() + File.separator + obj.getCtlrNmbr());
+                obj.setFtpFormDir(ApplicationConfig.FTP_FORM + File.separator + obj.getCtlrNmbr() + File.separator);
+                obj.setFtpDownload(true);
+
+                this.config.makeDirectory(obj.getLocalFormDir(), "VMS " + obj.getCtlrNmbr() + " Directory.");
+            }
+        }
+        catch (Exception e) {
+            log.error("VmsCtlrService.loadCtlrInfo: {}", e.toString());
+        }
+
+        for (Map.Entry<Long, TbVmsCtlr> obj : AppRepository.getInstance().getCtlrMap().entrySet()) {
+            log.info("VmsCtlrService.VmsCtlr: {}", obj.toString());
+        }
+    }
+
+    public void updateCtlrStts(boolean isRun, TbVmsCtlr AObj) {
+        boolean insHs = false;
+        Calendar cal = Calendar.getInstance();
+        int min = cal.get(Calendar.MINUTE);
+        if ((min % 5) == 0 && this.historyMin != min) {
+            insHs = true;
+            this.historyMin = min;
+        }
+
+        //제어기 상태정보 업데이트
+        List<TbVmsCtlrSttsDto> ctlrSttsList = Collections.synchronizedList(new ArrayList<>());
+        String UPDT_DT = SysUtils.getSysTime();
+        int normal = 0;
+        int error  = 0;
+        for (Map.Entry<Long, TbVmsCtlr> e : AppRepository.getInstance().getCtlrMap().entrySet()) {
+            TbVmsCtlr obj = e.getValue();
+            if (AObj != null && AObj.getCtlrNmbr() != obj.getCtlrNmbr()) {
+                continue;
+            }
+
+            obj.getStts().setUpdtDt(UPDT_DT);
+
+            if (isRun && obj.getNetState() >= NET.LOGINED && obj.getChannel() != null) {
+                //제어기 통신정상
+                normal++;
+                obj.getStts().setCmncSttsCd("CMS0");
+                obj.getStts().setCommSttsCd("CMS0");
+            }
+            else {
+                //제어기 통신이상
+                error++;
+                obj.getStts().initError();
+            }
+
+            if (isRun) {
+                ctlrSttsList.add(obj.getStts());
+            }
+            else {
+                this.vmsCtlrMapper.updateCtlrStts(obj.getStts());
+                if (insHs) {
+                    this.vmsCtlrMapper.insertCtlrSttsHs(obj.getStts());
+                }
+            }
+        }
+
+        // 제어기 상태정보 DB 업데이트
+        if (!ctlrSttsList.isEmpty()) {
+            DbmsDataProcess dbmsDataProcess = (DbmsDataProcess) AppUtils.getBean(DbmsDataProcess.class);
+            dbmsDataProcess.add(new DbmsData(DbmsDataType.DBMS_DATA_CTLR_STTS_LIST, insHs, ctlrSttsList));
+        }
+
+        log.info("VmsCtlrService.updateCtlrStts: total {}, normal {}, error {}", normal + error, normal, error);
+    }
+
+    public void monitoringSession() {
+        long currMilliSeconds = System.currentTimeMillis();
+        for (Map.Entry<Long, TbVmsCtlr> e : AppRepository.getInstance().getCtlrMap().entrySet()) {
+            TbVmsCtlr obj = e.getValue();
+//            if (obj.getNetState() >= NET.LOGIN_REQ && obj.getChannel() != null) {
+//                // 주차정보시스템 통신정상
+//                long recvTimout = currMilliSeconds - obj.getLastRecvTime();
+//                if (recvTimout > 15*1000) {
+//                    log.error("VmsCtlrService.monitoringSession: Idle timeout: {}, ipAddr={}, Idle={} sec.", obj.getID(), obj.getRSE_ID(), (int)(recvTimout/1000L));
+//                    obj.setLastRecvTime();
+//                    obj.sendFrED();
+//                }
+//
+//            }
+        }
+    }
+}

+ 58 - 0
src/main/java/com/its/vms/service/VmsFontService.java

@@ -0,0 +1,58 @@
+package com.its.vms.service;
+
+import com.its.vms.dao.mapper.VmsFontMapper;
+import com.its.vms.dto.TbVmsFontColrDto;
+import com.its.vms.dto.TbVmsFontNameDto;
+import com.its.vms.entity.TbVmsFontColr;
+import com.its.vms.entity.TbVmsFontName;
+import lombok.RequiredArgsConstructor;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.stereotype.Service;
+
+import java.util.List;
+import java.util.concurrent.ConcurrentHashMap;
+
+@Slf4j
+@Service
+@RequiredArgsConstructor
+public class VmsFontService {
+
+    private final VmsFontMapper vmsFontMapper;
+
+    public ConcurrentHashMap<Integer, TbVmsFontName> nameMap = new ConcurrentHashMap<>();
+    public ConcurrentHashMap<Integer, TbVmsFontColr> colrMap = new ConcurrentHashMap<>();
+
+    public void loadFontInfo() {
+        loadFontNameInfo();
+        loadFontColorInfo();
+    }
+
+    public void loadFontNameInfo() {
+        try {
+            List<TbVmsFontNameDto> infoList  = this.vmsFontMapper.selectFontName();
+            log.info("VmsFontService.loadFontNameInfo(), {} EA", infoList.size());
+            for (TbVmsFontNameDto dto : infoList) {
+                TbVmsFontName obj = dto.toEntity();
+                this.nameMap.put(obj.getVmsFontNameCd(), obj);
+            }
+        }
+        catch (Exception e) {
+            log.error("VmsFontService.loadFontNameInfo: {}", e.toString());
+        }
+    }
+
+    public void loadFontColorInfo() {
+        try {
+            List<TbVmsFontColrDto> infoList  = this.vmsFontMapper.selectFontColr();
+            log.info("VmsFontService.loadFontColorInfo(), {} EA", infoList.size());
+            for (TbVmsFontColrDto dto : infoList) {
+                TbVmsFontColr obj = dto.toEntity();
+                this.colrMap.put(obj.getVmsFontColrCd(), obj);
+            }
+        }
+        catch (Exception e) {
+            log.error("VmsFontService.loadFontColorInfo: {}", e.toString());
+        }
+    }
+
+}

+ 87 - 0
src/main/java/com/its/vms/service/VmsIfscService.java

@@ -0,0 +1,87 @@
+package com.its.vms.service;
+
+import com.its.vms.dao.mapper.VmsIfscMapper;
+import com.its.vms.dto.TbVmsIfscTrafDto;
+import com.its.vms.dto.TbVmsRltnIfscDto;
+import com.its.vms.entity.TbVmsCtlr;
+import com.its.vms.entity.TbVmsIfscTraf;
+import com.its.vms.entity.TbVmsRltnIfsc;
+import com.its.vms.global.AppRepository;
+import lombok.RequiredArgsConstructor;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.stereotype.Service;
+
+import java.util.List;
+import java.util.Objects;
+import java.util.concurrent.ConcurrentHashMap;
+
+@Slf4j
+@Service
+@RequiredArgsConstructor
+public class VmsIfscService {
+
+    private final VmsIfscMapper vmsIfscMapper;
+    private final VmsPrcsService vmsPrcsService;
+
+    public ConcurrentHashMap<Long, TbVmsIfscTraf> trafMap = new ConcurrentHashMap<>();
+
+    public void loadVmsIfscInfo() {
+        loadVmsRltnIfsc();
+        loadVmsIfscTrafInfo();
+    }
+
+    public void loadVmsRltnIfsc() {
+        AppRepository.getInstance().getCtlrMap().forEach((nmbr, obj) -> {
+            obj.getRltnIfscMap().forEach((ifscId, ifsc) -> {
+                ifsc.setUsed(false);
+            });
+        });
+
+        try {
+            List<TbVmsRltnIfscDto> infoList  = this.vmsIfscMapper.selectVmsRltnIfsc();
+            log.info("VmsIfscService.loadVmsRltnIfsc(), {} EA", infoList.size());
+            infoList.forEach(dto -> {
+                TbVmsCtlr vmsObj = AppRepository.getInstance().getCtlrMap().get(dto.getVmsCtlrNmbr());
+                if (vmsObj != null) {
+                    TbVmsRltnIfsc rltnIfsc = vmsObj.getRltnIfscMap().get(dto.getVmsIfscId());
+                    if (rltnIfsc == null) {
+                        rltnIfsc = dto.toEntity();
+                        vmsObj.getRltnIfscMap().put(dto.getVmsIfscId(), rltnIfsc);
+                    }
+                    rltnIfsc.setUsed(true);
+                    if (this.vmsPrcsService.isStaticCycle()) {
+                        boolean cngstCnfmYn = "Y".equals(dto.getCngstCnfmYn());
+                        Integer cngstCnfmSped = dto.getCngstCnfmSped();
+                        if (rltnIfsc.isCngstCnfmYn() != cngstCnfmYn || !Objects.equals(rltnIfsc.getCngstCnfmSped(), cngstCnfmSped)) {
+                            rltnIfsc.setCngstCnt(0);
+                        }
+                    }
+                    dto.rltnIfscCopy(rltnIfsc);
+                }
+            });
+        }
+        catch (Exception e) {
+            log.error("VmsIfscService.loadVmsRltnIfsc: {}", e.toString());
+        }
+    }
+
+    public void loadVmsIfscTrafInfo() {
+        trafMap.forEach((ifscId, ifsc) -> {
+            ifsc.setCmtrGradCd("0");
+            ifsc.setSped(0);
+            ifsc.setTrvlHh(0);
+        });
+
+        try {
+            List<TbVmsIfscTrafDto> infoList  = this.vmsIfscMapper.selectVmsIfscTrafInfo();
+            log.info("VmsIfscService.loadVmsIfscTrafInfo(), {} EA", infoList.size());
+            infoList.forEach(dto -> {
+                this.trafMap.put(dto.getVmsIfscId(), dto.toEntity());
+            });
+        }
+        catch (Exception e) {
+            log.error("VmsIfscService.loadVmsIfscTrafInfo: {}", e.toString());
+        }
+    }
+
+}

+ 16 - 0
src/main/java/com/its/vms/service/VmsPrcsService.java

@@ -0,0 +1,16 @@
+package com.its.vms.service;
+
+import lombok.Data;
+import lombok.RequiredArgsConstructor;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.stereotype.Service;
+
+@Slf4j
+@Data
+@Service
+@RequiredArgsConstructor
+public class VmsPrcsService {
+
+    private boolean isStaticCycle = false;
+
+}

+ 192 - 0
src/main/java/com/its/vms/service/VmsSymbService.java

@@ -0,0 +1,192 @@
+package com.its.vms.service;
+
+import com.its.app.utils.FloodFill;
+import com.its.app.utils.ItsUtils;
+import com.its.vms.config.ApplicationConfig;
+import com.its.vms.dao.mapper.VmsSymbMapper;
+import com.its.vms.dto.TbVmsSymbIfscDto;
+import com.its.vms.dto.TbVmsSymbLibDto;
+import com.its.vms.entity.TbVmsSymbIfsc;
+import com.its.vms.entity.TbVmsSymbLib;
+import lombok.RequiredArgsConstructor;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.stereotype.Service;
+
+import javax.imageio.ImageIO;
+import java.awt.*;
+import java.awt.image.BufferedImage;
+import java.io.ByteArrayOutputStream;
+import java.io.File;
+import java.io.IOException;
+import java.util.List;
+import java.util.Map;
+import java.util.concurrent.ConcurrentHashMap;
+
+@Slf4j
+@Service
+@RequiredArgsConstructor
+public class VmsSymbService {
+
+    private final ApplicationConfig config;
+    private final VmsSymbMapper vmsSymbMapper;
+
+    public ConcurrentHashMap<String, TbVmsSymbLib> symbMap = new ConcurrentHashMap<>();
+
+    public void loadVmsSymbInfo() {
+        loadVmsSymbLib();
+        loadVmsSymbCellInfo();
+    }
+
+    public void loadVmsSymbLib() {
+        try {
+            List<TbVmsSymbLibDto> infoList  = this.vmsSymbMapper.selectVmsSymbLib();
+            log.info("VmsSymbService.loadVmsSymbLib(), {} EA", infoList.size());
+            infoList.forEach(dto -> {
+                // 심벌 유형(SBT0:일반심벌이미지,SBT1:소통정보배경,SBT2:소통정보이미지,SBT3:동영상,SBT4:대기환경등급)
+                // 소통정보이미지 때문에 이미지번호에 "0" 을 추가하여 이미지번호로 사용함
+                String updtDt = "";
+                TbVmsSymbLib obj = dto.toEntity();
+                TbVmsSymbLib oldObj = this.symbMap.get(obj.getSymbLibNmbr());
+                if (oldObj != null) {
+                    updtDt = oldObj.getUpdtDt();
+                }
+                this.symbMap.put(obj.getSymbLibNmbr(), obj);
+
+                if ("SBT4".equals(obj.getSymbType())) {
+                    // 대기환경등급
+                    String symbExpl = dto.getSymbExpl();
+                    if (symbExpl != null) {
+                        String[] symbNmbrArr = symbExpl.split("\\^");
+                        for (String symbNmbr : symbNmbrArr) {
+                            obj.getGradSymbLibNmbrList().add(symbNmbr + "0");
+                        }
+                    }
+                }
+
+                obj.setLocalFileName(this.config.getFtpImageDir() + obj.getSymbFileNm());
+                obj.setFtpFileName(ApplicationConfig.FTP_IMAGE + File.separator + obj.getSymbFileNm()); // Ftp 다운로드 명을 설정
+
+                // 심벌 유형(SBT0:일반심벌이미지,SBT1:소통정보배경,SBT2:소통정보이미지,SBT3:동영상)
+                if ("SBT3".equals(obj.getSymbType())) {
+                    //위에서 이미지저장하기 위해 파일명을 변경하기 때문에 여기서 동영상 파일명을 다시 읽어온다
+                    obj.setSymbFileNm(dto.getSymbFileNm()); //동영상인 경우 동영상 파일명
+                    obj.setLocalFileName(this.config.getFtpVideoDir() + obj.getSymbFileNm());
+                    obj.setFtpFileName(ApplicationConfig.FTP_VIDEO + File.separator + obj.getSymbFileNm()); // Ftp 다운로드 명을 설정
+                }
+
+                if ("SBT2".equals(obj.getSymbType())) {
+                    //심벌 유형(SBT0:일반심벌이미지,SBT1:소통정보배경,SBT2:소통정보이미지,SBT3:동영상)
+                    //소통정보 등급에 따른 이미지를 새롭게 추가한다.
+                    for (int nTrf = 1; nTrf <= 3; nTrf++) {
+                        String trfUpdtDt = "";
+                        String trafSymbLibNmbr = dto.getSymbLibNmbr() + String.valueOf(nTrf);
+                        TbVmsSymbLib trfObj = this.symbMap.get(trafSymbLibNmbr);
+                        if (trfObj != null) {
+                            trfUpdtDt = trfObj.getUpdtDt();
+                        }
+                        trfObj = obj.clone(trafSymbLibNmbr);
+
+                        this.symbMap.put(trfObj.getSymbLibNmbr(), trfObj);
+
+                        Image imgBmp = obj.getImage();  // 원천이미지를 가지고 온다.
+                        if (imgBmp == null) {
+                            log.error("VmsSymbService.loadVmsSymbLib: Image Data Error: {}", trafSymbLibNmbr);
+                            continue;
+                        }
+
+                        String imagFmt = "bmp";
+                        BufferedImage formImage = new BufferedImage(imgBmp.getWidth(null), imgBmp.getHeight(null),
+                                (("png").equals(imagFmt) ? BufferedImage.TYPE_INT_ARGB : BufferedImage.TYPE_INT_RGB));
+                        Graphics2D 	g2d = (Graphics2D)formImage.createGraphics();
+
+                        FloodFill floodFill = new FloodFill(imgBmp);
+                        floodFill.setAntialiased(false);
+                        int orgColor = floodFill.getImage().getRGB(obj.getPosX(), obj.getPosY());
+                        int trfColor = VmsSymbService.getGradColor(nTrf);
+                        if (orgColor != trfColor) {
+                            floodFill.fill(obj.getPosX(), obj.getPosY(), VmsSymbService.getTrafColor(nTrf));
+                        }
+                        g2d.drawImage(floodFill.getImage(), 0, 0, imgBmp.getWidth(null), imgBmp.getHeight(null), null);
+                        ByteArrayOutputStream out = new ByteArrayOutputStream();
+                        try {
+                            ImageIO.write(formImage, imagFmt, out);
+                        } catch (IOException e) {
+                            log.error("VmsSymbService.loadVmsSymbLib: Image Convert error: {}", trafSymbLibNmbr);
+                        }
+                        g2d.dispose();
+                        trfObj.setImagData(out.toByteArray());
+
+                        trfObj.setLocalFileName(this.config.getFtpImageDir() + trfObj.getSymbFileNm());
+                        trfObj.setFtpFileName(ApplicationConfig.FTP_IMAGE + File.separator + trfObj.getSymbFileNm()); // Ftp 다운로드 명을 설정
+                        // 소통등급별 이미지 파일 저장
+                        saveByteArrayToFile(trfObj, trfUpdtDt);
+                    }
+                }
+
+                // 이미지 파일저장
+                if (!"SBT3".equals(obj.getSymbType())) {
+                    saveByteArrayToFile(obj, updtDt);
+                }
+            });
+        }
+        catch (Exception e) {
+            log.error("VmsSymbService.loadVmsSymbLib: {}", e.toString());
+        }
+    }
+
+    public void loadVmsSymbCellInfo() {
+        try {
+            List<TbVmsSymbIfscDto> infoList  = this.vmsSymbMapper.selectVmsSymbCellInfo();
+            log.info("VmsSymbService.loadVmsSymbCellInfo(), {} EA", infoList.size());
+            infoList.forEach(dto -> {
+                String updtDt = dto.getUpdtDt();
+                Integer symbLibNmbr = dto.getSymbLibNmbr();
+                TbVmsSymbLib obj = this.symbMap.get(symbLibNmbr + "0");
+                if (obj == null) {
+                    log.error("VmsSymbService.loadVmsSymbCellInfo: Not Found Cell Info {}.", symbLibNmbr);
+                    return;
+                }
+                TbVmsSymbIfsc cell = dto.toEntity();
+                for (Map.Entry<Integer, TbVmsSymbIfsc> cellObj : obj.getCellMap().entrySet()) {
+                    if (cellObj.getValue().getVmsIfscId().equals(cell.getVmsIfscId())) {
+                        cell.setDup(true);
+                        break;
+                    }
+                }
+                obj.getCellMap().put(cell.getCellId(), cell);
+            });
+        }
+        catch (Exception e) {
+            log.error("VmsSymbService.loadVmsSymbCellInfo: {}", e.getMessage());
+        }
+    }
+
+    public boolean saveByteArrayToFile(TbVmsSymbLib obj, String updtDt) {
+        boolean result = true;
+        File imagFile = new File(obj.getLocalFileName());
+        if (!imagFile.exists() || !obj.getUpdtDt().equals(updtDt)) {
+            if (imagFile.exists()) {
+                boolean deleted = imagFile.delete();
+                log.info("VmsSymbService.saveImageFile: Old file deleted {}, {}", obj.getLocalFileName(), deleted);
+            }
+            result = ItsUtils.saveByteArrayToFile(obj.getLocalFileName(), obj.getImagData());
+        }
+        obj.setUpdtDt(updtDt);  // 업데이트 시각을 업데이트 한다.
+        return result;
+    }
+
+    public static int getGradColor(int grad) {
+        if (grad == 1) return Color.GREEN.getRGB();
+        if (grad == 2) return Color.YELLOW.getRGB();
+        if (grad == 3) return Color.RED.getRGB();
+        return Color.GRAY.getRGB();
+    }
+
+    public static Color getTrafColor(int grad) {
+        if (grad == 1) return Color.GREEN;
+        if (grad == 2) return Color.YELLOW;
+        if (grad == 3) return Color.RED;
+        return Color.GRAY;
+    }
+
+}

+ 33 - 0
src/main/java/com/its/vms/ui/CtlrSttsDetlTableCellRenderer.java

@@ -0,0 +1,33 @@
+package com.its.vms.ui;
+
+import javax.swing.*;
+import javax.swing.table.DefaultTableCellRenderer;
+import java.awt.*;
+
+public class CtlrSttsDetlTableCellRenderer extends DefaultTableCellRenderer {
+
+    public Component getTableCellRendererComponent(JTable table, Object value, boolean isSelected, boolean hasFocus, int row, int column) {
+
+        Component cell = super.getTableCellRendererComponent(table, value, isSelected, hasFocus, row, column);
+        String commStts = table.getModel().getValueAt(row, 6).toString();
+        if (commStts.equals("Connect")) {
+            cell.setBackground(new Color(255, 255, 255, 255));
+            String door = table.getModel().getValueAt(row, 7).toString();
+            String fan = table.getModel().getValueAt(row, 8).toString();
+            String heater = table.getModel().getValueAt(row, 9).toString();
+            String video = table.getModel().getValueAt(row, 11).toString();
+        } else if (commStts.equals("Login")) {
+            cell.setBackground(new Color(182, 175, 97, 176));
+        } else {
+            cell.setBackground(new Color(182, 97, 97, 176));
+        }
+
+        if (column != 3 && column != 4) {
+            setHorizontalAlignment(SwingConstants.CENTER);
+        } else {
+            setHorizontalAlignment(SwingConstants.LEFT);
+        }
+
+        return cell;
+    }
+}

+ 32 - 0
src/main/java/com/its/vms/ui/CtlrSttsTableCellRenderer.java

@@ -0,0 +1,32 @@
+package com.its.vms.ui;
+
+import javax.swing.*;
+import javax.swing.table.DefaultTableCellRenderer;
+import java.awt.*;
+
+public class CtlrSttsTableCellRenderer extends DefaultTableCellRenderer {
+
+    public Component getTableCellRendererComponent(JTable table, Object value, boolean isSelected, boolean hasFocus, int row, int column) {
+
+        Component cell = super.getTableCellRendererComponent(table, value, isSelected, hasFocus, row, column);
+        String commStts = table.getModel().getValueAt(row, 6).toString();
+        if (commStts.equals("Connect")) {
+            cell.setBackground(new Color(255, 255, 255, 255));
+        } else if (commStts.equals("Login")) {
+            cell.setBackground(new Color(182, 175, 97, 176));
+        } else {
+            cell.setBackground(new Color(182, 97, 97, 176));
+        }
+
+        if (column != 3 && column != 4) {
+            setHorizontalAlignment(SwingConstants.CENTER);
+        } else {
+            setHorizontalAlignment(SwingConstants.LEFT);
+        }
+        if (column == 0) {
+            cell.setBackground(Color.LIGHT_GRAY);
+        }
+
+        return cell;
+    }
+}

+ 162 - 0
src/main/java/com/its/vms/ui/CtlrSttsTableModel.java

@@ -0,0 +1,162 @@
+package com.its.vms.ui;
+
+import com.its.vms.entity.TbVmsCtlr;
+import com.its.vms.dto.TbVmsCtlrSttsDto;
+import lombok.extern.slf4j.Slf4j;
+
+import javax.swing.table.AbstractTableModel;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+
+@Slf4j
+public class CtlrSttsTableModel extends AbstractTableModel {
+    private static final long serialVersionUID = 1331132425472559704L;
+
+    private List<TbVmsCtlr> ctlrList = Collections.synchronizedList(new ArrayList<TbVmsCtlr>());
+    private final String[] columnNames = {
+            "#",
+            "NO",
+            "ID",
+            "Name",
+            "IP Address",
+            "Mode",
+            "연결상태",
+            "Connect",
+            "Disconnect",
+            "Connected"
+    };
+    public static final String[] netStateStr = {
+            "Close", "Login", "Connect",
+    };
+
+    public CtlrSttsTableModel(List<TbVmsCtlr> ctlrList) {
+        this.ctlrList = ctlrList;
+
+        int indexCount = 1;
+        for (TbVmsCtlr obj : ctlrList) {
+            obj.setIndex(indexCount++);
+        }
+    }
+
+    @Override
+    public int getColumnCount() {
+        return columnNames.length;
+    }
+
+    @Override
+    public int getRowCount() {
+        int size = 0;
+        synchronized (this.ctlrList) {
+            size = this.ctlrList.size();
+        }
+        return size;
+    }
+
+    @Override
+    public String getColumnName(int columnIndex) {
+        if (columnIndex < columnNames.length) {
+            return columnNames[columnIndex];
+        }
+        return super.getColumnName(columnIndex);
+    }
+
+    @Override
+    public Class<?> getColumnClass(int columnIndex) {
+        if (ctlrList.isEmpty()) {
+            return Object.class;
+        }
+        return getValueAt(0, columnIndex).getClass();
+    }
+
+    public TbVmsCtlr getControllerInfo(int row) {
+        TbVmsCtlr info = this.ctlrList.get(row);
+        return info;
+    }
+
+    @Override
+    public Object getValueAt(int rowIndex, int columnIndex) {
+        Object returnValue = null;
+        synchronized (this.ctlrList) {
+            TbVmsCtlr info = this.ctlrList.get(rowIndex);
+            if (info == null) {
+                return "";
+            }
+
+            int netState = info.getNetState();
+            TbVmsCtlrSttsDto stts = info.getStts();
+            String temper = "-";
+            String fDoor = "-";
+            String bDoor = "-";
+            String fan = "-";
+            String hetr = "-";
+            String rtu = "-";
+            if ("CMS0".equals(stts.getCmncSttsCd())) {
+                temper = String.valueOf(stts.getCboxTmpr());
+                if ("CDS0".equals(stts.getCboxDoorSttsCd())) {
+                    fDoor = "닫힘";
+                } else if ("CDS1".equals(stts.getCboxDoorSttsCd())) {
+                    fDoor = "열림";
+                }
+                if ("CDS0".equals(stts.getCboxDoorSttsCd())) {
+                    bDoor = "닫힘";
+                } else if ("CDS1".equals(stts.getCboxDoorSttsCd())) {
+                    bDoor = "열림";
+                }
+                if ("PAS0".equals(stts.getFanSttsCd())) {
+                    fan = "가동";
+                } else if ("PAS1".equals(stts.getFanSttsCd())) {
+                    fan = "중지";
+                }
+                if ("HTS0".equals(stts.getHetrSttsCd())) {
+                    hetr = "가동";
+                } else if ("HTS1".equals(stts.getHetrSttsCd())) {
+                    hetr = "중지";
+                }
+            }
+            switch (columnIndex) {
+                case 0: returnValue = info.getIndex(); break;
+                case 1: returnValue = info.getCtlrNmbr(); break;
+                case 2: returnValue = info.getCtlrId(); break;
+                case 3: returnValue = " " + info.getName(); break;
+                case 4: returnValue = info.getCtlrIp(); break;
+                case 5: returnValue = info.getOperMode(); break;
+                case 6: returnValue = netStateStr[netState]; break;
+                case  7: returnValue = info.getConnectTm(); break;
+                case  8: returnValue = info.getDisConnectTm(); break;
+                case  9: returnValue = info.getConnectCount(); break;
+            }
+        }
+        return returnValue;
+    }
+
+    @Override
+    public void setValueAt(Object value, int rowIndex, int columnIndex) {
+        synchronized (this.ctlrList) {
+            TbVmsCtlr obj = ctlrList.get(rowIndex);
+            if (columnIndex == 0) {
+                obj.setIndex((int) value);
+            }
+        }
+    }
+    public void setValueAt(TbVmsCtlr obj, int rowIdx, int colIdx) {
+        synchronized (this.ctlrList) {
+        }
+        fireTableCellUpdated(rowIdx, colIdx);
+        fireTableDataChanged();
+    }
+
+    public void Add(TbVmsCtlr info) {
+        int index = 0;
+        synchronized (this.ctlrList) {
+            index = this.ctlrList.size();
+            this.ctlrList.add(info);
+        }
+        fireTableRowsInserted(index, index);
+    }
+
+    public void setValue(TbVmsCtlr obj, int viewRow, int modelRow) {
+        fireTableDataChanged();
+    }
+
+}

+ 70 - 0
src/main/java/com/its/vms/ui/JTextAreaOutputStream.java

@@ -0,0 +1,70 @@
+package com.its.vms.ui;
+
+import javax.swing.*;
+import java.io.IOException;
+import java.io.OutputStream;
+
+public class JTextAreaOutputStream extends OutputStream {
+
+    private final JTextArea logArea;
+    public static boolean isLoggingPause = false;
+    private final StringBuilder sb = new StringBuilder();
+
+    public JTextAreaOutputStream(JTextArea logArea) {
+        if (logArea == null)
+            throw new IllegalArgumentException ("Destination is null...");
+        this.logArea = logArea;
+    }
+
+    @Override
+    public void write(byte[] buffer, int offset, int length) throws IOException
+    {
+        if (isLoggingPause) {
+            return;
+        }
+        final String text = new String(buffer, offset, length);
+        SwingUtilities.invokeLater(new Runnable ()
+        {
+            @Override
+            public void run()
+            {
+                synchronized (logArea) {
+                    if (logArea.getLineCount() > 2000) {
+                        logArea.setText(null);
+                    }
+                    logArea.append(text);
+                    logArea.setCaretPosition(logArea.getDocument().getLength());
+                }
+            }
+        });
+    }
+
+    @Override
+    public void write(int b) throws IOException {
+        if (isLoggingPause) {
+            sb.setLength(0);
+            return;
+        }
+        if (b == '\n') {
+            final String text = sb.toString() + "\n";
+            SwingUtilities.invokeLater(new Runnable ()
+            {
+                @Override
+                public void run()
+                {
+                    synchronized (logArea) {
+                        if (logArea.getLineCount() > 2000) {
+                            logArea.setText(null);
+                        }
+                        logArea.append(text);
+                        logArea.setCaretPosition(logArea.getDocument().getLength());
+                        sb.setLength(0);
+                    }
+                }
+            });
+        } else {
+            sb.append(String.valueOf((char)b));
+            //sb.append((char) b);
+        }
+    }
+}

Alguns arquivos não foram mostrados porque muitos arquivos mudaram nesse diff