浏览代码

first commit

shjung 3 年之前
当前提交
3d9f64e391
共有 65 个文件被更改,包括 3520 次插入0 次删除
  1. 34 0
      .gitignore
  2. 118 0
      .mvn/wrapper/MavenWrapperDownloader.java
  3. 二进制
      .mvn/wrapper/maven-wrapper.jar
  4. 2 0
      .mvn/wrapper/maven-wrapper.properties
  5. 322 0
      mvnw
  6. 182 0
      mvnw.cmd
  7. 169 0
      pom.xml
  8. 105 0
      src/main/java/com/tsi/api/server/TsiApiServerApplication.java
  9. 44 0
      src/main/java/com/tsi/api/server/config/TsiSchedulingConfig.java
  10. 438 0
      src/main/java/com/tsi/api/server/controller/TscSsipApiController.java
  11. 215 0
      src/main/java/com/tsi/api/server/controller/TscSsipAppController.java
  12. 13 0
      src/main/java/com/tsi/api/server/controller/TscSsipTestController.java
  13. 31 0
      src/main/java/com/tsi/api/server/controller/result/AbstractTscSsipApiResult.java
  14. 29 0
      src/main/java/com/tsi/api/server/controller/result/TscNaviApiResultAuthInfo.java
  15. 26 0
      src/main/java/com/tsi/api/server/controller/result/TscNaviApiResultDeviceRegisterInfo.java
  16. 29 0
      src/main/java/com/tsi/api/server/controller/result/TscNaviApiResultNodeStatusInfo.java
  17. 20 0
      src/main/java/com/tsi/api/server/controller/result/TscSsipApiResultBrokerInfo.java
  18. 8 0
      src/main/java/com/tsi/api/server/controller/result/TscSsipApiResultError.java
  19. 26 0
      src/main/java/com/tsi/api/server/controller/result/TscSsipApiResultKafkaAuth.java
  20. 26 0
      src/main/java/com/tsi/api/server/controller/result/TscSsipApiResultKafkaTokenInfo.java
  21. 29 0
      src/main/java/com/tsi/api/server/controller/result/TscSsipApiResultNodeInfo.java
  22. 26 0
      src/main/java/com/tsi/api/server/controller/result/TscSsipApiResultSystemStatus.java
  23. 16 0
      src/main/java/com/tsi/api/server/dto/KafkaTokenAuthDto.java
  24. 24 0
      src/main/java/com/tsi/api/server/dto/KafkaTokenDto.java
  25. 12 0
      src/main/java/com/tsi/api/server/dto/SystemStatus2Dto.java
  26. 36 0
      src/main/java/com/tsi/api/server/dto/SystemStatusDto.java
  27. 39 0
      src/main/java/com/tsi/api/server/error/TscSsipApiErrorCode.java
  28. 47 0
      src/main/java/com/tsi/api/server/error/TscSsipApiErrorResponse.java
  29. 16 0
      src/main/java/com/tsi/api/server/exception/AbstractTscSsipApiException.java
  30. 10 0
      src/main/java/com/tsi/api/server/exception/TscSsipApiServiceException.java
  31. 61 0
      src/main/java/com/tsi/api/server/mybatis/MybatisConfig.java
  32. 21 0
      src/main/java/com/tsi/api/server/mybatis/TscSsipApiMapper.java
  33. 20 0
      src/main/java/com/tsi/api/server/mybatis/TscSsipAppMapper.java
  34. 21 0
      src/main/java/com/tsi/api/server/mybatis/TsiDatabaseMapper.java
  35. 158 0
      src/main/java/com/tsi/api/server/mybatis/TsiDatabaseService.java
  36. 26 0
      src/main/java/com/tsi/api/server/mybatis/vo/AbstractDbmsVo.java
  37. 12 0
      src/main/java/com/tsi/api/server/mybatis/vo/AlarmConfigVo.java
  38. 19 0
      src/main/java/com/tsi/api/server/mybatis/vo/AlarmOccrVo.java
  39. 17 0
      src/main/java/com/tsi/api/server/mybatis/vo/ProcessStateVo.java
  40. 63 0
      src/main/java/com/tsi/api/server/repository/TsiAlarmManager.java
  41. 47 0
      src/main/java/com/tsi/api/server/repository/TsiSystemStatusManager.java
  42. 44 0
      src/main/java/com/tsi/api/server/scheduler/TsiScheduler.java
  43. 135 0
      src/main/java/com/tsi/api/server/service/TscSsipApiService.java
  44. 91 0
      src/main/java/com/tsi/api/server/service/TscSsipAppService.java
  45. 88 0
      src/main/java/com/tsi/api/server/service/TscSsipKafkaTokenService.java
  46. 36 0
      src/main/java/com/tsi/api/server/util/ApiUtils.java
  47. 16 0
      src/main/java/com/tsi/api/server/vo/ApiInvokeVo.java
  48. 9 0
      src/main/java/com/tsi/api/server/vo/AuthorizedVo.java
  49. 11 0
      src/main/java/com/tsi/api/server/vo/BrokerVo.java
  50. 12 0
      src/main/java/com/tsi/api/server/vo/DeviceInfo.java
  51. 13 0
      src/main/java/com/tsi/api/server/vo/KafkaAuthorizedVo.java
  52. 13 0
      src/main/java/com/tsi/api/server/vo/NaviAuthorizedVo.java
  53. 14 0
      src/main/java/com/tsi/api/server/vo/NodeStatusVo.java
  54. 11 0
      src/main/java/com/tsi/api/server/vo/NodeVo.java
  55. 58 0
      src/main/java/com/tsi/api/server/vo/SystemStatusVo.java
  56. 21 0
      src/main/java/com/tsi/api/server/vo/TsiAlarmConfigVo.java
  57. 10 0
      src/main/java/com/tsi/api/server/vo/VersionVo.java
  58. 43 0
      src/main/resources/application.yml
  59. 9 0
      src/main/resources/banner.txt
  60. 87 0
      src/main/resources/logback-spring.xml
  61. 106 0
      src/main/resources/mybatis/mapper/tsc-ssip-api.xml
  62. 56 0
      src/main/resources/mybatis/mapper/tsc-ssip-app.xml
  63. 47 0
      src/main/resources/mybatis/mapper/tsi-database.xml
  64. 21 0
      src/main/resources/mybatis/mybatis-config.xml
  65. 12 0
      src/test/java/com/tsi/api/server/TscSsipApiApplicationTests.java

+ 34 - 0
.gitignore

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

+ 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();
+    }
+
+}

二进制
.mvn/wrapper/maven-wrapper.jar


+ 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

+ 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%

+ 169 - 0
pom.xml

@@ -0,0 +1,169 @@
+<?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.3.11.RELEASE</version>
+        <relativePath/> <!-- lookup parent from repository -->
+    </parent>
+    <groupId>com.tsi.api</groupId>
+    <artifactId>tsi-web</artifactId>
+    <version>0.0.1</version>
+    <name>tsi-web</name>
+    <description>TSI WEB Server</description>
+
+    <packaging>jar</packaging>
+
+    <!--<repositories>
+        <repository>
+            <id>oracle</id>
+            <url>http://maven.jahia.org/maven2</url>
+        </repository>
+    </repositories>-->
+
+    <properties>
+        <java.version>1.8</java.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.tsi.api.server.TsiApiServerApplication</start-class>
+        <webapp.lib>C://UTIC-2021//tsi-repository</webapp.lib>
+        <maven.test.skip>true</maven.test.skip>
+    </properties>
+
+    <dependencies>
+        <dependency>
+            <groupId>com.tsi</groupId>
+            <artifactId>tsi-common</artifactId>
+            <version>1.0</version>
+            <scope>system</scope>
+            <systemPath>${webapp.lib}/tsi-common.jar</systemPath>
+        </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>
+        </dependency>
+        <dependency>
+            <groupId>org.mybatis.spring.boot</groupId>
+            <artifactId>mybatis-spring-boot-starter</artifactId>
+            <version>2.1.3</version>
+        </dependency>
+
+        <!-- FOR DATABASE: START -->
+        <dependency>
+            <groupId>org.mariadb.jdbc</groupId>
+            <artifactId>mariadb-java-client</artifactId>
+            <version>2.7.0</version>
+        </dependency>
+        <!-- FOR DATABASE: END -->
+
+        <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>
+
+        <!-- FOR UTIL: START -->
+        <dependency>
+            <groupId>com.github.dozermapper</groupId>
+            <artifactId>dozer-spring4</artifactId>
+            <version>6.5.0</version>
+        </dependency>
+        <!-- FOR UTIL: END -->
+
+        <dependency>
+            <groupId>io.jsonwebtoken</groupId>
+            <artifactId>jjwt</artifactId>
+            <version>0.9.1</version>
+        </dependency>
+
+        <!-- FOR JPA: START -->
+        <!--<dependency>
+            <groupId>org.springframework.boot</groupId>
+            <artifactId>spring-boot-starter-data-jpa</artifactId>
+        </dependency>-->
+        <!-- FOR JPA: END -->
+
+        <!-- FOR WEB UI: START -->
+        <dependency>
+            <groupId>org.springframework.boot</groupId>
+            <artifactId>spring-boot-test</artifactId>
+<!--
+            <version>2.4.7-SNAPSHOT</version>
+-->
+            <scope>test</scope>
+        </dependency>
+
+        <dependency>
+            <groupId>org.junit.jupiter</groupId>
+            <artifactId>junit-jupiter-api</artifactId>
+            <version>5.6.2</version>
+            <scope>test</scope>
+        </dependency>
+        <dependency>
+            <groupId>org.jetbrains</groupId>
+            <artifactId>annotations</artifactId>
+            <version>21.0.1</version>
+            <scope>compile</scope>
+        </dependency>
+        <dependency>
+            <groupId>org.hibernate</groupId>
+            <artifactId>hibernate-core</artifactId>
+            <version>4.2.1.Final</version>
+        </dependency>
+        <!-- FOR WEB UI: END -->
+
+    </dependencies>
+
+    <build>
+        <plugins>
+            <plugin>
+                <groupId>org.springframework.boot</groupId>
+                <artifactId>spring-boot-maven-plugin</artifactId>
+                <configuration>
+                    <includeSystemScope>true</includeSystemScope>
+                    <excludes>
+                        <exclude>
+                            <groupId>org.projectlombok</groupId>
+                            <artifactId>lombok</artifactId>
+                        </exclude>
+                    </excludes>
+                </configuration>
+            </plugin>
+        </plugins>
+    </build>
+
+</project>

+ 105 - 0
src/main/java/com/tsi/api/server/TsiApiServerApplication.java

@@ -0,0 +1,105 @@
+package com.tsi.api.server;
+
+import com.tsi.api.server.mybatis.TsiDatabaseService;
+import com.tsi.api.server.mybatis.vo.AbstractDbmsVo;
+import com.tsi.api.server.mybatis.vo.AlarmOccrVo;
+import com.tsi.api.server.repository.TsiAlarmManager;
+import com.tsi.api.server.vo.TsiAlarmConfigVo;
+import com.tsi.app.common.app.AppUtils;
+import lombok.extern.slf4j.Slf4j;
+import org.mybatis.spring.annotation.MapperScan;
+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.ApplicationListener;
+import org.springframework.context.annotation.ComponentScan;
+import org.springframework.context.event.ContextClosedEvent;
+
+import javax.annotation.PostConstruct;
+import java.text.SimpleDateFormat;
+import java.util.Date;
+
+@Slf4j
+@MapperScan(basePackageClasses = TsiApiServerApplication.class)
+@SpringBootApplication
+@ComponentScan(basePackages = {"com.tsi.app.common", "com.tsi.api.server.config", "com.tsi.api.server"})
+public class TsiApiServerApplication implements CommandLineRunner, ApplicationListener<ContextClosedEvent>, InitializingBean, DisposableBean {
+
+    private static String applicationName = "tsi-web";
+
+    @PostConstruct
+    public void started() {
+/*
+        TimeZone.setDefault(TimeZone.getTimeZone(applicationProperties.getTimeZone()));
+        System.out.println("....................................... started: " + new Date());
+*/
+    }
+
+    public static void main(String[] args) {
+        SpringApplication application = new SpringApplicationBuilder()
+                .sources(TsiApiServerApplication.class)
+                .listeners(new ApplicationPidFileWriter("./conf/" + applicationName + ".pid"))
+                .build();
+        application.setBannerMode(Banner.Mode.OFF);
+        application.run(args);
+    }
+
+    @Override
+    public void run(String... args) throws Exception {
+        SimpleDateFormat sdfDate = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
+        log.info("");
+        log.info("");
+        log.info("************************************************************************************");
+        log.info("**                                                                                **");
+        log.info("**                               TSI CVIM System                                  **");
+        log.info("**                           CVIM API Server Program.                             **");
+        log.info("**                                                                                **");
+        log.info("**                                                                   [ver.1.0]    **");
+        log.info("** startup: {}", sdfDate.format(new Date()));
+        log.info("************************************************************************************");
+
+        TsiAlarmManager.getInstance().getProcessStateVo().setProcessId(applicationName);
+        try {
+            TsiDatabaseService tsiDatabaseService = (TsiDatabaseService) AppUtils.getBean(TsiDatabaseService.class);
+            AlarmOccrVo alarm = new AlarmOccrVo(AbstractDbmsVo.DBMS_ALARM_OCCR_HS);
+            alarm.setAlarmCode(TsiAlarmConfigVo.SYS_00);
+            alarm.setAlarmTarget(applicationName);
+            alarm.setAlarmValue("Running");
+            tsiDatabaseService.insertAlarmOccrHs(alarm);
+            tsiDatabaseService.updateProcessState(0);
+        }
+        catch(Exception e) {
+        }
+    }
+
+    @Override
+    public void destroy() throws Exception {
+
+    }
+
+    @Override
+    public void afterPropertiesSet() throws Exception {
+
+    }
+
+    @Override
+    public void onApplicationEvent(ContextClosedEvent contextClosedEvent) {
+        SimpleDateFormat sdfDate = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
+        TsiDatabaseService tsiDatabaseService = (TsiDatabaseService)AppUtils.getBean(TsiDatabaseService.class);
+        try {
+            // 시스템 종료 알람 이력 저장
+            AlarmOccrVo alarm = new AlarmOccrVo(AbstractDbmsVo.DBMS_ALARM_OCCR_HS);
+            alarm.setAlarmCode(TsiAlarmConfigVo.SYS_00);
+            alarm.setAlarmTarget(applicationName);
+            alarm.setAlarmValue("Terminated");
+            tsiDatabaseService.insertAlarmOccrHs(alarm);
+            tsiDatabaseService.updateProcessState(2);
+        } catch (Exception e) { }
+        log.error("Application Terminated: {}, {}", sdfDate.format(new Date()), contextClosedEvent.toString());
+    }
+}

+ 44 - 0
src/main/java/com/tsi/api/server/config/TsiSchedulingConfig.java

@@ -0,0 +1,44 @@
+package com.tsi.api.server.config;
+
+import lombok.Data;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.boot.context.properties.ConfigurationProperties;
+import org.springframework.context.annotation.Configuration;
+import org.springframework.scheduling.annotation.SchedulingConfigurer;
+import org.springframework.scheduling.concurrent.ThreadPoolTaskScheduler;
+import org.springframework.scheduling.config.ScheduledTaskRegistrar;
+
+import javax.annotation.PostConstruct;
+
+@Slf4j
+@Data
+@Configuration
+@ConfigurationProperties(prefix = "application.scheduling")
+public class TsiSchedulingConfig implements SchedulingConfigurer {
+
+    private int poolCore = 0;
+
+    private final int SCHEDULE_THREAD_POOL_SIZE = 10;
+
+    @PostConstruct
+    private void init() {
+        log.info("[{}] ------------", this.getClass().getSimpleName());
+        if (this.poolCore == 0) {
+            log.warn("[{}] poolCore size set as default: {} EA.", this.getClass().getSimpleName(), this.poolCore);
+            this.poolCore = 10;
+        }
+        log.info("[{}] poolCore: {} EA.", this.getClass().getSimpleName(), this.poolCore);
+    }
+
+    @Override
+    public void configureTasks(ScheduledTaskRegistrar scheduledTaskRegistrar) {
+
+        ThreadPoolTaskScheduler threadPoolTaskScheduler = new ThreadPoolTaskScheduler();
+
+        threadPoolTaskScheduler.setPoolSize(SCHEDULE_THREAD_POOL_SIZE);
+        threadPoolTaskScheduler.setThreadNamePrefix("scheduler-");
+        threadPoolTaskScheduler.initialize();
+
+        scheduledTaskRegistrar.setTaskScheduler(threadPoolTaskScheduler);
+    }
+}

+ 438 - 0
src/main/java/com/tsi/api/server/controller/TscSsipApiController.java

@@ -0,0 +1,438 @@
+package com.tsi.api.server.controller;
+
+import com.tsi.api.server.controller.result.*;
+import com.tsi.api.server.dto.KafkaTokenAuthDto;
+import com.tsi.api.server.dto.KafkaTokenDto;
+import com.tsi.api.server.dto.SystemStatus2Dto;
+import com.tsi.api.server.dto.SystemStatusDto;
+import com.tsi.api.server.error.TscSsipApiErrorCode;
+import com.tsi.api.server.repository.TsiSystemStatusManager;
+import com.tsi.api.server.service.TscSsipApiService;
+import com.tsi.api.server.service.TscSsipKafkaTokenService;
+import com.tsi.api.server.util.ApiUtils;
+import com.tsi.api.server.vo.ApiInvokeVo;
+import com.tsi.api.server.vo.BrokerVo;
+import com.tsi.api.server.vo.KafkaAuthorizedVo;
+import com.tsi.api.server.vo.SystemStatusVo;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.http.HttpStatus;
+import org.springframework.http.ResponseEntity;
+import org.springframework.web.bind.annotation.*;
+
+import javax.servlet.http.HttpServletRequest;
+import java.util.UUID;
+
+@Slf4j
+@RestController
+public class TscSsipApiController {
+
+    private final String SSIP_API_NODE_INFO     = "/api/nodeInfo/{apiToken}";
+    private final String SSIP_API_BROKER_INFO   = "/api/brokerInfo/{apiToken}";
+    private final String SSIP_API_UUID          = "/api/uuid";
+    private final String SSIP_API_SYSTEM_STATUS = "/api/system-status";
+    private final String SSIP_API_SYSTEM_STATUS2 = "/api/system-status2";
+    private final String SSIP_API_KAFKA_TOKEN   = "/api/kafka/token/{apiToken}";
+    private final String SSIP_API_KAFKA_AUTH    = "/api/kafka/auth";
+
+    private final TscSsipApiService tscSsipApiService;
+    private final TscSsipKafkaTokenService tscSsipKafkaTokenService;
+
+    public TscSsipApiController(TscSsipApiService tscSsipApiService, TscSsipKafkaTokenService tscSsipKafkaTokenService) {
+        this.tscSsipApiService = tscSsipApiService;
+        this.tscSsipKafkaTokenService = tscSsipKafkaTokenService;
+    }
+
+    @GetMapping(value = {SSIP_API_NODE_INFO}, produces = {"application/json; charset=utf8"})
+    public ResponseEntity<AbstractTscSsipApiResult> getNodeInfo(@PathVariable("apiToken") String apiToken, HttpServletRequest request) {
+
+        String apiId = SSIP_API_NODE_INFO;
+        String remoteIP = ApiUtils.getRemoteIP(request);
+        log.info("{}, {}, {}", apiId, remoteIP, apiToken);
+
+        ApiInvokeVo apiInvokeVo = ApiInvokeVo.builder()
+                .apiId(apiId)
+                .apiToken(apiToken)
+                .ipAddr(remoteIP)
+                .error(TscSsipApiErrorCode.SUCCESS.getCode())
+                .build();
+
+        try {
+            TscSsipApiErrorCode authorizedInfo = this.tscSsipApiService.getAuthorizedInfo(apiId, apiToken, remoteIP);
+            if (authorizedInfo != TscSsipApiErrorCode.SUCCESS) {
+                // api token 인증 오류
+                log.error("인증오류: [{}] ==> [{}]: [{}].[{}]" + apiId, remoteIP, apiToken, authorizedInfo.getCode(), authorizedInfo.getMessage());
+                apiInvokeVo.setError(authorizedInfo.getCode());
+                this.tscSsipApiService.insertInvokeHs(apiInvokeVo, true);
+                TscSsipApiResultError error = new TscSsipApiResultError(authorizedInfo.getCode(), authorizedInfo.getMessage());
+                return new ResponseEntity<>(error, HttpStatus.UNAUTHORIZED);
+            }
+        }
+        catch (Exception e) {
+            log.error("getNodeInfo: {}", e.getMessage());
+            // 데이터베이스 오류
+            TscSsipApiResultError error = new TscSsipApiResultError(TscSsipApiErrorCode.ERROR_INTERNAL_DATA.getCode(), TscSsipApiErrorCode.ERROR_INTERNAL_DATA.getMessage());
+            apiInvokeVo.setError(TscSsipApiErrorCode.ERROR_INTERNAL_DATA.getCode());
+            this.tscSsipApiService.insertInvokeHs(apiInvokeVo, true);
+            return new ResponseEntity<>(error, HttpStatus.INTERNAL_SERVER_ERROR);
+        }
+        TscSsipApiResultNodeInfo result = new TscSsipApiResultNodeInfo(TscSsipApiErrorCode.SUCCESS.getCode(), TscSsipApiErrorCode.SUCCESS.getMessage());
+        result.setNodes(tscSsipApiService.getNodeInfoList());
+        result.setCount(result.getNodes().size());
+
+        // 이력저장
+        this.tscSsipApiService.insertInvokeHs(apiInvokeVo, true);
+        return new ResponseEntity<>(result, HttpStatus.OK);
+    }
+
+    @GetMapping(value = {SSIP_API_BROKER_INFO}, produces = {"application/json; charset=utf8"})
+    public ResponseEntity<AbstractTscSsipApiResult> getBrokerInfo(@PathVariable("apiToken") String apiToken, HttpServletRequest request) {
+
+        String apiId = SSIP_API_BROKER_INFO;
+        String remoteIP = ApiUtils.getRemoteIP(request);
+        log.info("{}, {}, {}", apiId, remoteIP, apiToken);
+
+        ApiInvokeVo apiInvokeVo = ApiInvokeVo.builder()
+                .apiId(apiId)
+                .apiToken(apiToken)
+                .ipAddr(remoteIP)
+                .error(TscSsipApiErrorCode.SUCCESS.getCode())
+                .build();
+
+        try {
+            TscSsipApiErrorCode authorizedInfo = this.tscSsipApiService.getAuthorizedInfo(apiId, apiToken, remoteIP);
+            if (authorizedInfo != TscSsipApiErrorCode.SUCCESS) {
+                // api token 인증 오류
+                log.error("인증오류: [{}] ==> [{}]: [{}].[{}]" + apiId, remoteIP, apiToken, authorizedInfo.getCode(), authorizedInfo.getMessage());
+                apiInvokeVo.setError(authorizedInfo.getCode());
+                this.tscSsipApiService.insertInvokeHs(apiInvokeVo, true);
+                TscSsipApiResultError error = new TscSsipApiResultError(authorizedInfo.getCode(), authorizedInfo.getMessage());
+                return new ResponseEntity<> (error, HttpStatus.UNAUTHORIZED);
+            }
+        }
+        catch (Exception e) {
+            log.error("getBrokerInfo: {}", e.getMessage());
+            // 데이터베이스 오류
+            TscSsipApiResultError error = new TscSsipApiResultError(TscSsipApiErrorCode.ERROR_INTERNAL_DATA.getCode(), TscSsipApiErrorCode.ERROR_INTERNAL_DATA.getMessage());
+            return new ResponseEntity<>(error, HttpStatus.INTERNAL_SERVER_ERROR);
+        }
+
+        BrokerVo brokerVo = null;
+        try {
+            brokerVo = this.tscSsipApiService.getBrokerInfo(apiToken);
+            if (brokerVo == null) {
+                apiInvokeVo.setError(TscSsipApiErrorCode.NOTFOUND_BROKER_INFO.getCode());
+                log.error("{}", apiInvokeVo.toString());
+                this.tscSsipApiService.insertInvokeHs(apiInvokeVo, true);
+                TscSsipApiResultError error = new TscSsipApiResultError(TscSsipApiErrorCode.NOTFOUND_BROKER_INFO.getCode(), TscSsipApiErrorCode.NOTFOUND_BROKER_INFO.getMessage());
+                return new ResponseEntity<> (error, HttpStatus.NON_AUTHORITATIVE_INFORMATION);
+            }
+        }
+        catch (Exception e) {
+            log.error("getBrokerInfo: {}", e.getMessage());
+            // 데이터베이스 오류
+            TscSsipApiResultError error = new TscSsipApiResultError(TscSsipApiErrorCode.ERROR_INTERNAL_DATA.getCode(), TscSsipApiErrorCode.ERROR_INTERNAL_DATA.getMessage());
+            apiInvokeVo.setError(TscSsipApiErrorCode.ERROR_INTERNAL_DATA.getCode());
+            this.tscSsipApiService.insertInvokeHs(apiInvokeVo, true);
+            return new ResponseEntity<>(error, HttpStatus.INTERNAL_SERVER_ERROR);
+        }
+
+        TscSsipApiResultBrokerInfo result = new TscSsipApiResultBrokerInfo(TscSsipApiErrorCode.SUCCESS.getCode(), TscSsipApiErrorCode.SUCCESS.getMessage());
+        result.setBrokerInfo(brokerVo);
+        result.setCount(1);
+
+        // 이력저장
+        this.tscSsipApiService.insertInvokeHs(apiInvokeVo, true);
+        return new ResponseEntity<>(result, HttpStatus.OK);
+    }
+
+    @GetMapping(value = {SSIP_API_UUID})
+    public String getUUID(){
+        String uid = UUID.randomUUID().toString();
+        uid = uid.replace("-","").toUpperCase();
+        return uid;
+    }
+
+    @PostMapping(value = {SSIP_API_SYSTEM_STATUS}, produces = {"application/json; charset=utf8"})
+    public ResponseEntity<AbstractTscSsipApiResult> registerSystemStatus(@RequestBody SystemStatusDto status, HttpServletRequest request){
+
+        String apiId = SSIP_API_SYSTEM_STATUS;
+        String remoteIP = ApiUtils.getRemoteIP(request);
+        log.debug("{}, {}, {}", apiId, remoteIP, status.toString());
+
+        //명목메모리 사용률 = used / total = ( total - free ) / total
+        //실질메모리 사용률 = used2 / total = ( total - free2[2] ) / total = ( total - free - buffers - cached) / total
+        //free 열의 두번째 행이 실질적인 유휴메모리 용량이다.
+        //[root@localhost1 ~]# free
+        //             total       used       free     shared    buffers     cached
+        //Mem:       1016828     933428      83400      31380      63516     536812
+        //-/+ buffers/cache:     333100     683728
+        //Swap:       524284       1984     522300
+        //전체 용량 = 1016828
+        //명목 여유 메모리 = 83400
+        //실질 여유 메모리 = 683728 ( = 83400 + 63516 + 536812 )
+        SystemStatusVo vo = TsiSystemStatusManager.getInstance().get(status.getHostName());
+        if (vo == null) {
+            vo = new SystemStatusVo();
+            vo.setHostName(status.getHostName());
+            TsiSystemStatusManager.getInstance().put(status.getHostName(), vo);
+        }
+        try {
+            vo.setOsType(status.getOsType());
+            vo.setOsName(status.getOsName());
+            vo.setOsType(status.getOsType());
+            vo.setOsVersion(status.getOsVersion());
+            vo.setOsArch(status.getOsArch());
+            vo.setKernelRelease(status.getKernelRelease());
+            vo.setInternalIp(status.getInternalIp());
+            vo.setExternalIp(status.getExternalIp());
+            vo.setSwapMem(status.getSwapMem()); // long
+            vo.setCpuCnt(status.getCpuCnt());
+            vo.setUpTimes(status.getUpTimes());
+
+            vo.setUseCpuRate(status.getUseCpuRate());
+            vo.setTasks(status.getTasks());
+            vo.setThreads(status.getThreads());
+            vo.setLoadAvg(status.getLoadAvg());
+
+            // disk
+            if (status.getTotalDisk() > 0) {
+                double dblTotal = status.getTotalDisk();
+                double dblUsed = status.getUsedDisk();
+                status.setUseDiskRate((float)((dblUsed/dblTotal)*100.0));
+                if (status.getUseDiskRate() > 100.0) {
+                    status.setUseDiskRate(100);
+                }
+                status.setTotalDisk(status.getTotalDisk()/1024);    // KB => MB
+
+                vo.setTotalDisk((float)(dblTotal/1024/1024));
+                vo.setUseDisk((float)(dblUsed/1024/1024));
+                vo.setUseDiskRate(status.getUseDiskRate());
+            }
+            // swap
+            float total;
+            float used;
+            if (status.getSwapMem() > 0 && status.getUsedSwap() > 0) {
+                total = (float)status.getSwapMem();
+                used = (float)status.getUsedSwap();
+                status.setUseSwapRate((float)((used/total) * 100.0));
+                if (status.getUsedSwap() > 100.0) {
+                    status.setUseSwapRate(100);
+                }
+            }
+
+            // memory
+            if (status.getTotalMem() > 0) {
+                total = (float)status.getTotalMem();
+                // 명목
+                used = total - status.getFreeMem();
+                status.setUseMemRate((float)((used/total) * 100.0));       // calculate
+                if (status.getUseMemRate() > 100.0) {
+                    status.setUseMemRate(100);
+                }
+                // 실질
+                used = total - status.getFreeMem() - status.getCacheMem();
+                status.setRealMemRate((float)((used/total) * 100.0));       // calculate
+                if (status.getRealMemRate() > 100.0) {
+                    status.setRealMemRate(100);
+                }
+
+                vo.setTotalMem(total/1024);
+                vo.setUseMem(used/1024);
+                vo.setUseMemRate(status.getRealMemRate());
+            }
+            vo.setUpdateTm(System.currentTimeMillis());
+            vo.setUpdate(true);
+
+            //this.tscSsipApiService.insertSystemStatusHs(vo);
+            //this.tscSsipApiService.updateSystemInfo(status);
+        }
+        catch(Exception e) {
+            log.error("{}", e.getMessage().toString());
+            TscSsipApiResultError error = new TscSsipApiResultError(TscSsipApiErrorCode.ERROR_INTERNAL_DATA.getCode(), TscSsipApiErrorCode.ERROR_INTERNAL_DATA.getMessage());
+            return new ResponseEntity<> (error, HttpStatus.INTERNAL_SERVER_ERROR);
+        }
+        TscSsipApiResultSystemStatus result = new TscSsipApiResultSystemStatus(TscSsipApiErrorCode.SUCCESS.getCode(), TscSsipApiErrorCode.SUCCESS.getMessage());
+        result.setResult("ok");
+        return new ResponseEntity<>(result, HttpStatus.OK);
+    }
+
+    @PostMapping(value = {SSIP_API_SYSTEM_STATUS2}, produces = {"application/json; charset=utf8"})
+    public ResponseEntity<AbstractTscSsipApiResult> registerSystemStatus2(@RequestBody SystemStatus2Dto status, HttpServletRequest request){
+
+        String apiId = SSIP_API_SYSTEM_STATUS2;
+        String remoteIP = ApiUtils.getRemoteIP(request);
+        log.debug("{}, {}, {}", apiId, remoteIP, status.toString());
+
+        //명목메모리 사용률 = used / total = ( total - free ) / total
+        //실질메모리 사용률 = used2 / total = ( total - free2[2] ) / total = ( total - free - buffers - cached) / total
+        //free 열의 두번째 행이 실질적인 유휴메모리 용량이다.
+        //[root@localhost1 ~]# free
+        //             total       used       free     shared    buffers     cached
+        //Mem:       1016828     933428      83400      31380      63516     536812
+        //-/+ buffers/cache:     333100     683728
+        //Swap:       524284       1984     522300
+        //전체 용량 = 1016828
+        //명목 여유 메모리 = 83400
+        //실질 여유 메모리 = 683728 ( = 83400 + 63516 + 536812 )
+        SystemStatusVo vo = TsiSystemStatusManager.getInstance().get(status.getHostName());
+        if (vo == null) {
+            vo = new SystemStatusVo();
+            vo.setHostName(status.getHostName());
+            TsiSystemStatusManager.getInstance().put(status.getHostName(), vo);
+        }
+
+        try {
+            // cpu
+            vo.setUseCpuRate(status.getCpuLoad());
+            vo.setLoadAvg(status.getCpuLoad());
+            // disk
+            vo.setUseDiskRate(status.getDisUsage());
+            // memory
+            vo.setUseMemRate(status.getMemoryUsage());
+
+            vo.setUpdateTm(System.currentTimeMillis());
+            vo.setUpdate(true);
+        }
+        catch(Exception e) {
+            log.error("{}", e.getMessage().toString());
+            TscSsipApiResultError error = new TscSsipApiResultError(TscSsipApiErrorCode.ERROR_INTERNAL_DATA.getCode(), TscSsipApiErrorCode.ERROR_INTERNAL_DATA.getMessage());
+            return new ResponseEntity<> (error, HttpStatus.INTERNAL_SERVER_ERROR);
+        }
+        TscSsipApiResultSystemStatus result = new TscSsipApiResultSystemStatus(TscSsipApiErrorCode.SUCCESS.getCode(), TscSsipApiErrorCode.SUCCESS.getMessage());
+        result.setResult("ok");
+        return new ResponseEntity<>(result, HttpStatus.OK);
+    }
+
+    @GetMapping(value = {SSIP_API_KAFKA_TOKEN}, produces = {"application/json; charset=utf8"})
+    public ResponseEntity<AbstractTscSsipApiResult> getKafkaToken(@PathVariable("apiToken") String apiToken, HttpServletRequest request) {
+
+        String apiId = SSIP_API_KAFKA_TOKEN;
+        String remoteIP = ApiUtils.getRemoteIP(request);
+        log.info("{}, {}, {}", apiId, remoteIP, apiToken);
+
+        ApiInvokeVo apiInvokeVo = ApiInvokeVo.builder()
+                .apiId(apiId)
+                .apiToken(apiToken)
+                .ipAddr(remoteIP)
+                .error(TscSsipApiErrorCode.SUCCESS.getCode())
+                .build();
+
+        KafkaAuthorizedVo authorizedVo = null;
+        try {
+            authorizedVo = this.tscSsipApiService.getKafkaAuthorizedInfo(apiToken, remoteIP, true);
+            if (authorizedVo.getErrorCode() != TscSsipApiErrorCode.SUCCESS) {
+                // api token 인증 오류
+                log.error("인증오류: [{}] ==> [{}]: [{}].[{}]" + apiId, remoteIP, apiToken, authorizedVo.getErrorCode(), authorizedVo.getErrorCode().getMessage());
+                apiInvokeVo.setError(authorizedVo.getErrorCode().getCode());
+                this.tscSsipApiService.insertInvokeHs(apiInvokeVo, true);
+                TscSsipApiResultError error = new TscSsipApiResultError(authorizedVo.getErrorCode().getCode(), authorizedVo.getErrorCode().getMessage());
+                return new ResponseEntity<>(error, HttpStatus.UNAUTHORIZED);
+            }
+        }
+        catch (Exception e) {
+            log.error("tscSsipKafkaTokenService: {}", e.getMessage());
+            // 데이터베이스 오류
+            TscSsipApiResultError error = new TscSsipApiResultError(TscSsipApiErrorCode.ERROR_INTERNAL_DATA.getCode(), TscSsipApiErrorCode.ERROR_INTERNAL_DATA.getMessage());
+            apiInvokeVo.setError(TscSsipApiErrorCode.ERROR_INTERNAL_DATA.getCode());
+            this.tscSsipApiService.insertInvokeHs(apiInvokeVo, true);
+            return new ResponseEntity<>(error, HttpStatus.INTERNAL_SERVER_ERROR);
+        }
+
+        KafkaTokenDto token = this.tscSsipKafkaTokenService.generateToken(apiToken, authorizedVo.getBrokerId(), authorizedVo.getBrokerPwd(), "KAFKA");
+        TscSsipApiResultKafkaTokenInfo result = new TscSsipApiResultKafkaTokenInfo(TscSsipApiErrorCode.SUCCESS.getCode(), TscSsipApiErrorCode.SUCCESS.getMessage());
+        result.setAccessToken(token.getToken());
+        result.setCount(1);
+
+        // 이력저장
+        this.tscSsipApiService.insertInvokeHs(apiInvokeVo, true);
+        return new ResponseEntity<>(result, HttpStatus.OK);
+    }
+
+    @PostMapping(value = {SSIP_API_KAFKA_AUTH}, produces = {"application/json; charset=utf8"})
+    public ResponseEntity<AbstractTscSsipApiResult> getKafkaAuth(@RequestBody KafkaTokenAuthDto token, HttpServletRequest request) {
+
+        String apiId = SSIP_API_KAFKA_AUTH;
+        String remoteIP = ApiUtils.getRemoteIP(request);
+        log.info("{}, {}, {}", apiId, remoteIP, token);
+
+        String resultCode = String.valueOf(TscSsipApiErrorCode.SUCCESS.getCode());
+        TscSsipApiResultKafkaAuth result = new TscSsipApiResultKafkaAuth(TscSsipApiErrorCode.SUCCESS.getCode(), TscSsipApiErrorCode.SUCCESS.getMessage());
+
+        ApiInvokeVo apiInvokeVo = ApiInvokeVo.builder()
+                .apiId(apiId)
+                .apiToken(token.getApiToken())
+                .ipAddr(remoteIP)
+                .error(TscSsipApiErrorCode.SUCCESS.getCode())
+                .build();
+
+        KafkaAuthorizedVo authorizedVo = null;
+        try {
+            authorizedVo = this.tscSsipApiService.getKafkaAuthorizedInfo(token.getApiToken(), remoteIP, false);
+            if (authorizedVo.getErrorCode() != TscSsipApiErrorCode.SUCCESS) {
+                // api token 인증 오류
+                log.error("인증오류: [{}] ==> [{}]: [{}].[{}]" + apiId, remoteIP, token.getApiToken(), authorizedVo.getErrorCode(), authorizedVo.getErrorCode().getMessage());
+                apiInvokeVo.setError(authorizedVo.getErrorCode().getCode());
+                this.tscSsipApiService.insertInvokeHs(apiInvokeVo, true);
+                TscSsipApiResultError error = new TscSsipApiResultError(authorizedVo.getErrorCode().getCode(), authorizedVo.getErrorCode().getMessage());
+                return new ResponseEntity<>(error, HttpStatus.UNAUTHORIZED);
+            }
+        }
+        catch (Exception e) {
+            log.error("Exception: {}", e);
+            apiInvokeVo.setError(TscSsipApiErrorCode.ERROR_INTERNAL_DATA.getCode());
+            resultCode = String.valueOf(TscSsipApiErrorCode.ERROR_INTERNAL_DATA.getCode());
+            result.setResult(resultCode);
+            this.tscSsipApiService.insertInvokeHs(apiInvokeVo, true);
+            return new ResponseEntity<>(result, HttpStatus.OK);
+        }
+/*
+        SUCCESS              (0,"요청성공"),
+                UNREGISTERED_APITOKEN(1,"등록되지 않은 API TOKEN"),
+                APITOKEN_EXPIRED     (2,"API TOKEN 유효기간 오류"),
+                DENIED_IPADDR        (3,"접근불가 IP Address"),
+                NOTFOUND_BROKER_INFO (4,"접속 가능한 브로커 정보가 없음"),
+                NOTFOUND_URL         (5,"잘못된 URL 경로"),
+                ERROR_INTERNAL_DATA  (6,"내부 데이터 오류"),
+                NOT_AVAILABLE        (7,"현재 사용할수 없음"),       // useyn='N'
+                PENDING_REGISTRATION (8,"등록 대기 중");             // Navi Device, 등록 대기중 useyn='Y', state='R'
+*/
+
+        try {
+            log.info("token.getAccessToken(): {}", token.getAccessToken());
+            if (token.getAccessToken() != null && this.tscSsipKafkaTokenService.verifyToken(token.getAccessToken())) {
+                KafkaTokenDto tokenDto = this.tscSsipKafkaTokenService.decode(token.getAccessToken());
+                log.info("tokenDto: {}", tokenDto);
+                if (tokenDto.getApiToken() != null && tokenDto.getApiToken().equals(token.getApiToken())) {
+                    log.info("getApiToken: [{}] -- [{}]", tokenDto.getApiToken(), token.getApiToken());
+                    if (tokenDto.getUid() == null || tokenDto.getPwd() == null || !tokenDto.getUid().equals(authorizedVo.getBrokerId()) || !tokenDto.getPwd().equals(authorizedVo.getBrokerPwd())) {
+                        log.info("tokenDto: {}", tokenDto);
+                        apiInvokeVo.setError(TscSsipApiErrorCode.NOTFOUND_URL.getCode());
+                        resultCode = String.valueOf(TscSsipApiErrorCode.NOTFOUND_URL.getCode());
+                    }
+                }
+                else {
+                    log.info("error getApiToken: [{}] -- [{}]", tokenDto.getApiToken(), token.getApiToken());
+                    apiInvokeVo.setError(TscSsipApiErrorCode.UNREGISTERED_APITOKEN.getCode());
+                    resultCode = String.valueOf(TscSsipApiErrorCode.UNREGISTERED_APITOKEN.getCode());
+                }
+            }
+            else {
+                log.info("{}", token);
+                apiInvokeVo.setError(TscSsipApiErrorCode.APITOKEN_EXPIRED.getCode());
+                resultCode = String.valueOf(TscSsipApiErrorCode.APITOKEN_EXPIRED.getCode());
+            }
+        }
+        catch (Exception e) {
+            log.error("Exception: {}", e.getMessage());
+            apiInvokeVo.setError(TscSsipApiErrorCode.ERROR_INTERNAL_DATA.getCode());
+            resultCode = String.valueOf(TscSsipApiErrorCode.ERROR_INTERNAL_DATA.getCode());
+        }
+
+        result.setResult(resultCode);
+
+        // 이력저장
+        this.tscSsipApiService.insertInvokeHs(apiInvokeVo, true);
+        return new ResponseEntity<>(result, HttpStatus.OK);
+    }
+
+}

+ 215 - 0
src/main/java/com/tsi/api/server/controller/TscSsipAppController.java

@@ -0,0 +1,215 @@
+package com.tsi.api.server.controller;
+
+import com.tsi.api.server.controller.result.*;
+import com.tsi.api.server.error.TscSsipApiErrorCode;
+import com.tsi.api.server.service.TscSsipAppService;
+import com.tsi.api.server.util.ApiUtils;
+import com.tsi.api.server.vo.ApiInvokeVo;
+import com.tsi.api.server.vo.DeviceInfo;
+import com.tsi.api.server.vo.VersionVo;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.core.io.InputStreamResource;
+import org.springframework.core.io.Resource;
+import org.springframework.http.ContentDisposition;
+import org.springframework.http.HttpHeaders;
+import org.springframework.http.HttpStatus;
+import org.springframework.http.ResponseEntity;
+import org.springframework.web.bind.annotation.*;
+
+import javax.servlet.http.HttpServletRequest;
+import java.io.File;
+import java.io.IOException;
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.nio.file.Paths;
+import java.util.List;
+import java.util.UUID;
+
+@Slf4j
+@RestController
+public class TscSsipAppController {
+
+    private final String NAVI_NODE_STATUS     = "/app/nodes/{deviceId}";
+    private final String NAVI_DEVICE_AUTH     = "/app/auth/{deviceId}";
+    private final String NAVI_DEVICE_REGISTER = "/app/devices";
+    private final String NAVI_DOWNLOADS       = "/app/download/{fileName}";
+    private final String NAVI_API_UUID        = "/app/uuid";
+    private final String NAVI_SSL       = "/.well-known/pki-validation/{fileName}";
+
+    private final TscSsipAppService tscNaviApiService;
+
+    public TscSsipAppController(TscSsipAppService tscNaviApiService) {
+        this.tscNaviApiService = tscNaviApiService;
+    }
+
+    @GetMapping(value = {NAVI_NODE_STATUS}, produces = {"application/json; charset=utf8"})
+    public ResponseEntity<AbstractTscSsipApiResult> getNodeStatus(@PathVariable("deviceId") String deviceId, HttpServletRequest request) {
+
+        String apiId = NAVI_NODE_STATUS;
+        String remoteIP = ApiUtils.getRemoteIP(request);
+        log.info("{}, {}, {}", apiId, remoteIP, deviceId);
+
+        ApiInvokeVo apiInvokeVo = ApiInvokeVo.builder()
+                .apiId(apiId)
+                .apiToken(deviceId)
+                .ipAddr(remoteIP)
+                .error(TscSsipApiErrorCode.SUCCESS.getCode())
+                .build();
+
+        try {
+            TscSsipApiErrorCode authorizedInfo = this.tscNaviApiService.getAuthorizedInfo(apiId, deviceId, remoteIP);
+            if (authorizedInfo != TscSsipApiErrorCode.SUCCESS) {
+                // api token 인증 오류
+                log.error("인증오류: [{}] ==> [{}]: [{}].[{}]" + apiId, remoteIP, deviceId, authorizedInfo.getCode(), authorizedInfo.getMessage());
+                apiInvokeVo.setError(authorizedInfo.getCode());
+                this.tscNaviApiService.insertInvokeHs(apiInvokeVo, false);
+                TscSsipApiResultError error = new TscSsipApiResultError(authorizedInfo.getCode(), authorizedInfo.getMessage());
+                return new ResponseEntity<> (error, HttpStatus.UNAUTHORIZED);
+            }
+        }
+        catch (Exception e) {
+            log.error("getNodeStatus: {}", e.getMessage());
+            // 데이터베이스 오류
+            TscSsipApiResultError error = new TscSsipApiResultError(TscSsipApiErrorCode.ERROR_INTERNAL_DATA.getCode(), TscSsipApiErrorCode.ERROR_INTERNAL_DATA.getMessage());
+            return new ResponseEntity<>(error, HttpStatus.INTERNAL_SERVER_ERROR);
+        }
+
+
+        TscNaviApiResultNodeStatusInfo result = new TscNaviApiResultNodeStatusInfo(TscSsipApiErrorCode.SUCCESS.getCode(), TscSsipApiErrorCode.SUCCESS.getMessage());
+        result.setStatusList(tscNaviApiService.getNodeStatusList());
+        result.setCount(result.getStatusList().size());
+
+        // 이력저장
+        this.tscNaviApiService.insertInvokeHs(apiInvokeVo, false);
+        log.info("NodeStatus: {}, {}", deviceId, result.toString());
+        return new ResponseEntity<>(result, HttpStatus.OK);
+    }
+
+    @GetMapping(value = {NAVI_DEVICE_AUTH}, produces = {"application/json; charset=utf8"})
+    public ResponseEntity<AbstractTscSsipApiResult> getDeviceAuthInfo(@PathVariable("deviceId") String deviceId, HttpServletRequest request) {
+
+        String apiId = NAVI_DEVICE_AUTH;
+        String remoteIP = ApiUtils.getRemoteIP(request);
+        log.info("{}, {}, {}", apiId, remoteIP, deviceId);
+
+        ApiInvokeVo apiInvokeVo = ApiInvokeVo.builder()
+                .apiId(apiId)
+                .apiToken(deviceId)
+                .ipAddr(remoteIP)
+                .error(TscSsipApiErrorCode.SUCCESS.getCode())
+                .build();
+
+        TscSsipApiErrorCode authorizedInfo = null;
+        TscNaviApiResultAuthInfo result = null;
+        try {
+            authorizedInfo = this.tscNaviApiService.getAuthorizedInfo(apiId, deviceId, remoteIP);
+        /*if (authorizedInfo == TscSsipApiErrorCode.UNREGISTERED_APITOKEN) {
+            // api token 인증 오류
+            log.error("인증오류: [{}] ==> [{}]: [{}].[{}]" + apiId, remoteIP, deviceId, authorizedInfo.getCode(), authorizedInfo.getMessage());
+            apiInvokeVo.setError(authorizedInfo.getCode());
+            this.tscNaviApiService.insertInvokeHs(apiInvokeVo);
+            TscSsipApiResultError error = new TscSsipApiResultError(authorizedInfo.getCode(), authorizedInfo.getMessage());
+            return new ResponseEntity<> (error, HttpStatus.UNAUTHORIZED);
+        }*/
+
+            result = new TscNaviApiResultAuthInfo(authorizedInfo.getCode(), authorizedInfo.getMessage());
+            if (authorizedInfo == TscSsipApiErrorCode.SUCCESS) {
+                List<VersionVo> versionList = this.tscNaviApiService.getVersion();
+                log.info("version list: {}", versionList.toString());
+                result.setVersions(versionList);
+            }
+        }
+        catch (Exception e) {
+            log.error("getDeviceAuthInfo: {}", e.getMessage());
+            // 데이터베이스 오류
+            TscSsipApiResultError error = new TscSsipApiResultError(TscSsipApiErrorCode.ERROR_INTERNAL_DATA.getCode(), TscSsipApiErrorCode.ERROR_INTERNAL_DATA.getMessage());
+            return new ResponseEntity<>(error, HttpStatus.INTERNAL_SERVER_ERROR);
+        }
+
+        // 이력저장
+        this.tscNaviApiService.insertInvokeHs(apiInvokeVo, true);
+        log.info("Auth: {}, {}", deviceId, result.toString());
+        return new ResponseEntity<>(result, HttpStatus.OK);
+    }
+
+    @PostMapping(value = {NAVI_DEVICE_REGISTER}, produces = {"application/json; charset=utf8"})
+    public ResponseEntity<AbstractTscSsipApiResult> registerDevice(@RequestBody DeviceInfo deviceInfo,  HttpServletRequest request){
+        String apiId = NAVI_DEVICE_REGISTER;
+        String remoteIP = ApiUtils.getRemoteIP(request);
+        log.info("{}, {}, {}", apiId, remoteIP, deviceInfo.toString());
+
+        try {
+            this.tscNaviApiService.registerDevice(deviceInfo);
+        }
+        catch(Exception e) {
+            log.error("registerDevice: {}", e.getMessage().toString());
+            TscSsipApiResultError error = new TscSsipApiResultError(TscSsipApiErrorCode.ERROR_INTERNAL_DATA.getCode(), TscSsipApiErrorCode.ERROR_INTERNAL_DATA.getMessage());
+            return new ResponseEntity<> (error, HttpStatus.INTERNAL_SERVER_ERROR);
+        }
+        TscNaviApiResultDeviceRegisterInfo result = new TscNaviApiResultDeviceRegisterInfo(TscSsipApiErrorCode.SUCCESS.getCode(), TscSsipApiErrorCode.SUCCESS.getMessage());
+        result.setResult("ok");
+        return new ResponseEntity<>(result, HttpStatus.OK);
+    }
+
+    @GetMapping(value = {NAVI_DOWNLOADS})
+    public ResponseEntity<Resource> download(@PathVariable("fileName") String fileName, HttpServletRequest request) {
+        String apiId = NAVI_DOWNLOADS;
+        String remoteIP = ApiUtils.getRemoteIP(request);
+        log.info("{}, {}, {}", apiId, remoteIP, fileName);
+
+        try {
+            String separator = System.getProperty("file.separator");
+            String fileFullName = System.getProperty("user.dir")+separator+"downloads"+separator+fileName;
+            Path path = Paths.get(fileFullName);
+            File file2Upload = path.toFile();
+            String contentType = "application/download";
+            //String contentType = Files.probeContentType(path);
+            Resource resource = new InputStreamResource(Files.newInputStream(path));
+            HttpHeaders headers = new HttpHeaders();
+            headers.add(HttpHeaders.CONTENT_TYPE, contentType);
+            headers.setContentLength(file2Upload.length());
+            headers.setContentDisposition(ContentDisposition.parse("attachment;" + " filename=\"" + fileName + "\";"));
+
+            return new ResponseEntity<>(resource, headers, HttpStatus.OK);
+        }
+        catch (IOException e) {
+            log.error("download: {}", e.toString());
+            return new ResponseEntity<> (HttpStatus.INTERNAL_SERVER_ERROR);
+        }
+    }
+    @GetMapping(value = {NAVI_SSL})
+    public ResponseEntity<Resource> downloadssl(@PathVariable("fileName") String fileName, HttpServletRequest request) {
+        String apiId = NAVI_SSL;
+        String remoteIP = ApiUtils.getRemoteIP(request);
+        log.info("{}, {}, {}", apiId, remoteIP, fileName);
+
+        try {
+            String separator = System.getProperty("file.separator");
+            String fileFullName = System.getProperty("user.dir")+separator+".well-known"+separator+"pki-validation"+separator+fileName;
+            Path path = Paths.get(fileFullName);
+            File file2Upload = path.toFile();
+            String contentType = "application/download";
+            //String contentType = Files.probeContentType(path);
+            Resource resource = new InputStreamResource(Files.newInputStream(path));
+            HttpHeaders headers = new HttpHeaders();
+            headers.add(HttpHeaders.CONTENT_TYPE, contentType);
+            headers.setContentLength(file2Upload.length());
+            headers.setContentDisposition(ContentDisposition.parse("attachment;" + " filename=\"" + fileName + "\";"));
+
+            return new ResponseEntity<>(resource, headers, HttpStatus.OK);
+        }
+        catch (IOException e) {
+            log.error("download: {}", e.toString());
+            return new ResponseEntity<> (HttpStatus.INTERNAL_SERVER_ERROR);
+        }
+
+    }
+
+    @GetMapping(value = {NAVI_API_UUID})
+    public String getUUID(){
+        String uid = UUID.randomUUID().toString();
+        uid = uid.replace("-","").toUpperCase();
+        return uid;
+    }
+
+}

+ 13 - 0
src/main/java/com/tsi/api/server/controller/TscSsipTestController.java

@@ -0,0 +1,13 @@
+package com.tsi.api.server.controller;
+
+import org.springframework.web.bind.annotation.GetMapping;
+import org.springframework.web.bind.annotation.RestController;
+
+@RestController
+public class TscSsipTestController {
+
+    @GetMapping("/test")
+    public String index() {
+        return "TSC SSIP API";
+    }
+}

+ 31 - 0
src/main/java/com/tsi/api/server/controller/result/AbstractTscSsipApiResult.java

@@ -0,0 +1,31 @@
+package com.tsi.api.server.controller.result;
+
+import lombok.Getter;
+import lombok.Setter;
+import lombok.ToString;
+
+import java.text.SimpleDateFormat;
+import java.util.Date;
+
+@Getter
+@Setter
+@ToString
+public abstract class AbstractTscSsipApiResult {
+
+    private String timestamp;
+    private int status;
+    private String message;
+    private int count;
+
+    public AbstractTscSsipApiResult(int status, String message) {
+        this.status = status;
+        this.message = message;
+        this.count = 0;
+
+        Date date = new Date();
+        SimpleDateFormat sdf = new java.text.SimpleDateFormat("yyyy/MM/dd HH:mm:ss");
+        sdf.setTimeZone(java.util.TimeZone.getTimeZone("GMT+9"));
+
+        this.timestamp = sdf.format(date);
+    }
+}

+ 29 - 0
src/main/java/com/tsi/api/server/controller/result/TscNaviApiResultAuthInfo.java

@@ -0,0 +1,29 @@
+package com.tsi.api.server.controller.result;
+
+import com.tsi.api.server.vo.VersionVo;
+import lombok.Getter;
+import lombok.Setter;
+import lombok.ToString;
+
+import java.util.List;
+
+@Setter
+@Getter
+@ToString
+public class TscNaviApiResultAuthInfo extends AbstractTscSsipApiResult {
+
+    private static final long serialVersionUID = 1L;
+
+    private List<VersionVo> versions;
+
+    public TscNaviApiResultAuthInfo(int status, String message) {
+        super(status, message);
+        this.versions = null;
+    }
+
+    public TscNaviApiResultAuthInfo(int status, String message, List<VersionVo> versionList) {
+        super(status, message);
+        this.versions = versionList;
+    }
+
+}

+ 26 - 0
src/main/java/com/tsi/api/server/controller/result/TscNaviApiResultDeviceRegisterInfo.java

@@ -0,0 +1,26 @@
+package com.tsi.api.server.controller.result;
+
+import lombok.Getter;
+import lombok.Setter;
+import lombok.ToString;
+
+@Setter
+@Getter
+@ToString
+public class TscNaviApiResultDeviceRegisterInfo extends AbstractTscSsipApiResult {
+
+    private static final long serialVersionUID = 1L;
+
+    String result;
+
+    public TscNaviApiResultDeviceRegisterInfo(int status, String message) {
+        super(status, message);
+        result = "x";
+    }
+
+    public TscNaviApiResultDeviceRegisterInfo(int status, String message, String result) {
+        super(status, message);
+        this.result = result;
+    }
+
+}

+ 29 - 0
src/main/java/com/tsi/api/server/controller/result/TscNaviApiResultNodeStatusInfo.java

@@ -0,0 +1,29 @@
+package com.tsi.api.server.controller.result;
+
+import com.tsi.api.server.vo.NodeStatusVo;
+import lombok.Getter;
+import lombok.Setter;
+import lombok.ToString;
+
+import java.util.List;
+
+@Setter
+@Getter
+@ToString
+public class TscNaviApiResultNodeStatusInfo extends AbstractTscSsipApiResult {
+
+    private static final long serialVersionUID = 1L;
+
+    private List<NodeStatusVo> statusList;
+
+    public TscNaviApiResultNodeStatusInfo(int status, String message) {
+        super(status, message);
+        statusList = null;
+    }
+
+    public TscNaviApiResultNodeStatusInfo(int status, String message, List<NodeStatusVo> statusList) {
+        super(status, message);
+        this.statusList = statusList;
+    }
+
+}

+ 20 - 0
src/main/java/com/tsi/api/server/controller/result/TscSsipApiResultBrokerInfo.java

@@ -0,0 +1,20 @@
+package com.tsi.api.server.controller.result;
+
+import com.tsi.api.server.vo.BrokerVo;
+import lombok.Getter;
+import lombok.Setter;
+import lombok.ToString;
+
+@Setter
+@Getter
+@ToString
+public class TscSsipApiResultBrokerInfo extends AbstractTscSsipApiResult {
+
+    private static final long serialVersionUID = 1L;
+
+    private BrokerVo brokerInfo;
+
+    public TscSsipApiResultBrokerInfo(int resultCode, String resultDesc) {
+        super(resultCode, resultDesc);
+    }
+}

+ 8 - 0
src/main/java/com/tsi/api/server/controller/result/TscSsipApiResultError.java

@@ -0,0 +1,8 @@
+package com.tsi.api.server.controller.result;
+
+public class TscSsipApiResultError extends AbstractTscSsipApiResult {
+
+    public TscSsipApiResultError(int resultCode, String resultDesc) {
+        super(resultCode, resultDesc);
+    }
+}

+ 26 - 0
src/main/java/com/tsi/api/server/controller/result/TscSsipApiResultKafkaAuth.java

@@ -0,0 +1,26 @@
+package com.tsi.api.server.controller.result;
+
+import lombok.Getter;
+import lombok.Setter;
+import lombok.ToString;
+
+@Setter
+@Getter
+@ToString
+public class TscSsipApiResultKafkaAuth extends AbstractTscSsipApiResult {
+
+    private static final long serialVersionUID = 1L;
+
+    private String result;
+
+    public TscSsipApiResultKafkaAuth(int status, String message) {
+        super(status, message);
+        this.result = null;
+    }
+
+    public TscSsipApiResultKafkaAuth(int status, String message, String result) {
+        super(status, message);
+        this.result = result;
+    }
+
+}

+ 26 - 0
src/main/java/com/tsi/api/server/controller/result/TscSsipApiResultKafkaTokenInfo.java

@@ -0,0 +1,26 @@
+package com.tsi.api.server.controller.result;
+
+import lombok.Getter;
+import lombok.Setter;
+import lombok.ToString;
+
+@Setter
+@Getter
+@ToString
+public class TscSsipApiResultKafkaTokenInfo extends AbstractTscSsipApiResult {
+
+    private static final long serialVersionUID = 1L;
+
+    private String accessToken;
+
+    public TscSsipApiResultKafkaTokenInfo(int status, String message) {
+        super(status, message);
+        this.accessToken = null;
+    }
+
+    public TscSsipApiResultKafkaTokenInfo(int status, String message, String jwtToken) {
+        super(status, message);
+        this.accessToken = jwtToken;
+    }
+
+}

+ 29 - 0
src/main/java/com/tsi/api/server/controller/result/TscSsipApiResultNodeInfo.java

@@ -0,0 +1,29 @@
+package com.tsi.api.server.controller.result;
+
+import com.tsi.api.server.vo.NodeVo;
+import lombok.Getter;
+import lombok.Setter;
+import lombok.ToString;
+
+import java.util.List;
+
+@Setter
+@Getter
+@ToString
+public class TscSsipApiResultNodeInfo extends AbstractTscSsipApiResult {
+
+    private static final long serialVersionUID = 1L;
+
+    private List<NodeVo> nodes;
+
+    public TscSsipApiResultNodeInfo(int status, String message) {
+        super(status, message);
+        this.nodes = null;
+    }
+
+    public TscSsipApiResultNodeInfo(int status, String message, List<NodeVo> nodeList) {
+        super(status, message);
+        this.nodes = nodeList;
+    }
+
+}

+ 26 - 0
src/main/java/com/tsi/api/server/controller/result/TscSsipApiResultSystemStatus.java

@@ -0,0 +1,26 @@
+package com.tsi.api.server.controller.result;
+
+import lombok.Getter;
+import lombok.Setter;
+import lombok.ToString;
+
+@Setter
+@Getter
+@ToString
+public class TscSsipApiResultSystemStatus extends AbstractTscSsipApiResult {
+
+    private static final long serialVersionUID = 1L;
+
+    String result;
+
+    public TscSsipApiResultSystemStatus(int status, String message) {
+        super(status, message);
+        result = "x";
+    }
+
+    public TscSsipApiResultSystemStatus(int status, String message, String result) {
+        super(status, message);
+        this.result = result;
+    }
+
+}

+ 16 - 0
src/main/java/com/tsi/api/server/dto/KafkaTokenAuthDto.java

@@ -0,0 +1,16 @@
+package com.tsi.api.server.dto;
+
+import lombok.Getter;
+import lombok.Setter;
+import lombok.ToString;
+
+@ToString
+@Getter
+@Setter
+public class KafkaTokenAuthDto {
+    private String apiToken;
+    private String accessToken;
+
+    public KafkaTokenAuthDto() {
+    }
+}

+ 24 - 0
src/main/java/com/tsi/api/server/dto/KafkaTokenDto.java

@@ -0,0 +1,24 @@
+package com.tsi.api.server.dto;
+
+import lombok.Getter;
+import lombok.Setter;
+import lombok.ToString;
+
+@ToString
+@Getter
+@Setter
+public class KafkaTokenDto {
+    private String apiToken;
+    private String uid;
+    private String pwd;
+    private String token;
+    private String refreshToken;
+
+    public KafkaTokenDto() {
+    }
+
+    public KafkaTokenDto(String token, String refreshToken) {
+        this.token = token;
+        this.refreshToken = refreshToken;
+    }
+}

+ 12 - 0
src/main/java/com/tsi/api/server/dto/SystemStatus2Dto.java

@@ -0,0 +1,12 @@
+package com.tsi.api.server.dto;
+
+import lombok.Data;
+
+@Data
+public class SystemStatus2Dto {
+    private String hostName;
+
+    private float memoryUsage;
+    private float disUsage;
+    private float cpuLoad;
+}

+ 36 - 0
src/main/java/com/tsi/api/server/dto/SystemStatusDto.java

@@ -0,0 +1,36 @@
+package com.tsi.api.server.dto;
+
+import lombok.Data;
+
+@Data
+public class SystemStatusDto {
+    private String hostName;
+    private String osType;
+    private String osName;
+    private String osVersion;
+    private String osArch;
+    private String kernelRelease;
+    private String internalIp;
+    private String externalIp;
+    private long totalMem;
+    private long swapMem;
+    private long totalDisk;
+    private int cpuCnt;
+    private String upTimes;
+
+    private long usedDisk;
+    private int usedMem;
+    private int freeMem;
+    private int cacheMem;
+    private int availableMem;
+    private int usedSwap;
+    private int tasks;
+    private int threads;
+
+    private float useDiskRate;      // calculate
+    private float useMemRate;       // calculate
+    private float realMemRate;      // calculate
+    private float useSwapRate;      // calculate
+    private float useCpuRate;
+    private float loadAvg;          // load average
+}

+ 39 - 0
src/main/java/com/tsi/api/server/error/TscSsipApiErrorCode.java

@@ -0,0 +1,39 @@
+package com.tsi.api.server.error;
+
+import lombok.Getter;
+
+import java.util.HashMap;
+import java.util.Map;
+
+@Getter
+public enum TscSsipApiErrorCode {
+    SUCCESS              (0,"요청성공"),
+    UNREGISTERED_APITOKEN(1,"등록되지 않은 API TOKEN"),
+    APITOKEN_EXPIRED     (2,"API TOKEN 유효기간 오류"),
+    DENIED_IPADDR        (3,"접근불가 IP Address"),
+    NOTFOUND_BROKER_INFO (4,"접속 가능한 브로커 정보가 없음"),
+    NOTFOUND_URL         (5,"잘못된 URL 경로"),
+    ERROR_INTERNAL_DATA  (6,"내부 데이터 오류"),
+    NOT_AVAILABLE        (7,"현재 사용할수 없음"),       // useyn='N'
+    PENDING_REGISTRATION (8,"등록 대기 중");             // Navi Device, 등록 대기중 useyn='Y', state='R'
+
+    private final int code;
+    private final String message;
+    private static final Map<Integer, TscSsipApiErrorCode> map;
+
+    TscSsipApiErrorCode(int code, String message) {
+        this.code = code;
+        this.message = message;
+    }
+
+    static {
+        map = new HashMap<>();
+        for (TscSsipApiErrorCode e : values())
+            map.put(Integer.valueOf(e.code), e);
+    }
+
+    public static TscSsipApiErrorCode getValue(int code) {
+
+        return map.get(Integer.valueOf(code));
+    }
+}

+ 47 - 0
src/main/java/com/tsi/api/server/error/TscSsipApiErrorResponse.java

@@ -0,0 +1,47 @@
+package com.tsi.api.server.error;
+
+import lombok.Builder;
+import lombok.Getter;
+
+import java.util.ArrayList;
+import java.util.List;
+
+@Getter
+public class TscSsipApiErrorResponse {
+    private final int code;
+    private final String message;
+    private List<FieldError> errors;
+
+    @Builder
+    public TscSsipApiErrorResponse(int code, String message, List<FieldError> errors) {
+        this.code    = code;
+        this.message = message;
+        this.errors  = initErrors(errors);
+    }
+
+    private List<FieldError> initErrors(List<FieldError> errors) {
+        return (errors == null) ? new ArrayList<>() : errors;
+    }
+
+    public static TscSsipApiErrorResponse buildError(TscSsipApiErrorCode errorCode) {
+        return TscSsipApiErrorResponse.builder()
+                .code(errorCode.getCode())
+                .message(errorCode.getMessage())
+                .build();
+    }
+
+    @Getter
+    public static class FieldError {
+        private final String field;
+        private final String value;
+        private final String reason;
+
+        @Builder
+        public FieldError(String field, String value, String reason) {
+            this.field = field;
+            this.value = value;
+            this.reason = reason;
+        }
+    }
+
+}

+ 16 - 0
src/main/java/com/tsi/api/server/exception/AbstractTscSsipApiException.java

@@ -0,0 +1,16 @@
+package com.tsi.api.server.exception;
+
+import com.tsi.api.server.error.TscSsipApiErrorCode;
+
+public class AbstractTscSsipApiException extends RuntimeException {
+
+    private TscSsipApiErrorCode tscSsipApiErrorCode;
+
+    public AbstractTscSsipApiException(TscSsipApiErrorCode tscSsipApiErrorCode) {
+        this.tscSsipApiErrorCode = tscSsipApiErrorCode;
+    }
+
+    public TscSsipApiErrorCode getErrorCode() {
+        return this.tscSsipApiErrorCode;
+    }
+}

+ 10 - 0
src/main/java/com/tsi/api/server/exception/TscSsipApiServiceException.java

@@ -0,0 +1,10 @@
+package com.tsi.api.server.exception;
+
+import com.tsi.api.server.error.TscSsipApiErrorCode;
+
+public class TscSsipApiServiceException extends AbstractTscSsipApiException {
+
+    public TscSsipApiServiceException(TscSsipApiErrorCode tscSsipApiErrorCode) {
+        super(tscSsipApiErrorCode);
+    }
+}

+ 61 - 0
src/main/java/com/tsi/api/server/mybatis/MybatisConfig.java

@@ -0,0 +1,61 @@
+package com.tsi.api.server.mybatis;
+
+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;
+
+@Configuration
+@EnableTransactionManagement
+public class MybatisConfig {
+
+    @Value("${spring.datasource.mybatis.mapper-locations:classpath:mybatis/mapper/**/*.xml}")
+    String mapperLocations;
+
+    @PostConstruct
+    private void init() {
+    }
+
+    @Primary
+    @Bean(name="dataSource")
+    @ConfigurationProperties(prefix="spring.datasource.mybatis")
+    public DataSource dataSource() {
+        return DataSourceBuilder.create().build();
+    }
+
+    @Primary
+    @Bean(name="sqlSessionFactory")
+    public SqlSessionFactory sqlSessionFactoryBean(@Autowired @Qualifier("dataSource") DataSource dataSource, ApplicationContext applicationContext)
+            throws Exception {
+        SqlSessionFactoryBean factoryBean = new SqlSessionFactoryBean();
+        factoryBean.setDataSource(dataSource);
+        //factoryBean.setConfigLocation(applicationContext.getResource("classpath:mybatis/mapper/mybatis-config.xml"));
+        factoryBean.setMapperLocations(applicationContext.getResources(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);
+    }
+}

+ 21 - 0
src/main/java/com/tsi/api/server/mybatis/TscSsipApiMapper.java

@@ -0,0 +1,21 @@
+package com.tsi.api.server.mybatis;
+
+import com.tsi.api.server.dto.SystemStatusDto;
+import com.tsi.api.server.vo.*;
+import org.apache.ibatis.annotations.Mapper;
+import org.apache.ibatis.annotations.Param;
+
+import java.util.List;
+
+@Mapper
+public interface TscSsipApiMapper {
+
+    AuthorizedVo getApiAuthorizedInfo(@Param("apiId") String apiId, @Param("apiToken") String apiToken);
+    KafkaAuthorizedVo getApiKafkaAuthorizedInfo(@Param("apiToken") String apiToken);
+
+    List<NodeVo> getNodeInfoList();
+    BrokerVo getBrokerInfo(@Param("apiToken") String apiToken);
+    int insertInvokeHs(ApiInvokeVo voInvoke);
+    int insertSystemInfo(@Param("info") SystemStatusDto info);
+    int insertSystemStatusHs(@Param("info") SystemStatusVo info);
+}

+ 20 - 0
src/main/java/com/tsi/api/server/mybatis/TscSsipAppMapper.java

@@ -0,0 +1,20 @@
+package com.tsi.api.server.mybatis;
+
+import com.tsi.api.server.mybatis.vo.AlarmConfigVo;
+import com.tsi.api.server.vo.*;
+import org.apache.ibatis.annotations.Mapper;
+import org.apache.ibatis.annotations.Param;
+
+import java.util.List;
+
+@Mapper
+public interface TscSsipAppMapper {
+
+    List<NodeStatusVo> getNodeStatusList();
+    NaviAuthorizedVo getDeviceAuthorizedInfo(@Param("apiId") String apiId, @Param("deviceId") String deviceId);
+    List<VersionVo> getVersion();
+    int registerDevice(DeviceInfo deviceInfo);
+    int insertInvokeHs(ApiInvokeVo voInvoke);
+
+    List<AlarmConfigVo> getAlarmConfig();
+}

+ 21 - 0
src/main/java/com/tsi/api/server/mybatis/TsiDatabaseMapper.java

@@ -0,0 +1,21 @@
+package com.tsi.api.server.mybatis;
+
+import com.tsi.api.server.mybatis.vo.AlarmConfigVo;
+import com.tsi.api.server.mybatis.vo.AlarmOccrVo;
+import com.tsi.api.server.mybatis.vo.ProcessStateVo;
+import org.apache.ibatis.annotations.Mapper;
+import org.apache.ibatis.annotations.Param;
+
+import java.util.List;
+
+@Mapper
+public interface TsiDatabaseMapper {
+
+    List<AlarmConfigVo> getAlarmConfig();
+    int insertAlarmOccrHs(@Param("vo") AlarmOccrVo vo);
+
+    int updateProcessStatusStart(@Param("stts") ProcessStateVo stts);
+    int updateProcessStatusStop(@Param("stts")ProcessStateVo stts);
+    int updateProcessStatusRun(@Param("stts")ProcessStateVo stts);
+
+}

+ 158 - 0
src/main/java/com/tsi/api/server/mybatis/TsiDatabaseService.java

@@ -0,0 +1,158 @@
+package com.tsi.api.server.mybatis;
+
+import com.tsi.api.server.mybatis.vo.AbstractDbmsVo;
+import com.tsi.api.server.mybatis.vo.AlarmConfigVo;
+import com.tsi.api.server.mybatis.vo.AlarmOccrVo;
+import com.tsi.api.server.repository.TsiAlarmManager;
+import com.tsi.api.server.repository.TsiSystemStatusManager;
+import com.tsi.api.server.vo.SystemStatusVo;
+import com.tsi.api.server.vo.TsiAlarmConfigVo;
+import com.tsi.app.common.app.AppUtils;
+import lombok.Getter;
+import lombok.Setter;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.stereotype.Service;
+
+import javax.annotation.PostConstruct;
+import java.text.SimpleDateFormat;
+import java.util.Date;
+import java.util.List;
+import java.util.Map;
+
+@Slf4j
+@Getter
+@Setter
+@Service
+public class TsiDatabaseService {
+
+    private TsiDatabaseMapper tsiDatabaseMapper;
+    private TscSsipApiMapper tscSsipApiMapper;
+
+    public TsiDatabaseService() {
+    }
+
+    @PostConstruct
+    void init() {
+        this.tsiDatabaseMapper = (TsiDatabaseMapper) AppUtils.getBean(TsiDatabaseMapper.class);
+        this.tscSsipApiMapper = (TscSsipApiMapper) AppUtils.getBean(TscSsipApiMapper.class);
+        initDatabase();
+        loadDatabase();
+    }
+
+    public void initDatabase() {
+    }
+
+    public void loadDatabase() {
+    }
+
+    public int loadAlarmConfig() {
+        //long startTime = System.nanoTime();
+
+        List<AlarmConfigVo> objLists = this.tsiDatabaseMapper.getAlarmConfig();
+        for (AlarmConfigVo obj : objLists) {
+            TsiAlarmConfigVo alarm = TsiAlarmManager.getInstance().get(obj.getAlarmCode());
+            if (alarm != null) {
+                alarm.setDesc(obj.getDesc());
+                alarm.setValue(obj.getValue());
+                alarm.setUseYn(obj.getUseYn().equals("Y"));
+            }
+            else {
+                alarm = new TsiAlarmConfigVo();
+                alarm.setAlarmCode(obj.getAlarmCode());
+                alarm.setDesc(obj.getDesc());
+                alarm.setValue(obj.getValue());
+                alarm.setUseYn(obj.getUseYn().equals("Y"));
+                TsiAlarmManager.getInstance().put(obj.getAlarmCode(), alarm);
+            }
+        }
+        //log.info("      loadAlarmConfig: {} EA, {} {}.", objLists.size(), TimeUtils.elapsedTime(startTime), Thread.currentThread().getName());
+        return objLists.size();
+    }
+
+    public int insertAlarmOccrHs(AlarmOccrVo vo) {
+        int res = 0;
+        try {
+            res = this.tsiDatabaseMapper.insertAlarmOccrHs(vo);
+        }
+        catch(Exception e) {
+            log.error("{}", e.getMessage());
+        }
+        return res;
+    }
+    public int updateProcessState(int flag) {
+        int res = 0;
+        try {
+            if (flag == 0) {
+                res = this.tsiDatabaseMapper.updateProcessStatusStart(TsiAlarmManager.getInstance().getProcessStateVo());
+            }
+            else if (flag == 1) {
+                res = this.tsiDatabaseMapper.updateProcessStatusRun(TsiAlarmManager.getInstance().getProcessStateVo());
+            }
+            else {
+                res = this.tsiDatabaseMapper.updateProcessStatusStop(TsiAlarmManager.getInstance().getProcessStateVo());
+            }
+        }
+        catch(Exception e) {
+            log.error("{}", e.getMessage());
+        }
+        return res;
+    }
+    public int updateSystemStatus() {
+        int job = 0;
+        long currTm = System.currentTimeMillis();
+        SimpleDateFormat sdfDate = new SimpleDateFormat("yyyyMMddHHmmss");
+        String clctDt = sdfDate.format(new Date());
+
+        for (Map.Entry<String, SystemStatusVo> obj : TsiSystemStatusManager.getInstance().getMap().entrySet()) {
+            SystemStatusVo status = obj.getValue();
+            status.setClctDt(clctDt);
+            if (status.isUpdate() || (currTm - status.getUpdateTm() <= 20000)) {
+                // 최신이거나 최소 이전 주기 데이터까지 현재시점으로 업데이트 한다.
+                try {
+                    this.tscSsipApiMapper.insertSystemStatusHs(status);
+                    job++;
+                }
+                catch(Exception e) {
+                    log.error("{}", e.getMessage());
+                }
+
+                // 시스템 알람 발생 이력 저장 "SYS_01";     // 시스템 CPU 사용량(%)
+                // 시스템 알람 발생 이력 저장 "SYS_02";     // 시스템 메모리 사용량(%)
+                // 시스템 알람 발생 이력 저장 "SYS_03";     // 시스템 Disk 사용량(%)
+                if (TsiAlarmManager.getInstance().checkAlarm(TsiAlarmConfigVo.SYS_01)) {
+                    TsiAlarmConfigVo config1 = TsiAlarmManager.getInstance().get(TsiAlarmConfigVo.SYS_01);
+                    if (status.getUseCpuRate() > config1.getValue()) {
+                        AlarmOccrVo cpuAlarm = new AlarmOccrVo(AbstractDbmsVo.DBMS_ALARM_OCCR_HS);
+                        cpuAlarm.setAlarmCode(TsiAlarmConfigVo.SYS_01);
+                        cpuAlarm.setAlarmTarget(status.getHostName());
+                        cpuAlarm.setAlarmValue(Float.toString(status.getUseCpuRate()));
+                        this.tsiDatabaseMapper.insertAlarmOccrHs(cpuAlarm);
+                    }
+                }
+                if (TsiAlarmManager.getInstance().checkAlarm(TsiAlarmConfigVo.SYS_02)) {
+                    TsiAlarmConfigVo config2 = TsiAlarmManager.getInstance().get(TsiAlarmConfigVo.SYS_02);
+                    if (status.getUseMemRate() > config2.getValue()) {
+                        AlarmOccrVo memAlarm = new AlarmOccrVo(AbstractDbmsVo.DBMS_ALARM_OCCR_HS);
+                        memAlarm.setAlarmCode(TsiAlarmConfigVo.SYS_02);
+                        memAlarm.setAlarmTarget(status.getHostName());
+                        memAlarm.setAlarmValue(Float.toString(status.getUseCpuRate()));
+                        this.tsiDatabaseMapper.insertAlarmOccrHs(memAlarm);
+                    }
+                }
+                if (TsiAlarmManager.getInstance().checkAlarm(TsiAlarmConfigVo.SYS_03)) {
+                    TsiAlarmConfigVo config3 = TsiAlarmManager.getInstance().get(TsiAlarmConfigVo.SYS_03);
+                    if (status.getUseDiskRate() > config3.getValue()) {
+                        AlarmOccrVo memAlarm = new AlarmOccrVo(AbstractDbmsVo.DBMS_ALARM_OCCR_HS);
+                        memAlarm.setAlarmCode(TsiAlarmConfigVo.SYS_03);
+                        memAlarm.setAlarmTarget(status.getHostName());
+                        memAlarm.setAlarmValue(Float.toString(status.getUseCpuRate()));
+                        this.tsiDatabaseMapper.insertAlarmOccrHs(memAlarm);
+                    }
+                }
+
+            }
+            status.setUpdate(false);
+        }
+        return job;
+    }
+}

+ 26 - 0
src/main/java/com/tsi/api/server/mybatis/vo/AbstractDbmsVo.java

@@ -0,0 +1,26 @@
+package com.tsi.api.server.mybatis.vo;
+
+import com.tsi.app.common.utils.TimeUtils;
+import lombok.Getter;
+import lombok.Setter;
+import lombok.ToString;
+
+@Getter
+@Setter
+@ToString
+public abstract class AbstractDbmsVo {
+
+    public static final int DBMS_NODE_STATUS = 1;
+    public static final int DBMS_TPMS_STAT_1S = 2;
+    public static final int DBMS_KAFKA_TRANS_HS = 3;
+    public static final int DBMS_ALARM_OCCR_HS = 4;
+    public static final int DBMS_PROCESS_STATE = 5;
+
+    protected int dbmsType;
+    protected String eventDt;
+
+    public AbstractDbmsVo(int dbmsType) {
+        this.dbmsType = dbmsType;
+        this.eventDt = TimeUtils.getCurrentTimeString();
+    }
+}

+ 12 - 0
src/main/java/com/tsi/api/server/mybatis/vo/AlarmConfigVo.java

@@ -0,0 +1,12 @@
+package com.tsi.api.server.mybatis.vo;
+
+import lombok.Data;
+
+@Data
+public class AlarmConfigVo {
+
+    private String alarmCode;
+    private String desc;
+    private int    value;
+    private String useYn;
+}

+ 19 - 0
src/main/java/com/tsi/api/server/mybatis/vo/AlarmOccrVo.java

@@ -0,0 +1,19 @@
+package com.tsi.api.server.mybatis.vo;
+
+import lombok.Getter;
+import lombok.Setter;
+import lombok.ToString;
+
+@Getter
+@Setter
+@ToString
+public class AlarmOccrVo extends com.tsi.api.server.mybatis.vo.AbstractDbmsVo {
+
+    protected String alarmCode;
+    protected String alarmTarget;
+    protected String alarmValue;
+
+    public AlarmOccrVo(int dbmsType) {
+        super(dbmsType);
+    }
+}

+ 17 - 0
src/main/java/com/tsi/api/server/mybatis/vo/ProcessStateVo.java

@@ -0,0 +1,17 @@
+package com.tsi.api.server.mybatis.vo;
+
+import lombok.Getter;
+import lombok.Setter;
+import lombok.ToString;
+
+@Getter
+@Setter
+@ToString
+public class ProcessStateVo extends AbstractDbmsVo {
+
+    protected String processId;
+
+    public ProcessStateVo(int dbmsType) {
+        super(dbmsType);
+    }
+}

+ 63 - 0
src/main/java/com/tsi/api/server/repository/TsiAlarmManager.java

@@ -0,0 +1,63 @@
+package com.tsi.api.server.repository;
+
+import com.tsi.api.server.mybatis.vo.AbstractDbmsVo;
+import com.tsi.api.server.mybatis.vo.ProcessStateVo;
+import com.tsi.api.server.vo.TsiAlarmConfigVo;
+import lombok.extern.slf4j.Slf4j;
+
+import java.util.concurrent.ConcurrentHashMap;
+
+@Slf4j
+public class TsiAlarmManager {
+
+    private static TsiAlarmManager _instance = null;
+
+    public static TsiAlarmManager getInstance() {
+        if (_instance == null) {
+            synchronized (TsiAlarmManager.class) {
+                if (_instance == null)
+                    _instance = new TsiAlarmManager();
+            }
+        }
+        return _instance;
+    }
+
+    private ConcurrentHashMap<String, TsiAlarmConfigVo> tsiAlarmConfigMap;
+    private ProcessStateVo processStateVo;
+
+    private TsiAlarmManager() {
+        this.tsiAlarmConfigMap = new ConcurrentHashMap<>();
+        this.processStateVo = new ProcessStateVo(AbstractDbmsVo.DBMS_PROCESS_STATE);
+    }
+
+    public ProcessStateVo getProcessStateVo() {
+        return this.processStateVo;
+    }
+    public TsiAlarmConfigVo get(String key) {
+        return this.tsiAlarmConfigMap.get(key);
+    }
+    public void put(String key, TsiAlarmConfigVo vo) {
+        this.tsiAlarmConfigMap.put(key, vo);
+    }
+
+    public int size() {
+        return this.tsiAlarmConfigMap.size();
+    }
+
+    public boolean containsKey(String key) {
+        return this.tsiAlarmConfigMap.containsKey(key);
+    }
+
+    public boolean checkAlarm(String code) {
+        TsiAlarmConfigVo vo = get(code);
+        return (vo != null && vo.isUseYn());
+    }
+    public boolean isAlarm(String code, int value) {
+        TsiAlarmConfigVo vo = get(code);
+        if (vo != null && vo.isUseYn()) {
+            return (value > vo.getValue());
+        }
+        return false;
+    }
+
+}

+ 47 - 0
src/main/java/com/tsi/api/server/repository/TsiSystemStatusManager.java

@@ -0,0 +1,47 @@
+package com.tsi.api.server.repository;
+
+import com.tsi.api.server.vo.SystemStatusVo;
+import lombok.extern.slf4j.Slf4j;
+
+import java.util.concurrent.ConcurrentHashMap;
+
+@Slf4j
+public class TsiSystemStatusManager {
+
+    private static TsiSystemStatusManager _instance = null;
+
+    public static TsiSystemStatusManager getInstance() {
+        if (_instance == null) {
+            synchronized (TsiSystemStatusManager.class) {
+                if (_instance == null)
+                    _instance = new TsiSystemStatusManager();
+            }
+        }
+        return _instance;
+    }
+
+    private ConcurrentHashMap<String, SystemStatusVo> tsiSystemStatusMap;
+
+    private TsiSystemStatusManager() {
+        this.tsiSystemStatusMap = new ConcurrentHashMap<>();
+    }
+
+    public ConcurrentHashMap<String, SystemStatusVo> getMap() {
+        return this.tsiSystemStatusMap;
+    }
+    public SystemStatusVo get(String key) {
+        return this.tsiSystemStatusMap.get(key);
+    }
+    public void put(String key, SystemStatusVo vo) {
+        this.tsiSystemStatusMap.put(key, vo);
+    }
+
+    public int size() {
+        return this.tsiSystemStatusMap.size();
+    }
+
+    public boolean containsKey(String key) {
+        return this.tsiSystemStatusMap.containsKey(key);
+    }
+
+}

+ 44 - 0
src/main/java/com/tsi/api/server/scheduler/TsiScheduler.java

@@ -0,0 +1,44 @@
+package com.tsi.api.server.scheduler;
+
+import com.tsi.api.server.mybatis.TsiDatabaseService;
+import com.tsi.app.common.utils.TimeUtils;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.scheduling.annotation.Async;
+import org.springframework.scheduling.annotation.EnableScheduling;
+import org.springframework.scheduling.annotation.Scheduled;
+import org.springframework.stereotype.Component;
+
+import javax.annotation.PreDestroy;
+
+@Slf4j
+@EnableScheduling
+@Component
+public class TsiScheduler {
+
+    private final TsiDatabaseService tsiDatabaseService;
+
+    public TsiScheduler(TsiDatabaseService tsiDatabaseService) {
+        this.tsiDatabaseService = tsiDatabaseService;
+    }
+
+    @PreDestroy
+    public void onShutDown() {
+    }
+
+    @Async
+    @Scheduled(cron = "0 * * * * *")  // 1분 주기 작업 실행
+    public void jobLoadDatabase() {
+        long startTime = System.nanoTime();
+        int res = this.tsiDatabaseService.loadAlarmConfig();
+        this.tsiDatabaseService.updateProcessState(1);
+        log.info("      loadAlarmConfig: {} EA, {} {}.", res, TimeUtils.elapsedTime(startTime), Thread.currentThread().getName());
+    }
+
+    @Async
+    @Scheduled(cron = "0/10 * * * * *")  // 10 초 주기 작업 실행
+    public void jobUpdateSystemStatus() {
+        long startTime = System.nanoTime();
+        int res = this.tsiDatabaseService.updateSystemStatus();
+        log.info("jobUpdateSystemStatus: {} EA, {} {}.", res, TimeUtils.elapsedTime(startTime), Thread.currentThread().getName());
+    }
+}

+ 135 - 0
src/main/java/com/tsi/api/server/service/TscSsipApiService.java

@@ -0,0 +1,135 @@
+package com.tsi.api.server.service;
+
+import com.tsi.api.server.dto.SystemStatusDto;
+import com.tsi.api.server.error.TscSsipApiErrorCode;
+import com.tsi.api.server.mybatis.TscSsipApiMapper;
+import com.tsi.api.server.mybatis.TsiDatabaseMapper;
+import com.tsi.api.server.mybatis.vo.AbstractDbmsVo;
+import com.tsi.api.server.mybatis.vo.AlarmOccrVo;
+import com.tsi.api.server.repository.TsiAlarmManager;
+import com.tsi.api.server.vo.*;
+import org.springframework.stereotype.Service;
+import org.springframework.transaction.annotation.Transactional;
+
+import java.text.SimpleDateFormat;
+import java.util.*;
+
+@Service
+@Transactional(rollbackFor = {Exception.class})
+public class TscSsipApiService {
+
+    private final TscSsipApiMapper tscSsipApiMapper;
+    private final TsiDatabaseMapper tsiDatabaseMapper;
+
+    public TscSsipApiService(TscSsipApiMapper tscSsipApiMapper, TsiDatabaseMapper tsiDatabaseMapper) {
+        this.tscSsipApiMapper = tscSsipApiMapper;
+        this.tsiDatabaseMapper = tsiDatabaseMapper;
+    }
+
+    @Transactional(readOnly = true)
+    public List<NodeVo> getNodeInfoList() {
+        return tscSsipApiMapper.getNodeInfoList();
+    }
+
+    @Transactional(readOnly = true)
+    public AuthorizedVo getApiAuthorizedInfo(String apiId, String apiToken) {
+        return tscSsipApiMapper.getApiAuthorizedInfo(apiId, apiToken);
+    }
+
+    public TscSsipApiErrorCode getAuthorizedInfo(String apiId, String apiToken, String remoteIP) {
+
+        AuthorizedVo authorized = getApiAuthorizedInfo(apiId, apiToken);
+        if (authorized == null) {
+            // 등록되지 않은 사용자
+            return TscSsipApiErrorCode.UNREGISTERED_APITOKEN;
+        }
+        else {
+            if (authorized.getIsAuthorized() == 0) {
+                // 키 유효기간이 지남
+                return TscSsipApiErrorCode.APITOKEN_EXPIRED;
+            }
+            else {
+                // ip address 체크
+                String[] ipAddrs = authorized.getAccessIpAddress().replaceAll(" ", "").split(",");
+                Set<String> setIpAddrs = new HashSet<>(Arrays.asList(ipAddrs));
+                if (setIpAddrs.contains("*") || setIpAddrs.contains(remoteIP)) {
+                    return TscSsipApiErrorCode.SUCCESS;
+                }
+            }
+        }
+        return TscSsipApiErrorCode.DENIED_IPADDR;
+    }
+
+    public KafkaAuthorizedVo getApiKafkaAuthorizedInfo(String apiToken) {
+        return tscSsipApiMapper.getApiKafkaAuthorizedInfo(apiToken);
+    }
+    public KafkaAuthorizedVo getKafkaAuthorizedInfo(String apiToken, String remoteIP, boolean checkIpAddr) {
+
+        KafkaAuthorizedVo authorized = getApiKafkaAuthorizedInfo(apiToken);
+        if (authorized == null) {
+            // 등록되지 않은 사용자
+            authorized = new KafkaAuthorizedVo();
+            authorized.setErrorCode(TscSsipApiErrorCode.UNREGISTERED_APITOKEN);
+        }
+        else {
+            if (authorized.getIsAuthorized() == 0) {
+                // 키 유효기간이 지남
+                authorized.setErrorCode(TscSsipApiErrorCode.APITOKEN_EXPIRED);
+            }
+            else {
+                // ip address 체크
+                if (checkIpAddr) {
+                    String[] ipAddrs = authorized.getAccessIpAddress().replaceAll(" ", "").split(",");
+                    Set<String> setIpAddrs = new HashSet<>(Arrays.asList(ipAddrs));
+                    if (setIpAddrs.contains("*") || setIpAddrs.contains(remoteIP)) {
+                        authorized.setErrorCode(TscSsipApiErrorCode.SUCCESS);
+                        return authorized;
+                    }
+                }
+                else {
+                    authorized.setErrorCode(TscSsipApiErrorCode.SUCCESS);
+                    return authorized;
+                }
+            }
+        }
+        authorized.setErrorCode(TscSsipApiErrorCode.DENIED_IPADDR);
+        return authorized;
+    }
+
+    public BrokerVo getBrokerInfo(String apiToken) {
+        return tscSsipApiMapper.getBrokerInfo(apiToken);
+    }
+
+    public int insertInvokeHs(ApiInvokeVo invokeVo, boolean isAlarm) {
+        Date date = new Date();
+        SimpleDateFormat sdf = new java.text.SimpleDateFormat("yyyy/MM/dd HH:mm:ss");
+        sdf.setTimeZone(java.util.TimeZone.getTimeZone("GMT+9"));
+        invokeVo.setEventDt(sdf.format(date));
+        if (isAlarm) {
+            TsiAlarmConfigVo alarmConfig = null;
+            String alarmCode = TsiAlarmConfigVo.API_01;
+            if (invokeVo.getApiId().contains("kafka")) {
+                alarmConfig = TsiAlarmManager.getInstance().get(TsiAlarmConfigVo.KAFKA_03);
+                alarmCode = TsiAlarmConfigVo.KAFKA_03;
+            }
+            else {
+                alarmConfig = TsiAlarmManager.getInstance().get(TsiAlarmConfigVo.API_01);
+            }
+            if (alarmConfig != null) {
+                AlarmOccrVo alarm = new AlarmOccrVo(AbstractDbmsVo.DBMS_ALARM_OCCR_HS);
+                alarm.setAlarmCode(alarmCode);
+                alarm.setAlarmTarget(invokeVo.getApiId());
+                alarm.setAlarmValue(invokeVo.getApiToken() + ", " + String.valueOf(invokeVo.getError()));
+                tsiDatabaseMapper.insertAlarmOccrHs(alarm);
+            }
+        }
+        return tscSsipApiMapper.insertInvokeHs(invokeVo);
+    }
+
+    public int updateSystemInfo(SystemStatusDto info){
+        return tscSsipApiMapper.insertSystemInfo(info);
+    }
+    public int insertSystemStatusHs(SystemStatusVo info){
+        return tscSsipApiMapper.insertSystemStatusHs(info);
+    }
+}

+ 91 - 0
src/main/java/com/tsi/api/server/service/TscSsipAppService.java

@@ -0,0 +1,91 @@
+package com.tsi.api.server.service;
+
+import com.tsi.api.server.error.TscSsipApiErrorCode;
+import com.tsi.api.server.mybatis.TscSsipAppMapper;
+import com.tsi.api.server.mybatis.TsiDatabaseMapper;
+import com.tsi.api.server.mybatis.vo.AbstractDbmsVo;
+import com.tsi.api.server.mybatis.vo.AlarmOccrVo;
+import com.tsi.api.server.repository.TsiAlarmManager;
+import com.tsi.api.server.vo.*;
+import com.tsi.app.common.app.AppUtils;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.stereotype.Service;
+import org.springframework.transaction.annotation.Transactional;
+
+import java.text.SimpleDateFormat;
+import java.util.Date;
+import java.util.List;
+import java.util.TimeZone;
+
+@Slf4j
+@Service
+@Transactional(rollbackFor = {Exception.class})
+public class TscSsipAppService {
+
+    private final TscSsipAppMapper tscNaviApiMapper;
+    private final TsiDatabaseMapper tsiDatabaseMapper;
+
+    public TscSsipAppService(TsiDatabaseMapper tsiDatabaseMapper) {
+        this.tsiDatabaseMapper = tsiDatabaseMapper;
+        this.tscNaviApiMapper = (TscSsipAppMapper) AppUtils.getBean(TscSsipAppMapper.class);
+    }
+
+    @Transactional(readOnly = true)
+    public List<NodeStatusVo> getNodeStatusList() {
+        return tscNaviApiMapper.getNodeStatusList();
+    }
+
+    @Transactional(readOnly = true)
+    public NaviAuthorizedVo getApiAuthorizedInfo(String apiId, String deviceId) {
+        return tscNaviApiMapper.getDeviceAuthorizedInfo(apiId, deviceId);
+    }
+
+    public TscSsipApiErrorCode getAuthorizedInfo(String apiId, String deviceId, String remoteIP) {
+
+        NaviAuthorizedVo authorized = getApiAuthorizedInfo(apiId, deviceId);
+        if (authorized == null) {
+            // 등록되지 않은 사용자
+            return TscSsipApiErrorCode.UNREGISTERED_APITOKEN;
+        }
+
+        log.info("{}", authorized.toString());
+        if (!authorized.getUseYn().equals("Y")) {
+            // 사용하지 않음으로 등록되어 있는 경우. 현재 사용할 수 없습니다. 관리자에게 문의하십시요.
+            return TscSsipApiErrorCode.NOT_AVAILABLE;
+        }
+        if (!authorized.getState().equals("C")) {
+            // 최초 디바이스 등록후 관리자가 확인하여 등록하지 않은 상태
+            return TscSsipApiErrorCode.PENDING_REGISTRATION;
+        }
+        if (!authorized.getExpired().equals("N")) {
+            // 유효기간이 지남
+            return TscSsipApiErrorCode.APITOKEN_EXPIRED;
+        }
+        return TscSsipApiErrorCode.SUCCESS;
+    }
+
+    public int registerDevice(DeviceInfo deviceInfo) {
+        return tscNaviApiMapper.registerDevice(deviceInfo);
+    }
+    public List<VersionVo> getVersion() {
+        return tscNaviApiMapper.getVersion();
+    }
+    public int insertInvokeHs(ApiInvokeVo invokeVo, boolean isAlarm) {
+        Date date = new Date();
+        SimpleDateFormat sdf = new SimpleDateFormat("yyyy/MM/dd HH:mm:ss");
+        sdf.setTimeZone(TimeZone.getTimeZone("GMT+9"));
+        invokeVo.setEventDt(sdf.format(date));
+        if (isAlarm) {
+            TsiAlarmConfigVo alarmConfig = TsiAlarmManager.getInstance().get(TsiAlarmConfigVo.API_01);
+            if (alarmConfig != null) {
+                AlarmOccrVo alarm = new AlarmOccrVo(AbstractDbmsVo.DBMS_ALARM_OCCR_HS);
+                alarm.setAlarmCode(TsiAlarmConfigVo.API_01);
+                alarm.setAlarmTarget(invokeVo.getApiId());
+                alarm.setAlarmValue(invokeVo.getApiToken() + ", " + String.valueOf(invokeVo.getError()));
+                tsiDatabaseMapper.insertAlarmOccrHs(alarm);
+            }
+        }
+        return tscNaviApiMapper.insertInvokeHs(invokeVo);
+    }
+
+}

+ 88 - 0
src/main/java/com/tsi/api/server/service/TscSsipKafkaTokenService.java

@@ -0,0 +1,88 @@
+package com.tsi.api.server.service;
+
+import com.tsi.api.server.dto.KafkaTokenDto;
+import io.jsonwebtoken.Claims;
+import io.jsonwebtoken.Jws;
+import io.jsonwebtoken.Jwts;
+import io.jsonwebtoken.SignatureAlgorithm;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.stereotype.Service;
+
+import javax.annotation.PostConstruct;
+import java.util.Base64;
+import java.util.Date;
+
+@Slf4j
+@Service
+public class TscSsipKafkaTokenService {
+
+    private String secretKey = "kafka-tsc-secret-key";
+
+    @PostConstruct
+    protected void init() {
+        log.info("************************************************ before: {}", this.secretKey);
+        this.secretKey = Base64.getEncoder().encodeToString(this.secretKey.getBytes());
+        log.info("************************************************ -after: {}", this.secretKey);
+    }
+
+    // Access Token create
+    public KafkaTokenDto generateToken(String apiToken, String uid, String pwd, String role) {
+        long tokenPeriod = 1000L * 60L * 10L;                       // 10분
+        long refreshPeriod = 1000L * 60L * 60L * 24L * 30L * 3L;    // 3주
+
+        Claims claims = Jwts.claims().setId(uid).setSubject(pwd);
+        claims.put("role", role);
+        claims.put("apiToken", apiToken);
+
+        Date now = new Date();
+        return new KafkaTokenDto(
+                Jwts.builder()
+                        .setClaims(claims)
+                        .setIssuedAt(now)
+                        .setExpiration(new Date(now.getTime() + tokenPeriod))
+                        .signWith(SignatureAlgorithm.HS256, this.secretKey)
+                        .compact(),
+                Jwts.builder()
+                        .setClaims(claims)
+                        .setIssuedAt(now)
+                        .setExpiration(new Date(now.getTime() + refreshPeriod))
+                        .signWith(SignatureAlgorithm.HS256, this.secretKey)
+                        .compact());
+    }
+
+    public KafkaTokenDto decode(String token) {
+        try {
+            Jws<Claims> claims = Jwts.parser()
+                    .setSigningKey(this.secretKey)
+                    .parseClaimsJws(token);
+
+            KafkaTokenDto kafkaTokenDto = new KafkaTokenDto();
+            kafkaTokenDto.setApiToken((String) claims.getBody().get("apiToken"));
+            kafkaTokenDto.setUid(claims.getBody().getId());
+            kafkaTokenDto.setPwd(claims.getBody().getSubject());
+
+            //log.info("{}", claims.toString());
+            return kafkaTokenDto;
+        }
+        catch (Exception e) {
+            return null;
+        }
+    }
+    public boolean verifyToken(String token) {
+        try {
+            Jws<Claims> claims = Jwts.parser()
+                    .setSigningKey(this.secretKey)
+                    .parseClaimsJws(token);
+            return claims.getBody()
+                    .getExpiration()
+                    .after(new Date());
+        }
+        catch (Exception e) {
+            return false;
+        }
+    }
+
+    public String getUid(String token) {
+        return Jwts.parser().setSigningKey(this.secretKey).parseClaimsJws(token).getBody().getSubject();
+    }
+}

+ 36 - 0
src/main/java/com/tsi/api/server/util/ApiUtils.java

@@ -0,0 +1,36 @@
+package com.tsi.api.server.util;
+
+import javax.servlet.http.HttpServletRequest;
+
+public class ApiUtils {
+
+    public static String getRemoteIP(HttpServletRequest request) {
+        if (request == null) {
+            return "";
+        }
+
+        String ipAddr = request.getHeader("X-FORWARDED-FOR");
+
+        // proxy 환경일 경우
+        if (ipAddr == null || ipAddr.length() == 0) {
+            ipAddr = request.getHeader("Proxy-Client-IP");
+        }
+
+        // 웹로직 서버일 경우
+        if (ipAddr == null || ipAddr.length() == 0) {
+            ipAddr = request.getHeader("WL-Proxy-Client-IP");
+        }
+
+        // 기타
+        if (ipAddr == null || ipAddr.length() == 0) {
+            ipAddr = request.getRemoteAddr() ;
+        }
+
+        //-Djava.net.preferIPv4Stack=true
+        if (ipAddr.equals("0:0:0:0:0:0:0:1"))   //==> ipv6 <== default
+        {
+            ipAddr = "127.0.0.1";   //==> localhost
+        }
+        return ipAddr;
+    }
+}

+ 16 - 0
src/main/java/com/tsi/api/server/vo/ApiInvokeVo.java

@@ -0,0 +1,16 @@
+package com.tsi.api.server.vo;
+
+import lombok.*;
+
+@Data
+@Builder
+@AllArgsConstructor
+@NoArgsConstructor(access = AccessLevel.PROTECTED)
+public class ApiInvokeVo {
+
+    String apiId;
+    String apiToken;
+    String ipAddr;
+    String eventDt;
+    int error;
+}

+ 9 - 0
src/main/java/com/tsi/api/server/vo/AuthorizedVo.java

@@ -0,0 +1,9 @@
+package com.tsi.api.server.vo;
+
+import lombok.Data;
+
+@Data
+public class AuthorizedVo {
+    private String accessIpAddress;
+    private int isAuthorized;
+}

+ 11 - 0
src/main/java/com/tsi/api/server/vo/BrokerVo.java

@@ -0,0 +1,11 @@
+package com.tsi.api.server.vo;
+
+import lombok.Data;
+
+@Data
+public class BrokerVo {
+    private String ipAddr;  // 브로커 서버 IP주소
+    private int    port;    // 브로커 서버 포트번호
+    private String id;      // 브로커 서버 접속 ID
+    private String pwd;     // 브로커 서버 접속 패스워드
+}

+ 12 - 0
src/main/java/com/tsi/api/server/vo/DeviceInfo.java

@@ -0,0 +1,12 @@
+package com.tsi.api.server.vo;
+
+import lombok.Data;
+
+@Data
+public class DeviceInfo {
+    private String deviceId;
+    private String company;
+    private String manager;
+    private String phone;
+    private String email;
+}

+ 13 - 0
src/main/java/com/tsi/api/server/vo/KafkaAuthorizedVo.java

@@ -0,0 +1,13 @@
+package com.tsi.api.server.vo;
+
+import com.tsi.api.server.error.TscSsipApiErrorCode;
+import lombok.Data;
+
+@Data
+public class KafkaAuthorizedVo {
+    private String accessIpAddress;
+    private int isAuthorized;
+    private String brokerId;
+    private String brokerPwd;
+    private TscSsipApiErrorCode errorCode;
+}

+ 13 - 0
src/main/java/com/tsi/api/server/vo/NaviAuthorizedVo.java

@@ -0,0 +1,13 @@
+package com.tsi.api.server.vo;
+
+import lombok.Data;
+import lombok.ToString;
+
+@ToString
+@Data
+public class NaviAuthorizedVo {
+    private String accessIpAddress;
+    private String state;
+    private String useYn;
+    private String expired;
+}

+ 14 - 0
src/main/java/com/tsi/api/server/vo/NodeStatusVo.java

@@ -0,0 +1,14 @@
+package com.tsi.api.server.vo;
+
+import lombok.Data;
+
+@Data
+public class NodeStatusVo {
+    private long    nodeId;      // 교차로 번호
+    private String  name;        // 교차로 이름
+    private double  lat;         // 위도(경위도)
+    private double  lng;         // 경도(경위도)
+    private int     type;
+    private String  addNode;
+    private int     status;      // 통신상태
+}

+ 11 - 0
src/main/java/com/tsi/api/server/vo/NodeVo.java

@@ -0,0 +1,11 @@
+package com.tsi.api.server.vo;
+
+import lombok.Data;
+
+@Data
+public class NodeVo {
+    private long   nodeId;      // 교차로 번호
+    private String nodeName;    // 교차로 이름
+    private String lat;    // 위도(경위도)
+    private String lng;   // 경도(경위도)
+}

+ 58 - 0
src/main/java/com/tsi/api/server/vo/SystemStatusVo.java

@@ -0,0 +1,58 @@
+package com.tsi.api.server.vo;
+
+import com.tsi.app.common.utils.TimeUtils;
+import lombok.Data;
+
+@Data
+public class SystemStatusVo {
+    private String clctDt;
+    private String hostName;
+
+    private String osType;
+    private String osName;
+    private String osVersion;
+    private String osArch;
+    private String kernelRelease;
+    private String internalIp;
+    private String externalIp;
+    private long swapMem;
+    private int cpuCnt;
+    private String upTimes;     // system booting time
+
+    private float totalMem;
+    private float useMem;
+    private float totalDisk;
+    private float useDisk;
+
+    private float useMemRate;       // calculate
+    private float useCpuRate;
+    private float useDiskRate;      // calculate
+
+    private int tasks;
+    private int threads;
+    private float loadAvg;          // load average
+
+    private long updateTm;
+    private boolean update;
+
+    public SystemStatusVo() {
+        this.clctDt = TimeUtils.getCurrentTimeString();
+        this.swapMem = 0;
+        this.cpuCnt = 0;
+
+        this.totalMem = 0;
+        this.useMem = 0;
+        this.totalDisk = 0;
+        this.useDisk = 0;
+
+        this.useMemRate = 0;       // calculate
+        this.useCpuRate = 0;
+        this.useDiskRate = 0;      // calculate
+
+        this.tasks = 0;
+        this.threads = 0;
+        this.loadAvg = 0;          // load average
+
+        this.update = true;
+    }
+}

+ 21 - 0
src/main/java/com/tsi/api/server/vo/TsiAlarmConfigVo.java

@@ -0,0 +1,21 @@
+package com.tsi.api.server.vo;
+
+import lombok.Data;
+
+@Data
+public class TsiAlarmConfigVo {
+
+    static public String SYS_00 = "SYS_00";     // 시스템 실행 여부
+    static public String SYS_01 = "SYS_01";     // 시스템 CPU 사용량(%)
+    static public String SYS_02 = "SYS_02";     // 시스템 메모리 사용량(%)
+    static public String SYS_03 = "SYS_03";     // 시스템 Disk 사용량(%)
+    static public String COMM_01 = "COMM_01";   // 알수 없는 제어기로 부터의 통신
+    static public String COMM_02 = "COMM_02";   // 제어기 통신 수신 대기 초과 시간(초)
+    static public String KAFKA_03 = "KAFKA_03"; // 카프카 브로커 인증 카프카 브로커 인증	0	Y	N
+    static public String API_01 = "API_01";     // API 인증 API 인증	0	Y	N
+
+    private String  alarmCode;
+    private String  desc;
+    private int     value;
+    private boolean useYn;
+}

+ 10 - 0
src/main/java/com/tsi/api/server/vo/VersionVo.java

@@ -0,0 +1,10 @@
+package com.tsi.api.server.vo;
+
+import lombok.Data;
+
+@Data
+public class VersionVo {
+    String item;
+    String version;
+    String value;
+}

+ 43 - 0
src/main/resources/application.yml

@@ -0,0 +1,43 @@
+spring:
+  application:
+    name: tsi-web
+  datasource:
+    mybatis:
+      platform: mariadb
+      driver-class-name: org.mariadb.jdbc.Driver
+      username: cvim
+      password: 44Klctest$$
+      jpool-name: hikari-cp
+      jmaximum-pool-size: 30
+      jminimum-idle: 2
+
+server:
+  port: 8099
+  shutdown: graceful
+  error:
+    whitelabel:
+      enabled: true
+    include-exception: false
+    include-stacktrace: never
+
+---
+spring:
+  profiles: wonju
+  datasource:
+    mybatis:
+      jdbc-url: jdbc:mariadb://10.4.4.20:3307/cvim_db?characterEncoding=UTF-8&serverTimezone=UTC
+
+---
+spring:
+  profiles: seoul
+  datasource:
+    mybatis:
+      jdbc-url: jdbc:mariadb://192.168.202.105:3306/cvim_db?characterEncoding=UTF-8&serverTimezone=UTC
+
+---
+spring:
+  profiles: dev
+  datasource:
+    mybatis:
+      #jdbc-url: jdbc:mariadb://61.108.209.105:3306/cvim_db?characterEncoding=UTF-8&serverTimezone=UTC
+      jdbc-url: jdbc:mariadb://59.29.208.150:23307/cvim_db?characterEncoding=UTF-8&serverTimezone=UTC

+ 9 - 0
src/main/resources/banner.txt

@@ -0,0 +1,9 @@
+  _____   ____    ___        _      ____    ____      ____
+ |_   _| / ___|  |_ _|      / \    |  _ \  |  _ \    / ___|    ___   _ __  __   __   ___   _ __
+   | |   \___ \   | |      / _ \   | |_) | | |_) |   \___ \   / _ \ | '__| \ \ / /  / _ \ | '__|
+   | |    ___) |  | |     / ___ \  |  __/  |  __/     ___) | |  __/ | |     \ V /  |  __/ | |
+   |_|   |____/  |___|   /_/   \_\ |_|     |_|       |____/   \___| |_|      \_/    \___| |_|
+
+spring-boot.version: ${spring-boot.version}
+application.version: ${application.version}
+  application.title: ${application.title}

+ 87 - 0
src/main/resources/logback-spring.xml

@@ -0,0 +1,87 @@
+<?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="tsi-api-server"/>
+    <property name="ROOT_LOG_LEVEL"  value="DEBUG"/>
+    <property name="LOG_CHARSET"     value="UTF-8" />
+    <property name="LOG_PATH"        value="${user.dir}/logs/${PROJECT_NAME}/"/>
+    <property name="LOG_BACKUP_PATH" value="${user.dir}/logs/${PROJECT_NAME}/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_SCHEDULE"    value="schedule.log"/>
+    <property name="LOG_FILE_NAME_PATTERN"     value="%d{yyyyMMdd}_%i.log.gz"/>
+
+    <property name="MAX_FILESIZE" value="500MB"/>
+    <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:-} %msg%n"/>
+    <property name="LOG_PATTERN_SQL"         value="[%d{yyyy-MM-dd HH:mm:ss.SSS}] [%-5level] %msg%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">
+            <charset>${LOG_CHARSET}</charset>
+            <pattern>${LOG_PATTERN_CONSOLE}</pattern>
+        </encoder>
+    </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>
+
+    <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_FILE}</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.tsi.api.server.scheduler" level="INFO" additivity="false">
+        <appender-ref ref="FILE_SCHEDULE"/>
+        <appender-ref ref="FILE_ERROR"/>
+    </logger>
+
+</configuration>

+ 106 - 0
src/main/resources/mybatis/mapper/tsc-ssip-api.xml

@@ -0,0 +1,106 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
+
+<mapper namespace="com.tsi.api.server.mybatis.TscSsipApiMapper">
+
+    <select id="getApiAuthorizedInfo" parameterType="java.util.HashMap" resultType="com.tsi.api.server.vo.AuthorizedVo">
+        <![CDATA[
+        SELECT TRIM(a.ipaddr) AS accessIpAddress,
+               IF (a.expiredt >= now(), 1, 0) AS isAuthorized
+          FROM tb_tsc_api_client a, tb_tsc_api_acl b
+         WHERE a.useyn    = 'Y'
+           AND a.state    = 'C'
+           AND a.apitoken = #{apiToken}
+           AND a.apitoken = b.apitoken
+           AND b.apiid    = #{apiId}
+           AND b.acl      = 'A'
+        ]]>
+    </select>
+
+    <select id="getApiKafkaAuthorizedInfo" parameterType="java.util.HashMap" resultType="com.tsi.api.server.vo.KafkaAuthorizedVo">
+        <![CDATA[
+        SELECT TRIM(a.ipaddr) AS accessIpAddress,
+               IF (a.expiredt >= now(), 1, 0) AS isAuthorized,
+               NVL(broker_id, 'kAfKAiD') AS brokerId,
+               NVL(broker_pwd, 'kAfKApWd') AS brokerPwd
+        FROM tb_tsc_api_client a
+        WHERE a.useyn    = 'Y'
+          AND a.state    = 'C'
+          AND a.apitoken = #{apiToken}
+        ]]>
+    </select>
+
+    <select id="getNodeInfoList" resultType="com.tsi.api.server.vo.NodeVo">
+        <![CDATA[
+        SELECT nodeid AS nodeId,
+               TRIM(name) AS nodeName,
+               FORMAT(latitude, 10) AS lat,
+               FORMAT(longitude, 9) AS lng
+          FROM tb_tsc_node
+         WHERE useyn  = 'Y'
+        /*  AND nodeyn = 'Y'*/
+     ]]>
+   </select>
+
+   <select id="getBrokerInfo" parameterType="java.lang.String" resultType="com.tsi.api.server.vo.BrokerVo">
+        <![CDATA[
+        SELECT TRIM(b.host) AS ipAddr, b.port AS port, b.username AS id, b.password AS pwd
+          FROM tb_tsc_api_client a, tb_tsc_broker b
+         WHERE a.apitoken = #{apiToken}
+           AND a.expiredt >= now()
+           AND a.brokerid = b.broker_id
+           AND b.useyn    = 'Y'
+     ]]>
+   </select>
+
+    <insert id="insertInvokeHs" parameterType="com.tsi.api.server.vo.ApiInvokeVo">
+        <![CDATA[
+        INSERT INTO tb_tsc_api_invoke_hs (apiid, apitoken, ipaddr, eventdt, error)
+        VALUES (#{apiId}, #{apiToken}, #{ipAddr}, now(), #{error})
+        ]]>
+    </insert>
+
+    <insert id="insertSystemInfo" parameterType="com.tsi.api.server.dto.SystemStatusDto">
+        <![CDATA[
+        INSERT INTO tb_tsc_system (host_name, os_type, os_name, os_version, os_arch, kernel_release, internal_ip, external_ip, total_mem, swap_mem, total_disk, cpu_cnt, uptimes)
+        VALUES (#{info.hostName}, #{info.osType}, #{info.osName}, #{info.osVersion}, #{info.osArch}, #{info.kernelRelease}, #{info.internalIp}, #{info.externalIp},
+                #{info.totalMem}, #{info.swapMem}, #{info.totalDisk}, #{info.cpuCnt}, #{info.upTimes})
+            ON DUPLICATE KEY UPDATE
+                                 os_type = #{info.osType},
+                                 os_name = #{info.osName},
+                                 os_version = #{info.osVersion},
+                                 os_arch = #{info.osArch},
+                                 kernel_release = #{info.kernelRelease},
+                                 internal_ip = #{info.internalIp},
+                                 external_ip = #{info.externalIp},
+                                 total_mem = #{info.totalMem},
+                                 swap_mem = #{info.swapMem},
+                                 total_disk = #{info.totalDisk},
+                                 cpu_cnt = #{info.cpuCnt},
+                                 uptimes = #{info.upTimes}
+        ]]>
+    </insert>
+
+    <insert id="insertSystemStatusHs" parameterType="com.tsi.api.server.vo.SystemStatusVo">
+        <![CDATA[
+        INSERT INTO tb_tsc_system_status_hs (clct_dt, host_name, total_mem, use_mem, total_disk, use_disk, use_mem_rate, use_cpu_rate, use_disk_rate, task_cnt, thread_cnt, load_avg)
+        VALUES (STR_TO_DATE(#{info.clctDt}, '%Y%m%d%H%i%s'), #{info.hostName}, #{info.totalMem}, #{info.useMem}, #{info.totalDisk}, #{info.useDisk}, #{info.useMemRate}, #{info.useCpuRate}, #{info.useDiskRate}, #{info.tasks}, #{info.threads}, #{info.loadAvg})
+        ]]>
+    </insert>
+
+    <insert id="insertSystemStatusHsxx" parameterType="com.tsi.api.server.vo.SystemStatusVo">
+        <![CDATA[
+        INSERT INTO tb_tsc_system_status_hs (clct_dt, host_name, total_mem, use_mem, total_disk, use_disk, use_mem_rate, use_cpu_rate, use_disk_rate, task_cnt, thread_cnt, load_avg)
+        VALUES (DATE_SUB(NOW(), INTERVAL MOD(NOW(), 10) SECOND), #{info.hostName}, #{info.totalMem}, #{info.useMem}, #{info.totalDisk}, #{info.useDisk}, #{info.useMemRate}, #{info.useCpuRate}, #{info.useDiskRate}, #{info.tasks}, #{info.threads}, #{info.loadAvg})
+        ]]>
+    </insert>
+
+    <select id="getAlarmConfig" parameterType="java.util.HashMap" resultType="com.tsi.api.server.mybatis.vo.AlarmConfigVo">
+        <![CDATA[
+        select a.alarm_code as alarmCode, a.desc,
+               a.value, a.useyn
+        from tb_tsc_alarm_config a
+        ]]>
+    </select>
+
+</mapper>

+ 56 - 0
src/main/resources/mybatis/mapper/tsc-ssip-app.xml

@@ -0,0 +1,56 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
+
+<mapper namespace="com.tsi.api.server.mybatis.TscSsipAppMapper">
+
+    <select id="getDeviceAuthorizedInfo" parameterType="java.util.HashMap" resultType="com.tsi.api.server.vo.NaviAuthorizedVo">
+        <![CDATA[
+        SELECT TRIM(a.ipaddr) AS accessIpAddress, state AS state, useyn as useYn,
+               IF (a.expiredt >= NOW(), 'N', 'Y') AS expired
+          FROM tb_tsc_api_client a
+         WHERE a.apitoken = #{deviceId}
+           AND a.clientType = 'APP'
+        ]]>
+    </select>
+
+    <select id="getVersion" resultType="com.tsi.api.server.vo.VersionVo">
+        <![CDATA[
+        SELECT TRIM(a.item)    AS item,
+               TRIM(a.version) AS version,
+               TRIM(a.value)   AS value
+          FROM tb_tsc_version a
+         WHERE app = 'APP'
+     ]]>
+    </select>
+
+    <insert id="registerDevice" parameterType="com.tsi.api.server.vo.DeviceInfo">
+        <![CDATA[
+        INSERT INTO tb_tsc_api_client (apitoken, company, manager, phone, email, expiredt, eventdt, ipaddr, clientType, state, useyn)
+        VALUES (#{deviceId}, #{company}, #{manager}, #{phone}, #{email}, now(), now(), '*', 'APP', 'R', 'Y')
+        ]]>
+    </insert>
+
+    <insert id="insertInvokeHs" parameterType="com.tsi.api.server.vo.ApiInvokeVo">
+        <![CDATA[
+        INSERT INTO tb_tsc_api_invoke_hs (apiid, apitoken, ipaddr, eventdt, error)
+        VALUES (#{apiId}, #{apiToken}, #{ipAddr}, now(), #{error})
+        ]]>
+    </insert>
+
+    <select id="getNodeStatusList" resultType="com.tsi.api.server.vo.NodeStatusVo">
+        <![CDATA[
+        select a.nodeid as nodeId,
+               a.name as name,
+               a.latitude as lat,
+               a.longitude as lng,
+               a.nodetype as type,
+               a.addnode as addNode,
+               nvl(b.status, 0) as status
+        from tb_tsc_node a
+        left outer join tb_tsc_node_status b
+          on a.nodeid = b.nodeid
+       where a.useyn = 'Y'
+     ]]>
+    </select>
+
+</mapper>

+ 47 - 0
src/main/resources/mybatis/mapper/tsi-database.xml

@@ -0,0 +1,47 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
+
+<mapper namespace="com.tsi.api.server.mybatis.TsiDatabaseMapper">
+
+    <select id="getAlarmConfig" parameterType="java.util.HashMap" resultType="com.tsi.api.server.mybatis.vo.AlarmConfigVo">
+        <![CDATA[
+        select a.alarm_code as alarmCode, a.desc,
+               a.value, a.useyn
+        from tb_tsc_alarm_config a
+        ]]>
+    </select>
+    <insert id="insertAlarmOccrHs" parameterType="com.tsi.api.server.mybatis.vo.AlarmOccrVo">
+    <![CDATA[
+        insert into tb_tsc_alarm_hs(occr_dt, alarm_code, alarm_target, alarm_value)
+        values(STR_TO_DATE(#{vo.eventDt},'%Y%m%d%H%i%S'), #{vo.alarmCode}, #{vo.alarmTarget}, #{vo.alarmValue})
+        ]]>
+    </insert>
+
+    <update id="updateProcessStatusStart" parameterType="com.tsi.api.server.mybatis.vo.ProcessStateVo">
+    <![CDATA[
+        update tb_tsc_process
+        set process_state = 1,
+            update_tm = NOW(),
+            start_tm = NOW()
+        where process_id = #{stts.processId}
+        ]]>
+    </update>
+    <update id="updateProcessStatusStop" parameterType="com.tsi.api.server.mybatis.vo.ProcessStateVo">
+    <![CDATA[
+        update tb_tsc_process
+        set process_state = 0,
+            update_tm = NOW(),
+            end_tm = NOW()
+        where process_id = #{stts.processId}
+        ]]>
+    </update>
+    <update id="updateProcessStatusRun" parameterType="com.tsi.api.server.mybatis.vo.ProcessStateVo">
+    <![CDATA[
+        update tb_tsc_process
+        set process_state = 1,
+            update_tm = NOW()
+        where process_id = #{stts.processId}
+        ]]>
+    </update>
+
+</mapper>

+ 21 - 0
src/main/resources/mybatis/mybatis-config.xml

@@ -0,0 +1,21 @@
+<!DOCTYPE configuration PUBLIC "-//mybatis.org//DTD Config 3.0//EN" "HTTP://mybatis.org/dtd/mybatis-3-config.dtd">
+<configuration>
+	<settings>
+		<setting name="aggressiveLazyLoading" value="false"/>
+		<setting name="jdbcTypeForNull" value="NULL"/>
+		<setting name="cacheEnabled" value="true"/>
+		<setting name="lazyLoadingEnabled" value="false"/>
+		<setting name="multipleResultSetsEnabled" value="true"/>
+		<setting name="useColumnLabel" value="true"/>
+		<setting name="useGeneratedKeys" value="false"/>
+		<setting name="defaultExecutorType" value="REUSE"/>
+		<setting name="defaultStatementTimeout" value="25000"/>
+		<setting name="mapUnderscoreToCamelCase" value="true"/>
+	</settings>
+    
+	<typeAliases>
+	</typeAliases>
+	
+	<typeHandlers>
+	</typeHandlers>
+</configuration>

+ 12 - 0
src/test/java/com/tsi/api/server/TscSsipApiApplicationTests.java

@@ -0,0 +1,12 @@
+package com.tsi.api.server;
+
+import org.junit.jupiter.api.Test;
+
+//@SpringBootTest
+class TscSsipApiApplicationTests {
+
+	@Test
+	void contextLoads() {
+	}
+
+}