shjung пре 11 месеци
комит
993ec7e7ac
45 измењених фајлова са 3885 додато и 0 уклоњено
  1. 7 0
      .bash_logout
  2. 117 0
      .bashrc
  3. 34 0
      .gitignore
  4. 118 0
      .mvn/wrapper/MavenWrapperDownloader.java
  5. BIN
      .mvn/wrapper/maven-wrapper.jar
  6. 2 0
      .mvn/wrapper/maven-wrapper.properties
  7. 27 0
      .profile
  8. 4 0
      bin/broker.sh
  9. 1 0
      bin/conn.bat
  10. 1 0
      bin/seoul.bat
  11. 59 0
      bin/start.sh
  12. 9 0
      bin/stat.sh
  13. 54 0
      bin/stop.sh
  14. 103 0
      bin/tsi-agent.sh
  15. 4 0
      broker.sh
  16. BIN
      jmx_prometheus_javaagent-0.20.0.jar
  17. 322 0
      mvnw
  18. 182 0
      mvnw.cmd
  19. 115 0
      pom.xml
  20. 1 0
      seoul.bat
  21. 85 0
      src/main/java/com/tsi/app/common/kafka/KafkaProducerFactory.java
  22. 364 0
      src/main/java/com/tsi/app/common/utils/ByteUtils.java
  23. 252 0
      src/main/java/com/tsi/app/common/utils/CRC16.java
  24. 83 0
      src/main/java/com/tsi/app/common/utils/CRC16Utils.java
  25. 22 0
      src/main/java/com/tsi/app/common/utils/Converter.java
  26. 38 0
      src/main/java/com/tsi/app/common/utils/Counter.java
  27. 31 0
      src/main/java/com/tsi/app/common/utils/Elapsed.java
  28. 122 0
      src/main/java/com/tsi/app/common/utils/HexString.java
  29. 76 0
      src/main/java/com/tsi/app/common/utils/LockFreeStack.java
  30. 82 0
      src/main/java/com/tsi/app/common/utils/NonBlockingQueue.java
  31. 8 0
      src/main/java/com/tsi/app/common/utils/OS.java
  32. 44 0
      src/main/java/com/tsi/app/common/utils/StringUtils.java
  33. 171 0
      src/main/java/com/tsi/app/common/utils/SysUtils.java
  34. 295 0
      src/main/java/com/tsi/app/common/utils/TimeUtils.java
  35. 63 0
      src/main/java/com/tsi/app/common/utils/Timespec.java
  36. 109 0
      src/main/java/com/tsi/comm/consumer/TsiCommConsumerApplication.java
  37. 96 0
      src/main/java/com/tsi/comm/consumer/kafka/KafkaConsumerService.java
  38. 378 0
      src/main/java/com/tsi/comm/consumer/kafka/TsiKafkaConsumerWorker.java
  39. 9 0
      src/main/resources/application.yml
  40. 23 0
      src/main/resources/logback-spring.xml
  41. 148 0
      src/test/java/com/tsi/comm/consumer/TsiCommConsumerApplicationTests.java
  42. 59 0
      start.sh
  43. 9 0
      stat.sh
  44. 54 0
      stop.sh
  45. 104 0
      tsi-agent.sh

+ 7 - 0
.bash_logout

@@ -0,0 +1,7 @@
+# ~/.bash_logout: executed by bash(1) when login shell exits.
+
+# when leaving the console clear the screen to increase privacy
+
+if [ "$SHLVL" = 1 ]; then
+    [ -x /usr/bin/clear_console ] && /usr/bin/clear_console -q
+fi

+ 117 - 0
.bashrc

@@ -0,0 +1,117 @@
+# ~/.bashrc: executed by bash(1) for non-login shells.
+# see /usr/share/doc/bash/examples/startup-files (in the package bash-doc)
+# for examples
+
+# If not running interactively, don't do anything
+case $- in
+    *i*) ;;
+      *) return;;
+esac
+
+# don't put duplicate lines or lines starting with space in the history.
+# See bash(1) for more options
+HISTCONTROL=ignoreboth
+
+# append to the history file, don't overwrite it
+shopt -s histappend
+
+# for setting history length see HISTSIZE and HISTFILESIZE in bash(1)
+HISTSIZE=1000
+HISTFILESIZE=2000
+
+# check the window size after each command and, if necessary,
+# update the values of LINES and COLUMNS.
+shopt -s checkwinsize
+
+# If set, the pattern "**" used in a pathname expansion context will
+# match all files and zero or more directories and subdirectories.
+#shopt -s globstar
+
+# make less more friendly for non-text input files, see lesspipe(1)
+[ -x /usr/bin/lesspipe ] && eval "$(SHELL=/bin/sh lesspipe)"
+
+# set variable identifying the chroot you work in (used in the prompt below)
+if [ -z "${debian_chroot:-}" ] && [ -r /etc/debian_chroot ]; then
+    debian_chroot=$(cat /etc/debian_chroot)
+fi
+
+# set a fancy prompt (non-color, unless we know we "want" color)
+case "$TERM" in
+    xterm-color|*-256color) color_prompt=yes;;
+esac
+
+# uncomment for a colored prompt, if the terminal has the capability; turned
+# off by default to not distract the user: the focus in a terminal window
+# should be on the output of commands, not on the prompt
+#force_color_prompt=yes
+
+if [ -n "$force_color_prompt" ]; then
+    if [ -x /usr/bin/tput ] && tput setaf 1 >&/dev/null; then
+	# We have color support; assume it's compliant with Ecma-48
+	# (ISO/IEC-6429). (Lack of such support is extremely rare, and such
+	# a case would tend to support setf rather than setaf.)
+	color_prompt=yes
+    else
+	color_prompt=
+    fi
+fi
+
+if [ "$color_prompt" = yes ]; then
+    PS1='${debian_chroot:+($debian_chroot)}\[\033[01;32m\]\u@\h\[\033[00m\]:\[\033[01;34m\]\w\[\033[00m\]\$ '
+else
+    PS1='${debian_chroot:+($debian_chroot)}\u@\h:\w\$ '
+fi
+unset color_prompt force_color_prompt
+
+# If this is an xterm set the title to user@host:dir
+case "$TERM" in
+xterm*|rxvt*)
+    PS1="\[\e]0;${debian_chroot:+($debian_chroot)}\u@\h: \w\a\]$PS1"
+    ;;
+*)
+    ;;
+esac
+
+# enable color support of ls and also add handy aliases
+if [ -x /usr/bin/dircolors ]; then
+    test -r ~/.dircolors && eval "$(dircolors -b ~/.dircolors)" || eval "$(dircolors -b)"
+    alias ls='ls --color=auto'
+    #alias dir='dir --color=auto'
+    #alias vdir='vdir --color=auto'
+
+    alias grep='grep --color=auto'
+    alias fgrep='fgrep --color=auto'
+    alias egrep='egrep --color=auto'
+fi
+
+# colored GCC warnings and errors
+#export GCC_COLORS='error=01;31:warning=01;35:note=01;36:caret=01;32:locus=01:quote=01'
+
+# some more ls aliases
+alias ll='ls -alF'
+alias la='ls -A'
+alias l='ls -CF'
+
+# Add an "alert" alias for long running commands.  Use like so:
+#   sleep 10; alert
+alias alert='notify-send --urgency=low -i "$([ $? = 0 ] && echo terminal || echo error)" "$(history|tail -n1|sed -e '\''s/^\s*[0-9]\+\s*//;s/[;&|]\s*alert$//'\'')"'
+
+# Alias definitions.
+# You may want to put all your additions into a separate file like
+# ~/.bash_aliases, instead of adding them here directly.
+# See /usr/share/doc/bash-doc/examples in the bash-doc package.
+
+if [ -f ~/.bash_aliases ]; then
+    . ~/.bash_aliases
+fi
+
+# enable programmable completion features (you don't need to enable
+# this, if it's already enabled in /etc/bash.bashrc and /etc/profile
+# sources /etc/bash.bashrc).
+if ! shopt -oq posix; then
+  if [ -f /usr/share/bash-completion/bash_completion ]; then
+    . /usr/share/bash-completion/bash_completion
+  elif [ -f /etc/bash_completion ]; then
+    . /etc/bash_completion
+  fi
+fi

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

BIN
.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.8.1/apache-maven-3.8.1-bin.zip
+wrapperUrl=https://repo.maven.apache.org/maven2/io/takari/maven-wrapper/0.5.6/maven-wrapper-0.5.6.jar

+ 27 - 0
.profile

@@ -0,0 +1,27 @@
+# ~/.profile: executed by the command interpreter for login shells.
+# This file is not read by bash(1), if ~/.bash_profile or ~/.bash_login
+# exists.
+# see /usr/share/doc/bash/examples/startup-files for examples.
+# the files are located in the bash-doc package.
+
+# the default umask is set in /etc/profile; for setting the umask
+# for ssh logins, install and configure the libpam-umask package.
+#umask 022
+
+# if running bash
+if [ -n "$BASH_VERSION" ]; then
+    # include .bashrc if it exists
+    if [ -f "$HOME/.bashrc" ]; then
+	. "$HOME/.bashrc"
+    fi
+fi
+
+# set PATH so it includes user's private bin if it exists
+if [ -d "$HOME/bin" ] ; then
+    PATH="$HOME/bin:$PATH"
+fi
+
+# set PATH so it includes user's private bin if it exists
+if [ -d "$HOME/.local/bin" ] ; then
+    PATH="$HOME/.local/bin:$PATH"
+fi

+ 4 - 0
bin/broker.sh

@@ -0,0 +1,4 @@
+kafkacat -b 123.142.27.53:9092 -L
+kafkacat -b 123.142.27.53:9093 -L
+kafkacat -b 123.142.27.53:9094 -L
+

+ 1 - 0
bin/conn.bat

@@ -0,0 +1 @@
+sftp -oPort=10022 hante-devops@59.29.208.150

+ 1 - 0
bin/seoul.bat

@@ -0,0 +1 @@
+sftp -oPort=22 cvim@61.108.209.104

+ 59 - 0
bin/start.sh

@@ -0,0 +1,59 @@
+#!/bin/sh
+
+ACTIVE_PROFILE=wonju
+#ACTIVE_PROFILE=wonju,mongodb
+SERVICE_HOME=$(dirname $0)
+
+usage() {
+	echo "Usage:" $0 "[comm/data]"
+	echo "RUN tsi-comm-server:" $0 "comm"
+	echo "RUN tsi-data-broker:" $0 "data"
+	exit
+}
+
+case $1 in
+  comm)
+    SERVICE_NAME=tsi-comm-server
+    SERVICE_VERSION=0.0.1
+    ;;
+  data)
+    SERVICE_NAME=tsi-data-broker
+    SERVICE_VERSION=0.0.1
+    ;;
+  *)
+    usage
+    ;;
+esac
+
+
+EXE_NAME=$SERVICE_NAME-$SERVICE_VERSION.jar
+PID_NAME=$SERVICE_NAME.pid
+SERVICE_PID=$SERVICE_HOME/conf/$PID_NAME
+
+export JAVA_OPT="-server"
+#export JAVA_OPT="$JAVA_OPT -Xms4096m -Xmx4096m"
+export JAVA_OPT="$JAVA_OPT -Xlog:gc*:file=logs/${SERVICE_NAME}/${SERVICE_NAME}.gc.log"
+export CONFIG_OPT="-Dspring.profiles.active=${ACTIVE_PROFILE}"
+#export CONFIG_OPT="--spring.config.location=conf//$SERVICE_NAME.yml"
+
+if [ ! -z "$SERVICE_PID" ]; then
+  if [ -f "$SERVICE_PID" ]; then
+    echo "$SERVICE_NAME is already running...."
+    exit
+  fi
+fi
+
+#nohup java $JAVA_OPT -jar ./$EXE_NAME $CONFIG_OPT 1> /dev/null 2>&1 &
+#java $JAVA_OPT -jar ./$EXE_NAME $CONFIG_OPT &
+java $JAVA_OPT -jar $CONFIG_OPT ./$EXE_NAME &
+
+echo "$SERVICE_NAME is started...."
+
+sleep 1
+
+ps -eaf | grep $SERVICE_NAME | grep -v grep |wc -l
+
+sleep 1
+
+ps -eaf | grep $SERVICE_NAME | grep -v grep
+

+ 9 - 0
bin/stat.sh

@@ -0,0 +1,9 @@
+#!/bin/sh
+
+export SERVICE_NAME=tsi-
+
+ps -eaf | grep $SERVICE_NAME | grep -v grep | grep -v tail | grep -v kafka | grep java | wc -l
+
+sleep 1
+
+ps -eaf | grep $SERVICE_NAME | grep -v grep | grep -v tail | grep -v kafka | grep java

+ 54 - 0
bin/stop.sh

@@ -0,0 +1,54 @@
+#!/bin/sh
+
+SERVICE_HOME=$(dirname $0)
+
+usage() {
+        echo "Usage:" $0 "[comm/data]"
+        echo "STOP tsi-comm-server:" $0 "comm"
+        echo "STOP tsi-data-broker:" $0 "data"
+        exit
+}
+
+case $1 in
+  comm)
+    SERVICE_NAME=tsi-comm-server
+    SERVICE_VERSION=0.0.1
+    ;;
+  data)
+    SERVICE_NAME=tsi-data-broker
+    SERVICE_VERSION=0.0.1
+    ;;
+  *)
+    usage
+    ;;
+esac
+
+
+EXE_NAME=$SERVICE_NAME-$SERVICE_VERSION.jar
+PID_NAME=$SERVICE_NAME.pid
+SERVICE_PID=$SERVICE_HOME/conf/$PID_NAME
+
+if [ ! -z "$SERVICE_PID" ]; then
+  if [ -f "$SERVICE_PID" ]; then
+    kill -15 `cat "$SERVICE_PID"` >/dev/null 2>&1
+    echo "$SERVICE_NAME stopping.........."
+  else
+    echo "$SERVICE_NAME is not running...."
+    exit
+  fi
+fi
+
+LOOP=$(seq 0 9)
+for i in $LOOP
+do
+  sleep 1
+  if [ -f "$SERVICE_PID" ]; then
+    echo "$SERVICE_NAME stopping.........."
+  else
+    echo "$SERVICE_NAME stopped.........."
+    exit
+  fi
+done
+
+echo "$SERVICE_NAME cannot be terminated......."
+ps -eaf | grep $SERVICE_NAME | grep -v grep

+ 103 - 0
bin/tsi-agent.sh

@@ -0,0 +1,103 @@
+#!/bin/bash
+
+SSIP_API_URI="http://10.4.4.40:8444/api/system-status"
+SSIP_API_TIMEOUT=3
+HEADER_CONTEXT_TYPE="Content-Type: application/json"
+
+# Check hostname
+name=$HOSTNAME
+echo -e "Hostname:" $name
+
+# Check OS Type
+otype=$(uname -o)
+echo -e "Operating System Type:" $otype
+
+# Check OS Release Version and Name
+oname=`cat /etc/os-release | grep 'NAME' | grep -v 'PRETTY_NAME' | grep -v 'CODENAME' | cut -f2 -d\"`
+over=`cat /etc/os-release | grep 'VERSION' | grep -v '_' | cut -f2 -d\"`
+echo "OS Name:" $oname
+echo "OS Version:" $over
+
+# Check Architecture
+oarch=$(uname -m)
+echo "Architecture:" $oarch
+
+# Check Kernel Release
+kernel=$(uname -r)
+echo "Kernel Release:" $kernel
+
+# Check Internal IP
+iip=$(hostname -I)
+echo "Internal IP:" $iip
+
+# Check Internal IP
+eip=$(dig +short myip.opendns.com @resolver1.opendns.com)
+echo "External IP:" $eip
+
+run_monitoring() {
+    totalmem=`free -m | grep ^Mem | awk '{print $2}'`
+    usedmem=`free -m | grep ^Mem | awk '{print $3}'`
+    freemem=`free -m | grep ^Mem | awk '{print $4}'`
+    cachemem=`free -m | grep ^Mem | awk '{print $6}'`
+    availablemem=`free -m | grep ^Mem | awk '{print $7}'`
+
+    swapmem=`free -m | grep ^Swap | awk '{print $2}'`
+    usedswap=`free -m | grep ^Swap | awk '{print $3}'`
+
+    cpucnt=`cat /proc/cpuinfo | grep 'processor' | wc -l`
+    uptimes=`uptime -s`
+
+    echo "cpuCnt:" ${cpucnt}
+
+    #usecpurate=`top -b -n 1 | grep Cpu | awk '{print $8}' | tr -d "%id," | awk '{print 100-$1}'`
+    usecpurate=`mpstat 1 1 | tail -1 | awk '{print 100-$NF}'`
+    echo "useCpuRate:" ${usecpurate}
+    tasks=`ps aux | grep -v ps | wc -l`
+    threads=200
+
+    #loadavg=`uptime | awk '{print $10}' | cut -f 1 -d ','`
+    loadavg=`cat /proc/loadavg | awk '{print $1}'`
+    echo "loadAvg:" ${loadavg}
+    
+    #DISK 사용율
+    totaldisk=`df -P | grep -v ^Filesystem | awk '{sum += $2} END { print sum; }'`
+    useddisk=`df -P | grep -v ^Filesystem | awk '{sum += $3} END { print sum; }'`
+    useddiskrate=$((100*$useddisk/$totaldisk))
+    echo DISK: $(($totaldisk/1024/1024)) GB, Used DISK: $(($useddisk/1024/1024)) GB, Rate: $useddiskrate %
+
+    # Call System Status Save REST API
+    PAYLOAD='{"hostName"      : "'${name}'", 
+              "osType"        : "'${otype}'", 
+              "osName"        : "'${oname}'", 
+              "osVersion"     : "'${over}'", 
+              "osArch"        : "'${oarch}'", 
+              "kernelRelease" : "'${kernel}'", 
+              "internalIp"    : "'${iip}'", 
+              "externalIp"    : "'${eip}'",
+              "totalMem"      : "'${totalmem}'",
+              "swapMem"       : "'${swapmem}'",
+              "totalDisk"     : "'${totaldisk}'",
+              "cpuCnt"        : "'${cpucnt}'",
+              "upTimes"       : "'${uptimes}'",
+              "usedDisk"      : "'${useddisk}'",
+              "usedMem"       : "'${usedmem}'",
+              "freeMem"       : "'${freemem}'",
+              "cacheMem"      : "'${cachemem}'",
+              "availableMem"  : "'${availablemem}'",
+              "usedSwap"      : "'${usedswap}'",
+              "tasks"         : "'${tasks}'",
+              "threads"       : "'${threads}'",
+              "useCpuRate"    : "'${usecpurate}'",
+              "loadAvg"       : "'${loadavg}'"
+	    }'
+
+    api_result=$(curl -d "${PAYLOAD}" -X POST $SSIP_API_URI -H "$HEADER_CONTEXT_TYPE" --connect-timeout $SSIP_API_TIMEOUT)
+
+    # Result
+    echo ""
+    echo ${api_result}
+    echo ""
+}
+
+run_monitoring
+

+ 4 - 0
broker.sh

@@ -0,0 +1,4 @@
+./kafkacat -b 172.24.0.30:9092 -L
+./kafkacat -b 172.24.0.31:9093 -L
+./kafkacat -b 172.24.0.32:9094 -L
+

BIN
jmx_prometheus_javaagent-0.20.0.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,config=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%

+ 115 - 0
pom.xml

@@ -0,0 +1,115 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
+    <modelVersion>4.0.0</modelVersion>
+    <parent>
+        <groupId>org.springframework.boot</groupId>
+        <artifactId>spring-boot-starter-parent</artifactId>
+        <version>2.4.13</version>
+        <relativePath/> <!-- lookup parent from repository -->
+    </parent>
+
+    <groupId>com.tsi.comm</groupId>
+    <artifactId>tsi-consumer</artifactId>
+    <version>0.0.1</version>
+    <name>tsi-consumer</name>
+    <description>TSI Communication Consumer</description>
+
+    <properties>
+        <java.version>1.8</java.version>
+        <netty.version>4.1.52.Final</netty.version>
+        <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>
+        <start-class>com.tsi.comm.consumer.TsiCommConsumerApplication</start-class>
+        <webapp.lib>C:\java\repository</webapp.lib>
+        <maven.test.skip>true</maven.test.skip>
+    </properties>
+
+    <repositories>
+        <repository>
+            <id>jitpack.io</id>
+            <url>https://jitpack.io</url>
+        </repository>
+    </repositories>
+
+    <dependencies>
+
+        <dependency>
+            <groupId>com.fasterxml.jackson.module</groupId>
+            <artifactId>jackson-module-kotlin</artifactId>
+        </dependency>
+
+        <dependency>
+            <groupId>org.mybatis.spring.boot</groupId>
+            <artifactId>mybatis-spring-boot-starter</artifactId>
+            <version>2.2.0</version>
+        </dependency>
+        <dependency>
+            <groupId>org.springframework.kafka</groupId>
+            <artifactId>spring-kafka</artifactId>
+            <version>2.7.0</version>
+        </dependency>
+        <!--<dependency>
+            <groupId>org.apache.kafka</groupId>
+            <artifactId>kafka-clients</artifactId>
+            <version>2.7.0</version>
+        </dependency>-->
+
+        <dependency>
+            <groupId>org.projectlombok</groupId>
+            <artifactId>lombok</artifactId>
+            <optional>true</optional>
+        </dependency>
+
+        <dependency>
+            <groupId>org.springframework.boot</groupId>
+            <artifactId>spring-boot-starter-test</artifactId>
+            <scope>test</scope>
+        </dependency>
+        <dependency>
+            <groupId>org.springframework.kafka</groupId>
+            <artifactId>spring-kafka-test</artifactId>
+            <scope>test</scope>
+        </dependency>
+
+        <dependency>
+            <groupId>io.netty</groupId>
+            <artifactId>netty-all</artifactId>
+            <version>${netty.version}</version>
+        </dependency>
+
+        <dependency>
+            <groupId>org.jctools</groupId>
+            <artifactId>jctools-core</artifactId>
+            <version>3.3.0</version>
+        </dependency>
+
+        <dependency>
+            <groupId>com.fasterxml.jackson.core</groupId>
+            <artifactId>jackson-databind</artifactId>
+            <version>2.10.3</version>
+        </dependency>
+
+    </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>

+ 1 - 0
seoul.bat

@@ -0,0 +1 @@
+sftp -oPort=22 cvim@61.108.209.104

+ 85 - 0
src/main/java/com/tsi/app/common/kafka/KafkaProducerFactory.java

@@ -0,0 +1,85 @@
+package com.tsi.app.common.kafka;
+
+import org.apache.kafka.clients.producer.ProducerConfig;
+import org.springframework.kafka.core.DefaultKafkaProducerFactory;
+import org.springframework.kafka.core.KafkaTemplate;
+
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.Properties;
+
+public class KafkaProducerFactory {
+
+    public static <K,V> KafkaTemplate<K, V> createByteArrayTemplate(String bootstrapServers, List<Map<String, String>> props) {
+        Map<String, Object> configs = new HashMap<>();
+        configs.put(ProducerConfig.BOOTSTRAP_SERVERS_CONFIG, bootstrapServers);
+        configs.put("enable.idempotence", false);
+        configs.put(ProducerConfig.ACKS_CONFIG, "0");
+        configs.put(ProducerConfig.RETRIES_CONFIG, 0);
+        configs.put(ProducerConfig.LINGER_MS_CONFIG, 1);
+        configs.put(ProducerConfig.REQUEST_TIMEOUT_MS_CONFIG, 3000);
+        configs.put(ProducerConfig.DELIVERY_TIMEOUT_MS_CONFIG, 4000);
+        //configs.put("queue.buffering.max.messages", 10000000);
+        //configs.put("queue.buffering.max.kbytes", 2147483647);
+        //configs.put("queue.buffering.max.ms", 0);
+        //configs.put("api.version.request", false);
+        configs.put(ProducerConfig.TRANSACTION_TIMEOUT_CONFIG, 5000);
+        configs.put(ProducerConfig.KEY_SERIALIZER_CLASS_CONFIG, org.apache.kafka.common.serialization.StringSerializer.class);
+        configs.put(ProducerConfig.VALUE_SERIALIZER_CLASS_CONFIG, org.apache.kafka.common.serialization.ByteArraySerializer.class);
+
+        for (Map<String, String> prop : props) {
+            for (Map.Entry<String, String> elem : prop.entrySet()) {
+                String key = elem.getKey();
+                String val = elem.getValue();
+                if (val != null) {
+                    if (val.equals("true") || val.equals("false")) {
+                        configs.put(key, val.equals("true"));
+                    } else {
+                        configs.put(key, val);
+                    }
+                }
+            }
+        }
+
+        DefaultKafkaProducerFactory<K, V> defaultKafkaProducerFactory = new DefaultKafkaProducerFactory<>(configs);
+        return new KafkaTemplate<>(defaultKafkaProducerFactory);
+    }
+
+    public static <K,V> KafkaTemplate<K, V> createProducerTemplate(Map<String, Object> props) {
+        DefaultKafkaProducerFactory<K, V> defaultKafkaProducerFactory = new DefaultKafkaProducerFactory<>(props);
+        return new KafkaTemplate<>(defaultKafkaProducerFactory);
+    }
+
+    public static Properties getProperties(String bootstrapServers, List<Map<String, String>> props) {
+        Properties properties  = new Properties();
+        properties.put(ProducerConfig.BOOTSTRAP_SERVERS_CONFIG, bootstrapServers);
+        properties.put("enable.idempotence", false);
+        properties.put(ProducerConfig.ACKS_CONFIG, "0");
+        properties.put(ProducerConfig.RETRIES_CONFIG, 0);
+        properties.put(ProducerConfig.LINGER_MS_CONFIG, 1);
+        properties.put(ProducerConfig.REQUEST_TIMEOUT_MS_CONFIG, 3000);
+        properties.put(ProducerConfig.DELIVERY_TIMEOUT_MS_CONFIG, 4000);
+        //properties.put("queue.buffering.max.messages", 10000000);
+        //properties.put("queue.buffering.max.kbytes", 2147483647);
+        //properties.put("queue.buffering.max.ms", 0);
+        //properties.put("api.version.request", false);
+        properties.put("transaction.timeout.ms", 5000);
+        properties.put(ProducerConfig.KEY_SERIALIZER_CLASS_CONFIG, org.apache.kafka.common.serialization.StringSerializer.class);
+        properties.put(ProducerConfig.VALUE_SERIALIZER_CLASS_CONFIG, org.apache.kafka.common.serialization.ByteArraySerializer.class);
+        for (Map<String, String> prop : props) {
+            for (Map.Entry<String, String> elem : prop.entrySet()) {
+                String key = elem.getKey();
+                String val = elem.getValue();
+                if (val != null) {
+                    if (val.equals("true") || val.equals("false")) {
+                        properties.put(key, val.equals("true"));
+                    } else {
+                        properties.put(key, val);
+                    }
+                }
+            }
+        }
+        return properties ;
+    }
+}

+ 364 - 0
src/main/java/com/tsi/app/common/utils/ByteUtils.java

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

+ 252 - 0
src/main/java/com/tsi/app/common/utils/CRC16.java

@@ -0,0 +1,252 @@
+package com.tsi.app.common.utils;
+
+/**
+ * CRC16_CCITT: Polynomial x16+x12+x5+1 (0x1021), initial value 0x0000, low bit first, high bit after, result is exclusive to 0x0000
+ * CRC16_CCITT_FALSE: Polynomial x16+x12+x5+1 (0x1021), initial value 0xFFFF, low bit is after, high bit is first, result is exclusive to 0x0000
+ * CRC16_XMODEM: Polynomial x16+x12+x5+1 (0x1021), initial value 0x0000, low bit after, high bit first, result is XOR0
+ * CRC16_X25: Polynomial x16+x12+x5+1 (0x1021), initial value 0xffff, low bit first, high bit after, result is XORIF 0xFFFF
+ * CRC16_MODBUS: Polynomial x16+x15+x2+1 (0x8005), initial value 0xFFFF, low bit first, high bit after, result is X2000000 exclusive OR
+ * CRC16_IBM: Polynomial x16+x15+x2+1 (0x8005), initial value 0x0000, low bit first, high bit after, result is XOR0
+ * CRC16_MAXIM: Polynomial x16+x15+x2+1 (0x8005), initial value 0x0000, low bit first, high bit after, result is XORIF 0xFFFF
+ * CRC16_USB: Polynomial x16+x15+x2+1 (0x8005), initial value 0xFFFF, low bit first, high bit after, result is XORIF 0xFFFF
+ * <p>
+ * (1), preset a 16-bit register to hexadecimal FFFF (that is, all 1), call this register a CRC register;
+ * (2), the first 8-bit binary data (the first byte of the communication information frame) is different from the lower 8 bits of the 16-bit CRC register, the result is placed in the CRC register, the upper eight bits of data are not Change
+ * (3), shift the contents of the CRC register one bit to the right (toward the low position) to fill the highest bit with 0, and check the shifted out bit after the right shift;
+ * (4) If the shift bit is 0: repeat step 3 (shift one bit right again); if the shift bit is 1, the CRC register is XORed with the polynomial A001 (1010 0000 0000 0001);
+ * (5), repeat steps 3 and 4 until the right shift 8 times, so that the entire 8-bit data is processed;
+ * (6), repeat steps 2 to 5, and worker the next byte of the communication information frame;
+ * (7), after all the bytes of the communication information frame are calculated according to the above steps, the high and low bytes of the obtained 16-bit CRC register are exchanged;
+ * (8), the final CRC register content is: CRC code.
+ * <p>
+ * The polynomial 0xA001 in the above calculation step is the result of 0x8005 bitwise reversal.
+ * 0x8408 is the result of 0x1021 bitwise reversal.
+ * Online verification tool
+ * http://www.ip33.com/crc.html
+ * https://blog.csdn.net/htmlxx/article/details/17369105
+ * <p>
+ * Author:Water
+ * Time:2018/11/19 0019 15:03
+ */
+public class CRC16 {
+
+    /**
+     * CRC16_CCITT: Polynomial x16+x12+x5+1 (0x1021), initial value 0x0000, low bit first, high bit after, result is exclusive to 0x0000
+     * 0x8408 is the result of 0x1021 bitwise reversal.
+     *
+     * @param buffer
+     * @return
+     */
+    public static int CRC16_CCITT(byte[] buffer) {
+        int wCRCin = 0x0000;
+        int wCPoly = 0x8408;
+        for (byte b : buffer) {
+            wCRCin ^= ((int) b & 0x00ff);
+            for (int j = 0; j < 8; j++) {
+                if ((wCRCin & 0x0001) != 0) {
+                    wCRCin >>= 1;
+                    wCRCin ^= wCPoly;
+                } else {
+                    wCRCin >>= 1;
+                }
+            }
+        }
+//        wCRCin=(wCRCin<<8)|(wCRCin>>8);
+//        wCRCin &= 0xffff;
+        return wCRCin ^= 0x0000;
+
+    }
+
+    /**
+     * CRC-CCITT (0xFFFF)
+     * CRC16_CCITT_FALSE: Polynomial x16+x12+x5+1 (0x1021), initial value 0xFFFF, low bit is after, high bit is first, result is exclusive to 0x0000
+     *
+     * @param buffer
+     * @return
+     */
+    public static int CRC16_CCITT_FALSE(byte[] buffer) {
+        int wCRCin = 0xffff;
+        int wCPoly = 0x1021;
+        for (byte b : buffer) {
+            for (int i = 0; i < 8; i++) {
+                boolean bit = ((b >> (7 - i) & 1) == 1);
+                boolean c15 = ((wCRCin >> 15 & 1) == 1);
+                wCRCin <<= 1;
+                if (c15 ^ bit)
+                    wCRCin ^= wCPoly;
+            }
+        }
+        wCRCin &= 0xffff;
+        return wCRCin ^= 0x0000;
+    }
+
+    /**
+     * CRC-CCITT (XModem)
+     * CRC16_XMODEM: Polynomial x16+x12+x5+1 (0x1021), initial value 0x0000, low bit after, high bit first, result is XOR0
+     *
+     * @param buffer
+     * @return
+     */
+    public static int CRC16_XMODEM(byte[] buffer) {
+        int wCRCin = 0x0000; // initial value 65535
+        int wCPoly = 0x1021; // 0001 0000 0010 0001 (0, 5, 12)
+        for (byte b : buffer) {
+            for (int i = 0; i < 8; i++) {
+                boolean bit = ((b >> (7 - i) & 1) == 1);
+                boolean c15 = ((wCRCin >> 15 & 1) == 1);
+                wCRCin <<= 1;
+                if (c15 ^ bit)
+                    wCRCin ^= wCPoly;
+            }
+        }
+        wCRCin &= 0xffff;
+        return wCRCin ^= 0x0000;
+    }
+
+
+    /**
+     * CRC16_X25: Polynomial x16+x12+x5+1 (0x1021), initial value 0xffff, low bit first, high bit after, result is XORIF 0xFFFF
+     * 0x8408 is the result of 0x1021 bitwise reversal.
+     *
+     * @param buffer
+     * @return
+     */
+    public static int CRC16_X25(byte[] buffer) {
+        int wCRCin = 0xffff;
+        int wCPoly = 0x8408;
+        for (byte b : buffer) {
+            wCRCin ^= ((int) b & 0x00ff);
+            for (int j = 0; j < 8; j++) {
+                if ((wCRCin & 0x0001) != 0) {
+                    wCRCin >>= 1;
+                    wCRCin ^= wCPoly;
+                } else {
+                    wCRCin >>= 1;
+                }
+            }
+        }
+        return wCRCin ^= 0xffff;
+    }
+
+    /**
+     * CRC-16 (Modbus)
+     * CRC16_MODBUS: Polynomial x16+x15+x2+1 (0x8005), initial value 0xFFFF, low bit first, high bit after, result is X2000000 exclusive OR
+     * 0xA001 is the result of 0x8005 bitwise reversal
+     *
+     * @param buffer
+     * @return
+     */
+    public static int CRC16_MODBUS(byte[] buffer) {
+        int wCRCin = 0xffff;
+        int POLYNOMIAL = 0xa001;
+        for (byte b : buffer) {
+            wCRCin ^= ((int) b & 0x00ff);
+            for (int j = 0; j < 8; j++) {
+                if ((wCRCin & 0x0001) != 0) {
+                    wCRCin >>= 1;
+                    wCRCin ^= POLYNOMIAL;
+                } else {
+                    wCRCin >>= 1;
+                }
+            }
+        }
+        return wCRCin ^= 0x0000;
+    }
+
+    /**
+     * CRC-16
+     * CRC16_IBM: Polynomial x16+x15+x2+1 (0x8005), initial value 0x0000, low bit first, high bit after, result is XOR0
+     * 0xA001 is the result of 0x8005 bitwise reversal
+     *
+     * @param buffer
+     * @return
+     */
+    public static int CRC16_IBM(byte[] buffer) {
+        int wCRCin = 0x0000;
+        int wCPoly = 0xa001;
+        for (byte b : buffer) {
+            wCRCin ^= ((int) b & 0x00ff);
+            for (int j = 0; j < 8; j++) {
+                if ((wCRCin & 0x0001) != 0) {
+                    wCRCin >>= 1;
+                    wCRCin ^= wCPoly;
+                } else {
+                    wCRCin >>= 1;
+                }
+            }
+        }
+        return wCRCin ^= 0x0000;
+    }
+
+    /**
+     * CRC16_MAXIM: Polynomial x16+x15+x2+1 (0x8005), initial value 0x0000, low bit first, high bit after, result is XORIF 0xFFFF
+     * 0xA001 is the result of 0x8005 bitwise reversal
+     *
+     * @param buffer
+     * @return
+     */
+    public static int CRC16_MAXIM(byte[] buffer) {
+        int wCRCin = 0x0000;
+        int wCPoly = 0xa001;
+        for (byte b : buffer) {
+            wCRCin ^= ((int) b & 0x00ff);
+            for (int j = 0; j < 8; j++) {
+                if ((wCRCin & 0x0001) != 0) {
+                    wCRCin >>= 1;
+                    wCRCin ^= wCPoly;
+                } else {
+                    wCRCin >>= 1;
+                }
+            }
+        }
+        return wCRCin ^= 0xffff;
+    }
+
+    /**
+     * CRC16_USB: Polynomial x16+x15+x2+1 (0x8005), initial value 0xFFFF, low bit first, high bit after, result is XORIF 0xFFFF
+     * 0xA001 is the result of 0x8005 bitwise reversal
+     *
+     * @param buffer
+     * @return
+     */
+    public static int CRC16_USB(byte[] buffer) {
+        int wCRCin = 0xFFFF;
+        int wCPoly = 0xa001;
+        for (byte b : buffer) {
+            wCRCin ^= ((int) b & 0x00ff);
+            for (int j = 0; j < 8; j++) {
+                if ((wCRCin & 0x0001) != 0) {
+                    wCRCin >>= 1;
+                    wCRCin ^= wCPoly;
+                } else {
+                    wCRCin >>= 1;
+                }
+            }
+        }
+        return wCRCin ^= 0xffff;
+    }
+
+    /**
+     * CRC16_DNP: Polynomial x16+x13+x12+x11+x10+x8+x6+x5+x2+1 (0x3D65), initial value 0x0000, low bit first, high bit after, result is XORIF 0xFFFF
+     * 0xA6BC is the result of 0x3D65 bitwise reversal
+     *
+     * @param buffer
+     * @return
+     */
+    public static int CRC16_DNP(byte[] buffer) {
+        int wCRCin = 0x0000;
+        int wCPoly = 0xA6BC;
+        for (byte b : buffer) {
+            wCRCin ^= ((int) b & 0x00ff);
+            for (int j = 0; j < 8; j++) {
+                if ((wCRCin & 0x0001) != 0) {
+                    wCRCin >>= 1;
+                    wCRCin ^= wCPoly;
+                } else {
+                    wCRCin >>= 1;
+                }
+            }
+        }
+        return wCRCin ^= 0xffff;
+    }
+}

+ 83 - 0
src/main/java/com/tsi/app/common/utils/CRC16Utils.java

@@ -0,0 +1,83 @@
+package com.tsi.app.common.utils;
+
+public class CRC16Utils {
+    private static final int CRC16_ccitt_table[] = {
+        0x0000, 0x1189, 0x2312, 0x329B, 0x4624, 0x57AD, 0x6536, 0x74BF,
+        0x8C48, 0x9DC1, 0xAF5A, 0xBED3, 0xCA6C, 0xDBE5, 0xE97E, 0xF8F7,
+        0x1081, 0x0108, 0x3393, 0x221A, 0x56A5, 0x472C, 0x75B7, 0x643E,
+        0x9CC9, 0x8D40, 0xBFDB, 0xAE52, 0xDAED, 0xCB64, 0xF9FF, 0xE876,
+        0x2102, 0x308B, 0x0210, 0x1399, 0x6726, 0x76AF, 0x4434, 0x55BD,
+        0xAD4A, 0xBCC3, 0x8E58, 0x9FD1, 0xEB6E, 0xFAE7, 0xC87C, 0xD9F5,
+        0x3183, 0x200A, 0x1291, 0x0318, 0x77A7, 0x662E, 0x54B5, 0x453C,
+        0xBDCB, 0xAC42, 0x9ED9, 0x8F50, 0xFBEF, 0xEA66, 0xD8FD, 0xC974,
+        0x4204, 0x538D, 0x6116, 0x709F, 0x0420, 0x15A9, 0x2732, 0x36BB,
+        0xCE4C, 0xDFC5, 0xED5E, 0xFCD7, 0x8868, 0x99E1, 0xAB7A, 0xBAF3,
+        0x5285, 0x430C, 0x7197, 0x601E, 0x14A1, 0x0528, 0x37B3, 0x263A,
+        0xDECD, 0xCF44, 0xFDDF, 0xEC56, 0x98E9, 0x8960, 0xBBFB, 0xAA72,
+        0x6306, 0x728F, 0x4014, 0x519D, 0x2522, 0x34AB, 0x0630, 0x17B9,
+        0xEF4E, 0xFEC7, 0xCC5C, 0xDDD5, 0xA96A, 0xB8E3, 0x8A78, 0x9BF1,
+        0x7387, 0x620E, 0x5095, 0x411C, 0x35A3, 0x242A, 0x16B1, 0x0738,
+        0xFFCF, 0xEE46, 0xDCDD, 0xCD54, 0xB9EB, 0xA862, 0x9AF9, 0x8B70,
+        0x8408, 0x9581, 0xA71A, 0xB693, 0xC22C, 0xD3A5, 0xE13E, 0xF0B7,
+        0x0840, 0x19C9, 0x2B52, 0x3ADB, 0x4E64, 0x5FED, 0x6D76, 0x7CFF,
+        0x9489, 0x8500, 0xB79B, 0xA612, 0xD2AD, 0xC324, 0xF1BF, 0xE036,
+        0x18C1, 0x0948, 0x3BD3, 0x2A5A, 0x5EE5, 0x4F6C, 0x7DF7, 0x6C7E,
+        0xA50A, 0xB483, 0x8618, 0x9791, 0xE32E, 0xF2A7, 0xC03C, 0xD1B5,
+        0x2942, 0x38CB, 0x0A50, 0x1BD9, 0x6F66, 0x7EEF, 0x4C74, 0x5DFD,
+        0xB58B, 0xA402, 0x9699, 0x8710, 0xF3AF, 0xE226, 0xD0BD, 0xC134,
+        0x39C3, 0x284A, 0x1AD1, 0x0B58, 0x7FE7, 0x6E6E, 0x5CF5, 0x4D7C,
+        0xC60C, 0xD785, 0xE51E, 0xF497, 0x8028, 0x91A1, 0xA33A, 0xB2B3,
+        0x4A44, 0x5BCD, 0x6956, 0x78DF, 0x0C60, 0x1DE9, 0x2F72, 0x3EFB,
+        0xD68D, 0xC704, 0xF59F, 0xE416, 0x90A9, 0x8120, 0xB3BB, 0xA232,
+        0x5AC5, 0x4B4C, 0x79D7, 0x685E, 0x1CE1, 0x0D68, 0x3FF3, 0x2E7A,
+        0xE70E, 0xF687, 0xC41C, 0xD595, 0xA12A, 0xB0A3, 0x8238, 0x93B1,
+        0x6B46, 0x7ACF, 0x4854, 0x59DD, 0x2D62, 0x3CEB, 0x0E70, 0x1FF9,
+        0xF78F, 0xE606, 0xD49D, 0xC514, 0xB1AB, 0xA022, 0x92B9, 0x8330,
+        0x7BC7, 0x6A4E, 0x58D5, 0x495C, 0x3DE3, 0x2C6A, 0x1EF1, 0x0F78
+    };
+
+    public static int CRC16_CCITT_FALSE(byte[] bytes, int start, int length) {
+        int crc = 0xffff; // initial value
+        int polynomial = 0x1021; // poly value
+        for (int index = start; index < length; index++) {
+            byte b = bytes[index];
+            for (int i = 0; i < 8; i++) {
+                boolean bit = ((b >> (7 - i) & 1) == 1);
+                boolean c15 = ((crc >> 15 & 1) == 1);
+                crc <<= 1;
+                if (c15 ^ bit)
+                    crc ^= polynomial;
+            }
+        }
+        crc &= 0xffff;
+        return crc;
+    }
+
+    public static int CRC16_CCITT(byte[] bytes, int start, int length) {
+        int crc = 0x0000; // initial value
+        int polynomial = 0x8408;// poly value reversed 0x1021;
+
+        int i, j;
+        for (i = start; i < length; i++) {
+            crc ^= ((int) bytes[i] & 0x000000ff);
+            for (j = 0; j < 8; j++) {
+                if ((crc & 0x00000001) != 0) {
+                    crc >>= 1;
+                    crc ^= polynomial;
+                } else {
+                    crc >>= 1;
+                }
+            }
+        }
+        return crc;
+    }
+    //static int CRC16_ccitt_false(byte [] data, int start, int length) {
+    public static int CRC16_ccitt_cvim(byte [] data, int start, int length) {
+        int crc16 = 0xFFFF;
+        for (int ii = start; ii < length+start; ii++) {
+            crc16 =  CRC16_ccitt_table[(crc16 ^ data[ii]) & 0xFF] ^ (crc16 >> 8);
+        }
+        return crc16 & 0xFFFF;
+    }
+
+}

+ 22 - 0
src/main/java/com/tsi/app/common/utils/Converter.java

@@ -0,0 +1,22 @@
+package com.tsi.app.common.utils;
+
+public class Converter {
+
+    private Converter() {}
+
+    public static String getSize(double bytes) {
+        final long kilo = 1024;
+
+        double kb = bytes / kilo;
+        double mb = kb / kilo;
+        double gb = mb / kilo;
+        double tb = gb / kilo;
+
+        if (tb > 1.0D) return String.format("%.2f TB", tb);
+        if (gb > 1.0D) return String.format("%.2f GB", gb);
+        if (mb > 1.0D) return String.format("%.2f MB", mb);
+        if (kb > 1.0D) return String.format("%.2f KB", kb);
+
+        return String.format("%.2f Bytes", bytes);
+    }
+}

+ 38 - 0
src/main/java/com/tsi/app/common/utils/Counter.java

@@ -0,0 +1,38 @@
+package com.tsi.app.common.utils;
+
+import java.util.concurrent.atomic.AtomicLong;
+
+public class Counter {
+
+    private AtomicLong counter;
+
+    public Counter() {
+        this.counter = new AtomicLong(0);
+    }
+
+    public long reset() {
+        return this.counter.getAndSet(0);
+    }
+    public long reset(long value) {
+        return this.counter.getAndSet(0);
+    }
+
+    public long increment() {
+        return this.counter.incrementAndGet();
+    }
+    public long add(long value) {
+        return this.counter.addAndGet(value);
+    }
+
+    public long decrement() {
+        return this.counter.decrementAndGet();
+    }
+    public long get() {
+        return this.counter.get();
+    }
+
+    @Override
+    public String toString() {
+        return Converter.getSize(this.counter.doubleValue());
+    }
+}

+ 31 - 0
src/main/java/com/tsi/app/common/utils/Elapsed.java

@@ -0,0 +1,31 @@
+package com.tsi.app.common.utils;
+
+import java.util.concurrent.TimeUnit;
+
+public class Elapsed {
+
+	private long sTime = 0;
+
+	public Elapsed() {
+		reset();
+	}
+
+	private long getElapsed() {
+		return System.nanoTime() - sTime;
+	}
+	public long nanoSeconds() {
+		return getElapsed();
+	}
+
+	public long milliSeconds() {
+		return TimeUnit.MILLISECONDS.convert(getElapsed(), TimeUnit.NANOSECONDS);
+	}
+
+	public long seconds() {
+		return TimeUnit.SECONDS.convert(getElapsed(), TimeUnit.NANOSECONDS);
+	}
+	
+	public void reset() {
+		sTime = System.nanoTime();
+	}
+}

+ 122 - 0
src/main/java/com/tsi/app/common/utils/HexString.java

@@ -0,0 +1,122 @@
+package com.tsi.app.common.utils;
+
+import java.nio.ByteBuffer;
+import java.util.Objects;
+
+public class HexString {
+    private static final char[] hexArray = "0123456789ABCDEF".toCharArray();
+
+    private HexString() {}
+
+    public static String fromByte(byte b) {
+        return fromBytes(new byte[] {b});
+    }
+
+    public static String fromByte(int b) {
+        return fromBytes(new byte[] {(byte) b});
+    }
+
+    public static String fromInt(int i) {
+        byte[] bytes = new byte[] {(byte) (i >> 24), (byte) (i >> 16), (byte) (i >> 8), (byte) (i)};
+        return fromBytes(bytes);
+    }
+
+    public static String fromLong(long l) {
+        byte[] bytes =
+                new byte[] {
+                        (byte) (l >> 56),
+                        (byte) (l >> 48),
+                        (byte) (l >> 40),
+                        (byte) (l >> 32),
+                        (byte) (l >> 24),
+                        (byte) (l >> 16),
+                        (byte) (l >> 8),
+                        (byte) (l)
+                };
+        return fromBytes(bytes);
+    }
+
+    public static String fromBytes(byte[] bytes) {
+        return fromBytes(bytes, 0, bytes.length);
+    }
+
+    public static String fromBytesFormatted(byte[] bytes) {
+        return fromBytesFormatted(bytes, 0, bytes.length);
+    }
+
+    public static String fromBytes(byte[] bytes, int offset, int length) {
+        char[] hexChars = new char[length * 2];
+        for (int j = 0; j < length; j++) {
+            int v = bytes[j + offset] & 0xff;
+            hexChars[j * 2] = hexArray[v >>> 4];
+            hexChars[j * 2 + 1] = hexArray[v & 0x0f];
+        }
+        return new String(hexChars);
+    }
+
+    public static String fromBytesSpace(byte[] bytes, int offset, int length) {
+        char[] hexChars = new char[length * 3];
+        for (int j = 0; j < length; j++) {
+            int v = bytes[j + offset] & 0xff;
+            hexChars[j * 2    ] = hexArray[v >>> 4];
+            hexChars[j * 2 + 1] = hexArray[v & 0x0f];
+            hexChars[j * 2 + 2] = ' ';
+        }
+        return new String(hexChars);
+    }
+
+    public static String fromBytes(ByteBuffer buffer) {
+        return fromBytes(buffer.array(), buffer.arrayOffset(), buffer.arrayOffset() + buffer.limit());
+    }
+
+    public static String fromBytesFormatted(byte[] bytes, int offset, int length) {
+        StringBuilder builder = new StringBuilder();
+
+        int l = 1;
+        for (int i = offset; i < (offset + length); i++) {
+            if ((l != 1) && ((l - 1) % 8 == 0)) {
+                builder.append(' ');
+            }
+            if ((l != 1) && ((l - 1) % 16 == 0)) {
+                builder.append('\n');
+            }
+            l++;
+            appendFromByte(bytes[i], builder);
+            if (i != offset + length - 1) {
+                builder.append(' ');
+            }
+        }
+        return builder.toString();
+    }
+
+    public static byte[] toBytes(String hexString) {
+
+        Objects.requireNonNull(hexString);
+        if ((hexString.length() == 0) || ((hexString.length() % 2) != 0)) {
+            throw new NumberFormatException("argument is not a valid hex string");
+        }
+
+        int length = hexString.length();
+
+        byte[] data = new byte[length / 2];
+        for (int i = 0; i < length; i += 2) {
+            int firstCharacter = Character.digit(hexString.charAt(i), 16);
+            int secondCharacter = Character.digit(hexString.charAt(i + 1), 16);
+
+            if (firstCharacter == -1 || secondCharacter == -1) {
+                throw new NumberFormatException("argument is not a valid hex string");
+            }
+
+            data[i / 2] = (byte) ((firstCharacter << 4) + secondCharacter);
+        }
+        return data;
+    }
+
+    public static void appendFromByte(byte b, StringBuilder builder) {
+        builder.append(fromByte(b));
+    }
+
+    public static void appendFromBytes(StringBuilder builder, byte[] bytes, int offset, int length) {
+        builder.append(fromBytes(bytes, offset, length));
+    }
+}

+ 76 - 0
src/main/java/com/tsi/app/common/utils/LockFreeStack.java

@@ -0,0 +1,76 @@
+package com.tsi.app.common.utils;
+
+import java.util.concurrent.atomic.AtomicInteger;
+import java.util.concurrent.atomic.AtomicReference;
+import java.util.concurrent.locks.LockSupport;
+
+public class LockFreeStack<T> {
+
+    private AtomicReference<StackNode<T> > headNode = new AtomicReference<StackNode<T> >();
+    private AtomicInteger remains = new AtomicInteger(0);
+
+    // Push operation
+    public boolean offer(T value)
+    {
+        StackNode<T> newHead = new StackNode<T>(value);
+
+        // CAS loop defined
+        while (true) {
+            StackNode<T> currentHeadNode = headNode.get();
+            newHead.next = currentHeadNode;
+
+            // perform CAS operation before setting new
+            // value
+            if (headNode.compareAndSet(currentHeadNode, newHead)) {
+                break;
+            }
+            else {
+                // waiting for a nanosecond
+                LockSupport.parkNanos(1);
+            }
+        }
+
+        // getting the value atomically
+        remains.incrementAndGet();
+        return true;
+    }
+
+    // Pop function
+    public T take()
+    {
+        StackNode<T> currentHeadNode = headNode.get();
+
+        // CAS loop defined
+        while (currentHeadNode != null) {
+            StackNode<T> newHead = currentHeadNode.next;
+            if (headNode.compareAndSet(currentHeadNode,
+                    newHead)) {
+                break;
+            }
+            else {
+                // waiting for a nanosecond
+                LockSupport.parkNanos(1);
+                currentHeadNode = headNode.get();
+            }
+        }
+
+        T t = currentHeadNode != null ? currentHeadNode.value : null;
+
+        if (t != null)
+            remains.decrementAndGet();
+
+        return t;
+    }
+
+    public int size() {
+        return (int)remains.get();
+    }
+
+    private static class StackNode<T> {
+        T value;
+        StackNode<T> next;
+        StackNode(T value) { this.value = value; }
+
+        public T getValue() { return this.value; }
+    }
+}

+ 82 - 0
src/main/java/com/tsi/app/common/utils/NonBlockingQueue.java

@@ -0,0 +1,82 @@
+package com.tsi.app.common.utils;
+
+import java.util.concurrent.atomic.AtomicInteger;
+import java.util.concurrent.atomic.AtomicReference;
+
+public class NonBlockingQueue<T> {
+
+    private final AtomicReference<Node<T>> head, tail;
+    private final AtomicInteger size;
+
+    public NonBlockingQueue() {
+        head = new AtomicReference<>(null);
+        tail = new AtomicReference<>(null);
+        size = new AtomicInteger();
+        size.set(0);
+    }
+
+    public boolean offer(T element) {
+        if (element == null) {
+            return false;//throw new NullPointerException();
+        }
+
+        Node<T> node = new Node<>(element);
+        Node<T> currentTail;
+        do {
+            currentTail = tail.get();
+            node.setPrevious(currentTail);
+        } while(!tail.compareAndSet(currentTail, node));
+
+        if(node.previous != null) {
+            node.previous.next = node;
+        }
+
+        head.compareAndSet(null, node); //if we are inserting the first element
+        size.incrementAndGet();
+        return true;
+    }
+
+    public T take() {
+        if(head.get() == null) {
+            return null;
+            //throw new NoSuchElementException();
+        }
+
+        Node<T> currentHead;
+        Node<T> nextNode;
+        do {
+            currentHead = head.get();
+            nextNode = currentHead.getNext();
+        } while(!head.compareAndSet(currentHead, nextNode));
+
+        size.decrementAndGet();
+        return currentHead.getValue();
+    }
+
+    public int size() {
+        return this.size.get();
+    }
+
+    private class Node<T> {
+        private final T value;
+        private volatile Node<T> next;
+        private volatile Node<T> previous;
+
+        public Node(T value) {
+            this.value = value;
+            this.next = null;
+        }
+
+        public T getValue() {
+            return value;
+        }
+
+        public Node<T> getNext() {
+            return next;
+        }
+
+        public void setPrevious(Node<T> previous) {
+            this.previous = previous;
+        }
+    }
+}

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

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

+ 44 - 0
src/main/java/com/tsi/app/common/utils/StringUtils.java

@@ -0,0 +1,44 @@
+package com.tsi.app.common.utils;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.StringTokenizer;
+
+public class StringUtils {
+
+    private StringUtils() {}
+
+    public static String getString(boolean value) {
+        return value ? "1" : "0";
+    }
+
+    public static List<String> splitEmpty(String value, String separator) {
+        List<String> results = new ArrayList<String>();
+        StringTokenizer stringTokenizer = new StringTokenizer(value, separator);
+        while (stringTokenizer.hasMoreTokens()) {
+            results.add(stringTokenizer.nextToken().trim());
+        }
+        return results;
+    }
+
+    public static List<String> split(String value, String separator) {
+        String[] splits = value.split(separator);
+        List<String> results = new ArrayList<String>();
+        for (int ii = 0; ii < splits.length; ii++) {
+            splits[ii] = splits[ii].trim();
+            if (splits[ii].length() > 0) {
+                results.add(splits[ii]);
+            }
+        }
+        return results;
+    }
+
+    public static boolean isEmpty(String str) {
+        return str == null || str.length() == 0;
+    }
+
+    public static boolean isBlank(String s) {
+        return s == null || s.trim().isEmpty();
+    }
+
+}

+ 171 - 0
src/main/java/com/tsi/app/common/utils/SysUtils.java

@@ -0,0 +1,171 @@
+package com.tsi.app.common.utils;
+
+import java.text.SimpleDateFormat;
+import java.util.Date;
+import java.util.GregorianCalendar;
+
+public class SysUtils {
+    public static int toInt(String paramVal, int defVal) {
+        int result = defVal;
+
+        try {
+            result = Integer.parseInt(paramVal);
+        } catch (Exception var4) {
+        }
+
+        return result;
+    }
+
+    public static float toFloat(String paramVal, float defVal) {
+        float result = defVal;
+
+        try {
+            result = Float.parseFloat(paramVal);
+        } catch (Exception var4) {
+        }
+
+        return result;
+    }
+
+    public static double toDouble(String paramVal, double defVal) {
+        double result = defVal;
+
+        try {
+            result = Double.parseDouble(paramVal);
+        } catch (Exception var6) {
+        }
+
+        return result;
+    }
+
+    public static String getSysTime() {
+        SimpleDateFormat sdfDate = new SimpleDateFormat("yyyyMMddHHmmss");
+        Date dtLog = new Date();
+        return sdfDate.format(dtLog);
+    }
+
+    public static String getSysTimeStr() {
+        SimpleDateFormat sdfDate = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
+        Date dtLog = new Date();
+        return sdfDate.format(dtLog);
+    }
+
+    public static int gapTime(String startTm, String endTm, int calcType) {
+        if (startTm != null && !startTm.equals("") && startTm.length() == 14) {
+            if (endTm != null && !endTm.equals("") && endTm.length() == 14) {
+                Date startDateTime = TimeUtils.stringToDate(startTm);
+                Date endDateTime = TimeUtils.stringToDate(endTm);
+                if (startDateTime != null && endDateTime != null) {
+                    GregorianCalendar gcStartDateTime = new GregorianCalendar();
+                    GregorianCalendar gcEndDateTime = new GregorianCalendar();
+                    gcStartDateTime.setTime(startDateTime);
+                    gcEndDateTime.setTime(endDateTime);
+                    long gap = gcEndDateTime.getTimeInMillis() - gcStartDateTime.getTimeInMillis();
+                    long hour = gap / 1000L / 60L / 60L;
+                    long min = gap / 1000L / 60L;
+                    long second = gap / 1000L;
+                    if (10 == calcType) {
+                        return (int)hour;
+                    } else if (12 == calcType) {
+                        return (int)min;
+                    } else {
+                        return 13 == calcType ? (int)second : -1;
+                    }
+                } else {
+                    return -1;
+                }
+            } else {
+                return -1;
+            }
+        } else {
+            return -1;
+        }
+    }
+
+    public static String byteArrayToString(byte[] data) {
+        StringBuilder sb = new StringBuilder(data.length);
+
+        for(int ii = 0; ii < data.length && data[ii] >= 33 && data[ii] <= 126; ++ii) {
+            sb.append((char)data[ii]);
+        }
+
+        return sb.toString();
+    }
+
+    public static String byteArrayToHex(byte[] AData) {
+        if (AData != null && AData.length != 0) {
+            int ALen = AData.length;
+            int line = ALen / 16;
+            StringBuffer sb = new StringBuffer(ALen * 3 + line);
+            sb.append("\r\n");
+
+            for(int ii = 0; ii < ALen; ii += 16) {
+                for(int jj = 0; jj < 16; ++jj) {
+                    int pos = ii + jj;
+                    if (pos >= ALen) {
+                        break;
+                    }
+
+                    String hexNumber = "0" + Integer.toHexString(255 & AData[pos]).toUpperCase();
+                    sb.append(hexNumber.substring(hexNumber.length() - 2));
+                    sb.append(" ");
+                }
+
+                sb.append("\r\n");
+            }
+
+            return sb.toString();
+        } else {
+            return "";
+        }
+    }
+
+    public static int getBitValue(byte b, int pos) {
+        int val = b >> pos & 1;
+        return val;
+    }
+
+    public static long ipToLong(String ipAddress) {
+        String[] ipAddressInArray = ipAddress.split("\\.");
+        long result = 0L;
+
+        for(int i = 0; i < ipAddressInArray.length; ++i) {
+            int power = 3 - i;
+            int ip = Integer.parseInt(ipAddressInArray[i]);
+            result = (long)((double)result + (double)ip * Math.pow(256.0D, (double)power));
+        }
+
+        return result;
+    }
+
+    public static long ipToLong2(String ipAddress) {
+        long result = 0L;
+        String[] ipAddressInArray = ipAddress.split("\\.");
+
+        for(int i = 3; i >= 0; --i) {
+            long ip = Long.parseLong(ipAddressInArray[3 - i]);
+            result |= ip << i * 8;
+        }
+
+        return result;
+    }
+
+    public static String longToIp(long i) {
+        return (i >> 24 & 255L) + "." + (i >> 16 & 255L) + "." + (i >> 8 & 255L) + "." + (i & 255L);
+    }
+
+    public static String longToIp2(long ip) {
+        StringBuilder sb = new StringBuilder(15);
+
+        for(int i = 0; i < 4; ++i) {
+            sb.insert(0, Long.toString(ip & 255L));
+            if (i < 3) {
+                sb.insert(0, '.');
+            }
+
+            ip >>= 8;
+        }
+
+        return sb.toString();
+    }
+}

+ 295 - 0
src/main/java/com/tsi/app/common/utils/TimeUtils.java

@@ -0,0 +1,295 @@
+package com.tsi.app.common.utils;
+
+import java.text.ParseException;
+import java.text.SimpleDateFormat;
+import java.util.Calendar;
+import java.util.Date;
+import java.util.concurrent.TimeUnit;
+
+public class TimeUtils {
+    public static final int TYPE_CURR_05MIN = 0;
+    public static final int TYPE_PRCS_05MIN = 1;
+    public static final int TYPE_PRCS_15MIN = 2;
+    public static final int TYPE_PRCS_HOUR = 3;
+    public static final int TYPE_PRCS_DAY = 4;
+    public static final int TYPE_PRCS_MONTH = 5;
+    public static final int TYPE_PRCS_YEAR = 6;
+
+    private TimeUtils() {}
+
+    public static String elapsedTime(long startTime, long endTime) {
+        return elapsedTimeStr(endTime - startTime);
+    }
+    public static String elapsedTime(long startTime) {
+        return elapsedTimeStr(System.nanoTime() - startTime);
+    }
+    public static String elapsedTimeStr(long elapsed) {
+        long seconds = TimeUnit.SECONDS.convert(elapsed, TimeUnit.NANOSECONDS);
+        long miliSeconds = TimeUnit.MILLISECONDS.convert(elapsed, TimeUnit.NANOSECONDS) % 1000;
+        long microSeconds = TimeUnit.MICROSECONDS.convert(elapsed, TimeUnit.NANOSECONDS) % 1000;
+        long nanoSeconds = TimeUnit.NANOSECONDS.convert(elapsed, TimeUnit.NANOSECONDS) % 1000;
+
+        if (seconds > 0) {
+            return String.format("Elapsed: %,d sec. %3d ms. %d us. %3d ns.", seconds, miliSeconds, microSeconds, nanoSeconds);
+        }
+        if (miliSeconds > 0) {
+            return String.format("Elapsed: %3d ms. %3d us. %3d ns.", miliSeconds, microSeconds, nanoSeconds);
+        }
+        if (microSeconds > 0) {
+            return String.format("Elapsed: --- ms. %3d us. %3d ns.", microSeconds, nanoSeconds);
+        }
+        return String.format("Elapsed: --- ms. --- us. %3d ns.", nanoSeconds);
+    }
+    public static long currentElapsedTime() {
+        return System.nanoTime() / 1000000;
+    }
+    public static long currentTimeMillis() {
+        return System.currentTimeMillis();
+    }
+    public static long currentTimeSeconds() {
+        return TimeUnit.SECONDS.convert(System.currentTimeMillis(), TimeUnit.MILLISECONDS);
+    }
+    public static Date elapsedTimeToDate(long elapsedTime) {
+        long wallTime = currentTimeMillis() + elapsedTime - currentElapsedTime();
+        return new Date(wallTime);
+    }
+
+    public static String getCurrentTimeString() {
+        Calendar cal = Calendar.getInstance();
+        return (new SimpleDateFormat("yyyyMMddHHmmss")).format(cal.getTime());
+    }
+
+    public static String getCurrentTimeString(String parmaFmt) {
+        Calendar cal = Calendar.getInstance();
+        return (new SimpleDateFormat(parmaFmt)).format(cal.getTime());
+    }
+
+    public static Date getCurrentDate() {
+        Calendar cal = Calendar.getInstance();
+        return cal.getTime();
+    }
+
+    public static Date stringToDate(String paramTime) {
+        SimpleDateFormat transFormat = new SimpleDateFormat("yyyyMMddHHmmss");
+        Date to = null;
+
+        try {
+            to = transFormat.parse(paramTime);
+        } catch (ParseException var4) {
+            var4.printStackTrace();
+        }
+
+        return to;
+    }
+
+    public static String dateToString(Date paramDt, String paramFmt) {
+        Calendar cal = Calendar.getInstance();
+        cal.setTime(paramDt);
+        return (new SimpleDateFormat(paramFmt)).format(cal.getTime());
+    }
+
+    public static String dateToString(Date paramDt) {
+        Calendar cal = Calendar.getInstance();
+        cal.setTime(paramDt);
+        return (new SimpleDateFormat("yyyyMMddHHmmss")).format(cal.getTime());
+    }
+
+    public static String getNowDatetime() {
+        Date today = new Date();
+        SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss.SSSZ");
+        return sdf.format(today);
+    }
+
+    public static long getCurrentTimeSeconds() {
+        Calendar cal = Calendar.getInstance();
+        return Math.round((double)cal.getTimeInMillis() / 1000.0D);
+    }
+
+    public static long getCurrentTimeMilliSeconds() {
+        Calendar cal = Calendar.getInstance();
+        return cal.getTimeInMillis();
+    }
+
+    public static String getFiveMinString(Date paramDt) {
+        Calendar cal = Calendar.getInstance();
+        cal.setTime(paramDt);
+        cal.set(13, 0);
+        cal.set(14, 0);
+        int min = cal.get(12);
+        cal.add(12, -(min % 5));
+        return (new SimpleDateFormat("yyyyMMddHHmmss")).format(cal.getTime());
+    }
+
+    public static String getFiveMinString() {
+        Calendar cal = Calendar.getInstance();
+        return getFiveMinString(cal.getTime());
+    }
+
+    private static String getItsTimeString(Date paramDt, int cycle, int period) {
+        Calendar cal = Calendar.getInstance();
+        cal.setTime(paramDt);
+        cal.set(13, 0);
+        cal.set(14, 0);
+        int min = cal.get(12);
+        cal.add(12, -(min % cycle) - cycle * period);
+        return (new SimpleDateFormat("yyyyMMddHHmmss")).format(cal.getTime());
+    }
+
+    private static String getItsTimeToString(Date paramDt, int type) {
+        Calendar cal = Calendar.getInstance();
+        cal.setTime(paramDt);
+        switch(type) {
+            case 0:
+            case 1:
+                cal.add(12, 5);
+                break;
+            case 2:
+                cal.add(12, 15);
+                break;
+            case 3:
+                cal.add(11, 1);
+                break;
+            case 4:
+                cal.add(5, 1);
+                break;
+            case 5:
+                cal.add(2, 1);
+                break;
+            case 6:
+                cal.add(1, 1);
+        }
+
+        cal.add(13, -1);
+        return (new SimpleDateFormat("yyyyMMddHHmmss")).format(cal.getTime());
+    }
+
+    public static String getTime(int type) {
+        Calendar cal = Calendar.getInstance();
+        return getTime(cal.getTime(), type);
+    }
+
+    public static String getTime(String paramStr, int type) {
+        Calendar cal = Calendar.getInstance();
+        cal.setTime(stringToDate(paramStr));
+        return getTime(cal.getTime(), type);
+    }
+
+    public static String getTime(Date paramDt, int type) {
+        switch(type) {
+            case 0:
+                return getItsTimeString(paramDt, 5, 0);
+            case 1:
+                return getItsTimeString(paramDt, 5, 1);
+            case 2:
+                return getItsTimeString(paramDt, 15, 1);
+            case 3:
+                return getItsTimeString(paramDt, 60, 1);
+            case 4:
+                return getItsTimeString(paramDt, 1440, 1).substring(0, 8) + "000000";
+            case 5:
+                return getItsTimeString(paramDt, 1440, 1).substring(0, 6) + "01000000";
+            case 6:
+                return getItsTimeString(paramDt, 1440, 1).substring(0, 4) + "0101000000";
+            default:
+                return "";
+        }
+    }
+
+    public static String getToTime(int type) {
+        String prcsTime = getTime(type);
+        return getToTime(prcsTime, type);
+    }
+
+    public static String getToTime(String paramStr, int type) {
+        Calendar cal = Calendar.getInstance();
+        cal.setTime(stringToDate(paramStr));
+        return getToTime(cal.getTime(), type);
+    }
+
+    public static String getToTime(Date paramDt, int type) {
+        return getItsTimeToString(paramDt, type);
+    }
+
+    public static String getCurrMin() {
+        Calendar cal = Calendar.getInstance();
+        return getItsTimeString(cal.getTime(), 5, 0);
+    }
+
+    public static String getCurrMin(String paramStr) {
+        return getItsTimeString(stringToDate(paramStr), 5, 0);
+    }
+
+    public static String getCurrMin(Date paramDt) {
+        return getItsTimeString(paramDt, 5, 0);
+    }
+
+    public static String get05Min() {
+        Calendar cal = Calendar.getInstance();
+        return getItsTimeString(cal.getTime(), 5, 1);
+    }
+
+    public static String get05Min(String paramStr) {
+        return getItsTimeString(stringToDate(paramStr), 5, 1);
+    }
+
+    public static String get05Min(Date paramDt) {
+        return getItsTimeString(paramDt, 5, 1);
+    }
+
+    public static String get15Min() {
+        Calendar cal = Calendar.getInstance();
+        return getItsTimeString(cal.getTime(), 15, 1);
+    }
+
+    public static String get15Min(String paramStr) {
+        return getItsTimeString(stringToDate(paramStr), 15, 1);
+    }
+
+    public static String get15Min(Date paramDt) {
+        return getItsTimeString(paramDt, 15, 1);
+    }
+
+    public static String getHour() {
+        Calendar cal = Calendar.getInstance();
+        return getItsTimeString(cal.getTime(), 60, 1);
+    }
+
+    public static String getHour(String paramStr) {
+        return getItsTimeString(stringToDate(paramStr), 60, 1);
+    }
+
+    public static String getHour(Date paramDt) {
+        return getItsTimeString(paramDt, 60, 1);
+    }
+
+    public static String getDay() {
+        Calendar cal = Calendar.getInstance();
+        return getItsTimeString(cal.getTime(), 1440, 1).substring(0, 8) + "000000";
+    }
+
+    public static String getDay(String paramStr) {
+        return getItsTimeString(stringToDate(paramStr), 1440, 1).substring(0, 8) + "000000";
+    }
+
+    public static String getDay(Date paramDt) {
+        return getItsTimeString(paramDt, 1440, 1).substring(0, 8) + "000000";
+    }
+
+    public static String getToString(Date paramDt) {
+        Calendar cal = Calendar.getInstance();
+        cal.setTime(paramDt);
+        cal.add(13, -1);
+        return (new SimpleDateFormat("yyyyMMddHHmmss")).format(cal.getTime());
+    }
+
+    public static String getFiveMinToString(Date paramDt) {
+        String strFiveMin = getFiveMinString(paramDt);
+        Date dtFiveMin = stringToDate(strFiveMin);
+        return getToString(dtFiveMin);
+    }
+
+    public static String getFiveMinToString() {
+        Calendar cal = Calendar.getInstance();
+        return getFiveMinToString(cal.getTime());
+    }
+}

+ 63 - 0
src/main/java/com/tsi/app/common/utils/Timespec.java

@@ -0,0 +1,63 @@
+package com.tsi.app.common.utils;
+
+import java.nio.ByteBuffer;
+import java.nio.ByteOrder;
+import java.util.concurrent.TimeUnit;
+
+public class Timespec {
+
+    protected long tv_sec;
+    protected long tv_nsec;
+
+    public Timespec(ByteBuffer buffer) {
+        buffer.order(ByteOrder.nativeOrder());
+        this.tv_sec = buffer.getLong();
+        this.tv_nsec = buffer.getLong();
+    }
+    public Timespec(long sec, long nsec) {
+        this.tv_sec = sec;
+        this.tv_nsec = nsec;
+    }
+    public Timespec() {
+        init();
+    }
+
+    public void init() {
+        this.tv_sec = TimeUnit.SECONDS.convert(System.currentTimeMillis(), TimeUnit.MILLISECONDS);
+        this.tv_nsec = System.nanoTime();
+    }
+    public void tv_nsec(long nsec) {
+        this.tv_nsec = nsec;
+    }
+    public void tv_sec(long sec) {
+        this.tv_sec = sec;
+    }
+    public void set(long nsec, long sec) {
+        this.tv_nsec = nsec;
+        this.tv_sec = sec;
+    }
+    public byte[] tv_sec() {
+        ByteBuffer buffer = ByteBuffer.allocate(8);
+        buffer.putLong(this.tv_sec);
+        return buffer.array();
+    }
+    public byte[] tv_nsec() {
+        ByteBuffer buffer = ByteBuffer.allocate(8);
+        buffer.putLong(this.tv_nsec);
+        return buffer.array();
+    }
+    public byte[] bytes() {
+        ByteBuffer buffer = ByteBuffer.allocate(16);
+        buffer.order(ByteOrder.LITTLE_ENDIAN);
+        buffer.putLong(this.tv_sec);
+        buffer.putLong(this.tv_nsec);
+        return buffer.array();
+    }
+    public long timestamp() {
+        return this.tv_nsec;
+    }
+    public long times() {
+        return this.tv_sec;
+    }
+
+}

+ 109 - 0
src/main/java/com/tsi/comm/consumer/TsiCommConsumerApplication.java

@@ -0,0 +1,109 @@
+package com.tsi.comm.consumer;
+
+import com.tsi.comm.consumer.kafka.KafkaConsumerService;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.boot.ApplicationArguments;
+import org.springframework.boot.ApplicationRunner;
+import org.springframework.boot.Banner;
+import org.springframework.boot.SpringApplication;
+import org.springframework.boot.autoconfigure.SpringBootApplication;
+import org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration;
+import org.springframework.boot.builder.SpringApplicationBuilder;
+import org.springframework.context.ApplicationListener;
+import org.springframework.context.event.ContextClosedEvent;
+
+import java.text.SimpleDateFormat;
+import java.util.Date;
+import java.util.List;
+import java.util.Set;
+
+@Slf4j
+@SpringBootApplication(exclude = { DataSourceAutoConfiguration.class })
+public class TsiCommConsumerApplication implements ApplicationRunner, ApplicationListener<ContextClosedEvent> {
+
+    private static String bootstrapServers = "172.24.0.30:9092,172.24.0.31:9093,172.24.0.32:9094";
+    private static String topic = "node";
+    private static String consumerGroup = "tsi-consumer";
+    private static String nodeId = "";
+
+    private KafkaConsumerService kafkaConsumerService = null;
+
+    // --servers=172.24.0.30:9092,172.24.0.31:9093,172.24.0.32:9094 --topic=node --group=tsi-consumer1 --key=1510017600
+    public static void main(String[] args) {
+        SpringApplication application = new SpringApplicationBuilder()
+                .sources(TsiCommConsumerApplication.class)
+                .build();
+        application.setBannerMode(Banner.Mode.OFF);
+        application.run(args);
+//        SpringApplication.run(TsiCommConsumerApplication.class, args);
+    }
+
+    @Override
+    public void run(ApplicationArguments args) throws Exception {
+//        boolean debug = args.containsOption("debug");
+//        List<String> files = args.getNonOptionArgs();
+//        String[] sourceArgs = args.getSourceArgs();
+//        List<String> nonOptionArgs = args.getNonOptionArgs();
+        Set<String> optionNames = args.getOptionNames();
+
+//        log.error("sourceArgs: {}", sourceArgs);
+        boolean helpOptions = args.containsOption("help");
+        if (helpOptions) {
+            usage();
+            return;
+        }
+
+        boolean nodeOptions = args.containsOption("key");
+        if (!nodeOptions) {
+            log.error("****** key options are required.");
+            usage();
+            return;
+        }
+
+        for (String optionName : optionNames) {
+            List<String> optionValues = args.getOptionValues(optionName);
+            for (String optionValue : optionValues) {
+                if ("key".equals(optionName)) {
+                    nodeId = optionValue;
+                }
+                else if ("servers".equals(optionName)) {
+                    bootstrapServers = optionValue;
+                }
+                else if ("topic".equals(optionName)) {
+                    topic = optionValue;
+                }
+                else if ("group".equals(optionName)) {
+                    consumerGroup = optionValue;
+                }
+            }
+        }
+
+        if (!"node".equals(topic) && !"test".equals(topic) && !"cvim".equals(topic)) {
+            usage();
+            return;
+        }
+        kafkaConsumerService = new KafkaConsumerService(bootstrapServers, topic, consumerGroup, nodeId);
+        kafkaConsumerService.start();
+    }
+
+    private void usage() {
+        log.info("\r\n\n\n\n\nUsage: java -jar tsi-consumer --servers=xxx.xxx.xxx.xxx:nnnn --topic=node --group:tsi-consumer --key=1510017600\n" +
+                "   --servers=kafka bootstrap server[optional, default=172.24.0.30:9092,172.24.0.31:9093,172.24.0.32:9094]\n" +
+                "   --topic=topic name[optional, node/test/cvim, default=node]\n" +
+                "   --group=kafka consumer group name[optional, default=tsi-consumer]\n" +
+                "   --key=node id\n\n\n\n");
+    }
+
+    @Override
+    public void onApplicationEvent(ContextClosedEvent event) {
+        SimpleDateFormat sdfDate = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
+        try {
+            if (kafkaConsumerService != null) {
+                kafkaConsumerService.shutdown();
+            }
+        } catch (Exception e) {
+            log.error("{}", e.getMessage());
+        }
+        log.error("Application Terminated: {}, {}", sdfDate.format(new Date()), event);
+    }
+}

+ 96 - 0
src/main/java/com/tsi/comm/consumer/kafka/KafkaConsumerService.java

@@ -0,0 +1,96 @@
+package com.tsi.comm.consumer.kafka;
+
+import lombok.RequiredArgsConstructor;
+import lombok.extern.slf4j.Slf4j;
+import org.apache.kafka.clients.consumer.Consumer;
+import org.apache.kafka.clients.consumer.ConsumerConfig;
+import org.apache.kafka.common.TopicPartition;
+import org.springframework.kafka.core.ConsumerFactory;
+import org.springframework.kafka.core.DefaultKafkaConsumerFactory;
+import org.springframework.kafka.listener.ConcurrentMessageListenerContainer;
+import org.springframework.kafka.listener.ConsumerAwareRebalanceListener;
+import org.springframework.kafka.listener.ContainerProperties;
+
+import java.util.Collection;
+import java.util.HashMap;
+import java.util.Map;
+
+@Slf4j
+@RequiredArgsConstructor
+public class KafkaConsumerService {
+
+    private final String bootstrapServers;
+    private final String topic;
+    private final String groupId;
+    private final String nodeId;
+
+    private ConcurrentMessageListenerContainer<String, byte[]> kafkaListenerContainer;
+
+    public void start() {
+        log.info("Starting Kafka: {}, {}, {}, {}", this.bootstrapServers, this.topic, this.groupId, this.nodeId);
+
+        String consumerTopic = this.nodeId;
+        if ("test".equals(this.topic)) {
+            consumerTopic = "topic-for-ssd-test";
+        }
+        if ("cvim".equals(topic)) {
+            consumerTopic = "cvim-raw";
+        }
+
+        ContainerProperties containerProperties = new ContainerProperties(consumerTopic);
+        containerProperties.setGroupId(this.groupId);
+        containerProperties.setPollTimeout(5000);
+        //containerProperties.setAckMode(ContainerProperties.AckMode.MANUAL);
+        containerProperties.setMessageListener(new TsiKafkaConsumerWorker(consumerTopic, this.nodeId));
+        containerProperties.setConsumerRebalanceListener(new ConsumerAwareRebalanceListener() {
+            @Override
+            public void onPartitionsRevokedBeforeCommit(Consumer<?, ?> consumer, Collection<TopicPartition> partitions) {
+            }
+            @Override
+            public void onPartitionsRevokedAfterCommit(Consumer<?, ?> consumer, Collection<TopicPartition> partitions) {
+            }
+            @Override
+            public void onPartitionsAssigned(Consumer<?, ?> consumer, Collection<TopicPartition> partitions) {
+                consumer.seekToEnd(partitions);
+            }
+        });
+
+        ConsumerFactory<String, byte[]> consumerFactory = new DefaultKafkaConsumerFactory<>(getConsumerPropertiesMap());
+        this.kafkaListenerContainer = new ConcurrentMessageListenerContainer<>(consumerFactory, containerProperties);
+        this.kafkaListenerContainer.setBeanName("consumer");
+        this.kafkaListenerContainer.setConcurrency(1);
+        this.kafkaListenerContainer.setErrorHandler((thrownException, data) -> {
+            log.error("kafkaListenerContainer error: {}", thrownException.getMessage());
+            this.kafkaListenerContainer.stop();
+        });
+
+        this.kafkaListenerContainer.start();
+    }
+
+    public Map<String, Object> getConsumerPropertiesMap() {
+        Map<String, Object> properties = new HashMap<>();
+        properties.put(ConsumerConfig.BOOTSTRAP_SERVERS_CONFIG, this.bootstrapServers);
+        properties.put(ConsumerConfig.GROUP_ID_CONFIG, this.groupId);
+        properties.put(ConsumerConfig.ENABLE_AUTO_COMMIT_CONFIG, "true");
+        properties.put(ConsumerConfig.AUTO_COMMIT_INTERVAL_MS_CONFIG, 1);
+        properties.put(ConsumerConfig.SESSION_TIMEOUT_MS_CONFIG, "10000");
+        properties.put(ConsumerConfig.AUTO_OFFSET_RESET_CONFIG, "latest");
+        properties.put(ConsumerConfig.MAX_POLL_INTERVAL_MS_CONFIG, "100");
+        properties.put(ConsumerConfig.CHECK_CRCS_CONFIG, false);
+        properties.put(ConsumerConfig.MAX_POLL_RECORDS_CONFIG, 1);
+        properties.put(ConsumerConfig.KEY_DESERIALIZER_CLASS_CONFIG, org.apache.kafka.common.serialization.StringDeserializer.class);
+        properties.put(ConsumerConfig.VALUE_DESERIALIZER_CLASS_CONFIG, org.apache.kafka.common.serialization.ByteArrayDeserializer.class);
+
+        return properties;
+    }
+
+    public void shutdown() {
+        try {
+            if (this.kafkaListenerContainer != null) {
+                this.kafkaListenerContainer.stop();
+            }
+        }
+        catch(Exception ignored) {
+        }
+    }
+}

+ 378 - 0
src/main/java/com/tsi/comm/consumer/kafka/TsiKafkaConsumerWorker.java

@@ -0,0 +1,378 @@
+package com.tsi.comm.consumer.kafka;
+
+import com.tsi.app.common.utils.SysUtils;
+import lombok.AllArgsConstructor;
+import lombok.extern.slf4j.Slf4j;
+import org.apache.kafka.clients.consumer.ConsumerRecord;
+import org.springframework.kafka.listener.MessageListener;
+
+import java.text.SimpleDateFormat;
+import java.util.Date;
+
+@Slf4j
+@AllArgsConstructor
+public class TsiKafkaConsumerWorker implements MessageListener<String, byte[]> {
+
+    private final String topic;
+    private final String nodeId;
+    private final String TEST_TOPIC = "topic-for-ssd-test";
+
+    @Override
+    public void onMessage(ConsumerRecord<String, byte[]> record) {
+        if (!this.nodeId.equals(record.key())) {
+            return;
+        }
+
+        log.info("onMessage: Topic: {}, Key: {}, {} Bytes. {}",
+                this.topic, record.key(), record.value().length, SysUtils.byteArrayToHex(record.value()));
+
+        byte[] buffer = record.value();
+        int idx = 0;
+        if ("cvim-raw".equals(this.topic)) {
+            idx = 27 + 6;
+        }
+        else if ("topic-for-ssd-test".equals(this.topic)) {
+            int stx1    = buffer[idx++];
+            int stx2    = buffer[idx++];
+            int length  = ((buffer[idx++] & 0xFF) << 8) | (buffer[idx++] & 0xFF);
+            int opCode  = buffer[idx++];
+            int version = buffer[idx++];
+            log.info("STX1: {}, STX2: {}, Length: {}, OpCode: {}, Version: {}, Idx: {}",
+                    stx1, stx2, length, opCode, version, idx);
+            //idx = 6;
+        }
+        displayPacket(record.key(), record.value(), idx);
+    }
+
+    public static void displayPacket(String topicKey, byte[] buffer, int start) {
+        int idx = start;
+//        int stx1    = buffer[idx++];
+//        int stx2    = buffer[idx++];
+//        int length  = ((buffer[idx++] & 0xFF) << 8) | (buffer[idx++] & 0xFF);
+//        int opCode  = buffer[idx++];
+//        int version = buffer[idx++];
+        long nodeId = ((long) (buffer[idx++] & 0xFF) << 24) | ((buffer[idx++] & 0xFF) << 16) | ((buffer[idx++] & 0xFF) << 8) | (buffer[idx++] & 0xFF);
+//        log.info("STX1: {}, STX2: {}, LENTH: {}, OpCode: {}, Version: {}, NodeId: {}", stx1, stx2, length, opCode, version, nodeId);
+
+        log.info("NodeId: {}, {}", topicKey, nodeId);
+
+        int status  = buffer[idx++];
+        int error   = buffer[idx++];
+        int counter = buffer[idx++];                //주기 카운터, 초
+        int stts    = buffer[idx++];
+        long localTime = ((long) (buffer[idx++] & 0xFF) << 24) | ((buffer[idx++] & 0xFF) << 16) | ((buffer[idx++] & 0xFF) << 8) | (buffer[idx++] & 0xFF);
+
+        int manual  = ((status     ) & 0x01);       //수동, 1: 이상, 0: 정상
+        int blink   = ((status >> 1) & 0x01);       //점멸, 1: 점멸, 0: 정상
+        int turnOff = ((status >> 2) & 0x01);       //소등, 1: 소등, 0: 정상
+        int sensing = ((status >> 3) & 0x01);       //감응, 1: 감응, 0: 정상
+        int trans   = ((status >> 4) & 0x01);       //전이, 1: 전이중, 0: 전이완료
+
+        int conflict   = ((error     ) & 0x01);     //모순 이상,      1 : 이상, 0 : 정상
+        int centerComm = ((error >> 1) & 0x01);     //센터 통신 이상, 1: 센터 통신이상, 0 : 정상
+        int scuComm    = ((error >> 2) & 0x01);     //SCU 통신 이상,  1: MCU <--> SCU 통신 이상, 0: 정상
+
+        int statusCount = ((stts)      & 0x7F);     //총 신호상태정보의 개수, N 개
+        int splitFlag   = ((stts >> 7) & 0x01);     //데이터를 분할하여 전송할 경우 마지막 정보임을 나타내는 플래그(분할 패킷의 처음과 중간:0, 단일 또는 마지막 패킷:1)
+
+        Date date = new java.util.Date(localTime * 1000L);
+        SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
+        sdf.setTimeZone(java.util.TimeZone.getTimeZone("GMT+9"));
+        String signalTime = sdf.format(date);
+
+        log.info("   LocalTime: ({})", signalTime);
+        log.info("  SystemTime: ({})", SysUtils.getSysTimeStr());
+        log.info("      STATUS: 전이({}), 감응({}), 소등({}), 점멸({}), 수동({}) - (1:전이중, 0:전이완료... 1:상태, 0:정상)",
+                trans, sensing, turnOff, blink, manual);
+        log.info("       ERROR: SCU통신({}), 센터통신({}), 모순({}) - (1: 이상, 0: 정상)",
+                scuComm, centerComm, conflict);
+        log.info("CycleCounter: {} sec.", counter);
+        log.info("     Signals: {} EA, DataSplit({}) - (0:First/Middle, 1:Single/Last)", statusCount, splitFlag);
+
+//typedef struct _tsc_cvim_hdr_s
+//{
+//    uint8_t manual      : 1;    /* 수동, 1: 이상, 0: 정상 */
+//    uint8_t blink       : 1;    /* 점멸, 1: 점멸, 0: 정상 */
+//    uint8_t turnOff     : 1;    /* 소등, 1: 소등, 0: 정상 */
+//    uint8_t response    : 1;    /* 감응, 1: 감응, 0: 정상 */
+//    uint8_t trans       : 1;    /* 전이, 1: 전이중, 0: 전이완료 */
+//    uint8_t byte1Res0   : 3;    /* 예약, bit 7 ~ 5 */
+//
+//    uint8_t conflict    : 1;    /* 모순 이상, 1 : 이상, 0 : 정상 */
+//    uint8_t centerComm  : 1;    /* 센터 통신 이상, 1: 센터 통신이상, 0 : 정상 */
+//    uint8_t scuComm     : 1;    /* SCU 통신 이상,  1: MCU <--> SCU 통신 이상, 0: 정상 */
+//    uint8_t byte2Res0   : 5;    /* 예약, bit 7 ~ 3 */
+//
+//    uint8_t cycleCounter;       /* 주기 카운터, 초 */
+//
+//    uint8_t sttsCount   : 7;    /* 총 신호상태정보의 개수, N 개 */
+//    uint8_t splitFlag   : 1;    /* 데이터를 분할하여 전송할 경우 마지막 정보임을 나타내는 플래그(분할 패킷의 처음과 중간:0, 단일 또는 마지막 패킷:1) */
+//
+//    uint8_t currTime[4];        /* 현재시간, time_t형, Big Endian */
+//} tsc_cvim_hdr_t, *ptsc_cvim_hdr_t;
+
+        final int SIGNAL_STATUS_SIZE = 5;
+        int remainLength = buffer.length - idx;
+        if (statusCount * SIGNAL_STATUS_SIZE != remainLength) {
+            log.error("Signal Status Data length error: {} EA, {}, {}", statusCount, statusCount * SIGNAL_STATUS_SIZE, remainLength);
+            return;
+        }
+
+        log.info("SEQ\t신호등정보\t방향\t시간정보신뢰성\t보행자   \t비보호신호\t신호등상태\t표출\t잔여\t방향코드");
+        for (int ii = 0; ii < statusCount; ii++) {
+            int dirInfo = buffer[idx++] & 0xFF;
+            int sttsInfo = buffer[idx++] & 0xFF;
+            int displayTm = buffer[idx++] & 0xFF;
+            int remainTm = buffer[idx++] & 0xFF;
+            int dirCode = buffer[idx++] & 0xFF;
+
+            int dirAdd     = ((dirInfo) & 0x0F);        //3 ~ 0, 방향추가정보, 해당 방향에 연등지 없음(0), 해당 방향의 첫번째 연등지(1), 해당 방향의 두번째 연등지(2)
+            int lightsType = ((dirInfo >> 4) & 0x0F);   //7 ~ 4, 신호등 정보, ■ 미지정(0), 직진(1), 좌회전(2), 보행자(3), 자전거(4), 우회전(5), 버스(6), 유턴(7)
+
+            int lighting   = ((sttsInfo     ) & 0x07);  //2 ~ 0, 신호등 상태, ■ 소등(0), 적색점등(1), 황색점등(2), 녹색점등(3), 적색점멸(4), 황색점멸(5), 녹색점멸(6)
+            int unprotect  = ((sttsInfo >> 3) & 0x01);  //3, 비보호 상태, ■ 신호등 정보 유턴/좌회전에 대한 비보호 여부, ■ 비보호 아님(0), 비보호(1)
+            int walkerPush = ((sttsInfo >> 6) & 0x01);  //6, 보행자(푸쉬 또는 자동검지), ■ 없음(0), 버튼 눌림 or 자동검지(1)
+            int timeFlag   = ((sttsInfo >> 7) & 0x01);  //7, 시간 정보 신뢰성, ■ 고정신호시간(0), 가변신호시간(1)
+
+            String plightInfo;
+            switch (lightsType)
+            {
+                case 0: plightInfo = "미지정(0)"; break;
+                case 1: plightInfo = "직진(1)  "; break;
+                case 2: plightInfo = "좌회전(2)"; break;
+                case 3: plightInfo = "보행자(3)"; break;
+                case 4: plightInfo = "자전거(4)"; break;
+                case 5: plightInfo = "우회전(5)"; break;
+                case 6: plightInfo = "버스(6)  "; break;
+                case 7: plightInfo = "유턴(7)  "; break;
+                default: plightInfo = "XXX(" + lightsType + ")"; break;
+            }
+            String ptimeFlag;
+            switch (timeFlag)
+            {
+                case 0: ptimeFlag = "고정신호(0)"; break;
+                case 1: ptimeFlag = "가변신호(1)"; break;
+                default: ptimeFlag = "XXX(" + timeFlag + ")"; break;
+            }
+            String pwalkerPush;
+            switch (walkerPush)
+            {
+                case 0: pwalkerPush = "없음(0)    "; break;
+                case 1: pwalkerPush = "자동검지(1)"; break;
+                default: pwalkerPush = "XXX(" + walkerPush + ")"; break;
+            }
+            String punprotect;
+            switch (unprotect)
+            {
+                case 0: punprotect = "아님(0)  "; break;
+                case 1: punprotect = "비보호(1)"; break;
+                default: punprotect = "XXX(" + unprotect + ")"; break;
+            }
+            String plighting;
+            switch (lighting)
+            {
+                case 0: plighting = "소등(0)    "; break;
+                case 1: plighting = "적색점등(1)"; break;
+                case 2: plighting = "황색점등(2)"; break;
+                case 3: plighting = "녹색점등(3)"; break;
+                case 4: plighting = "적색점멸(4)"; break;
+                case 5: plighting = "황색점멸(5)"; break;
+                case 6: plighting = "녹색점멸(6)"; break;
+                default: plighting = "XXX(" + lighting + ")"; break;
+            }
+            log.info("{}\t{}\t{}\t{}\t{}\t{}\t{}\t{}\t{}\t{}",
+                    String.format("%3d", ii),
+                    plightInfo,
+                    dirAdd,
+                    ptimeFlag,
+                    pwalkerPush,
+                    punprotect,
+                    plighting,
+                    displayTm,
+                    remainTm,
+                    dirCode);
+        }
+//        typedef struct _tsc_cvim_stts_s
+//        {
+//            uint8_t dirAdd      : 4;    /* 3 ~ 0, 방향추가정보, 해당 방향에 연등지 없음(0), 해당 방향의 첫번째 연등지(1), 해당 방향의 두번째 연등지(2) */
+//            uint8_t lightInfo   : 4;    /* 7 ~ 4, 신호등 정보, ■ 미지정(0), 직진(1), 좌회전(2), 보행자(3), 자전거(4), 우회전(5), 버스(6), 유턴(7) */
+//
+//            uint8_t lighting    : 3;    /* 2 ~ 0, 신호등 상태, ■ 소등(0), 적색점등(1), 황색점등(2), 녹색점등(3), 적색점멸(4), 황색점멸(5), 녹색점멸(6) */
+//            uint8_t unprotect   : 1;    /* 3, 비보호 상태, ■ 신호등 정보 유턴/좌회전에 대한 비보호 여부, ■ 비보호 아님(0), 비보호(1) */
+//            uint8_t Reserved0   : 2;    /* 5 ~ 4, 예비, ■ 예비 */
+//            uint8_t walkerPush  : 1;    /* 6, 보행자(푸쉬 또는 자동검지), ■ 없음(0), 버튼 눌림 or 자동검지(1) */
+//            uint8_t timeFlag    : 1;    /* 7, 시간 정보 신뢰성, ■ 고정신호시간(0), 가변신호시간(1) */
+//
+//            uint8_t displayTm;          /* 표출 시간, ■ 초 */
+//            uint8_t remainTm;           /* 잔여 시간, ■ 초 */
+//            uint8_t dirCode;            /* 방향 코드, ■ 출력지정 테이블에 지정된 방향코드 */
+//        } tsc_cvim_stts_t, *ptsc_cvim_stts_t;
+
+    }
+
+//    public static void displayPacket(String topicKey, byte[] buffer, int start) {
+//        int idx = start;
+////        int stx1    = buffer[idx++];
+////        int stx2    = buffer[idx++];
+////        int length  = ((buffer[idx++] & 0xFF) << 8) | (buffer[idx++] & 0xFF);
+////        int opCode  = buffer[idx++];
+////        int version = buffer[idx++];
+//        long nodeId = ((long) (buffer[idx++] & 0xFF) << 24) | ((buffer[idx++] & 0xFF) << 16) | ((buffer[idx++] & 0xFF) << 8) | (buffer[idx++] & 0xFF);
+////        log.info("STX1: {}, STX2: {}, LENTH: {}, OpCode: {}, Version: {}, NodeId: {}", stx1, stx2, length, opCode, version, nodeId);
+//
+//        log.info("NodeId: {}, {}", topicKey, nodeId);
+//
+//        int status  = buffer[idx++];
+//        int error   = buffer[idx++];
+//        int counter = buffer[idx++];                //주기 카운터, 초
+//        int stts    = buffer[idx++];
+//        long localTime = ((long) (buffer[idx++] & 0xFF) << 24) | ((buffer[idx++] & 0xFF) << 16) | ((buffer[idx++] & 0xFF) << 8) | (buffer[idx++] & 0xFF);
+//
+//        int manual  = ((status     ) & 0x01);       //수동, 1: 이상, 0: 정상
+//        int blink   = ((status >> 1) & 0x01);       //점멸, 1: 점멸, 0: 정상
+//        int turnOff = ((status >> 2) & 0x01);       //소등, 1: 소등, 0: 정상
+//        int sensing = ((status >> 3) & 0x01);       //감응, 1: 감응, 0: 정상
+//        int trans   = ((status >> 4) & 0x01);       //전이, 1: 전이중, 0: 전이완료
+//
+//        int conflict   = ((error     ) & 0x01);     //모순 이상,      1 : 이상, 0 : 정상
+//        int centerComm = ((error >> 1) & 0x01);     //센터 통신 이상, 1: 센터 통신이상, 0 : 정상
+//        int scuComm    = ((error >> 2) & 0x01);     //SCU 통신 이상,  1: MCU <--> SCU 통신 이상, 0: 정상
+//
+//        int statusCount = ((stts)      & 0x7F);     //총 신호상태정보의 개수, N 개
+//        int splitFlag   = ((stts >> 7) & 0x01);     //데이터를 분할하여 전송할 경우 마지막 정보임을 나타내는 플래그(분할 패킷의 처음과 중간:0, 단일 또는 마지막 패킷:1)
+//
+//        Date date = new java.util.Date(localTime * 1000L);
+//        SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
+//        sdf.setTimeZone(java.util.TimeZone.getTimeZone("GMT+9"));
+//        String signalTime = sdf.format(date);
+//
+//        log.info("   LocalTime: ({})", signalTime);
+//        log.info("  SystemTime: ({})", SysUtils.getSysTimeStr());
+//        log.info("      STATUS: 전이({}), 감응({}), 소등({}), 점멸({}), 수동({}) - (1:전이중, 0:전이완료... 1:상태, 0:정상)",
+//                trans, sensing, turnOff, blink, manual);
+//        log.info("       ERROR: SCU통신({}), 센터통신({}), 모순({}) - (1: 이상, 0: 정상)",
+//                scuComm, centerComm, conflict);
+//        log.info("CycleCounter: {} sec.", counter);
+//        log.info("     Signals: {} EA, DataSplit({}) - (0:First/Middle, 1:Single/Last)", statusCount, splitFlag);
+//
+////typedef struct _tsc_cvim_hdr_s
+////{
+////    uint8_t manual      : 1;    /* 수동, 1: 이상, 0: 정상 */
+////    uint8_t blink       : 1;    /* 점멸, 1: 점멸, 0: 정상 */
+////    uint8_t turnOff     : 1;    /* 소등, 1: 소등, 0: 정상 */
+////    uint8_t response    : 1;    /* 감응, 1: 감응, 0: 정상 */
+////    uint8_t trans       : 1;    /* 전이, 1: 전이중, 0: 전이완료 */
+////    uint8_t byte1Res0   : 3;    /* 예약, bit 7 ~ 5 */
+////
+////    uint8_t conflict    : 1;    /* 모순 이상, 1 : 이상, 0 : 정상 */
+////    uint8_t centerComm  : 1;    /* 센터 통신 이상, 1: 센터 통신이상, 0 : 정상 */
+////    uint8_t scuComm     : 1;    /* SCU 통신 이상,  1: MCU <--> SCU 통신 이상, 0: 정상 */
+////    uint8_t byte2Res0   : 5;    /* 예약, bit 7 ~ 3 */
+////
+////    uint8_t cycleCounter;       /* 주기 카운터, 초 */
+////
+////    uint8_t sttsCount   : 7;    /* 총 신호상태정보의 개수, N 개 */
+////    uint8_t splitFlag   : 1;    /* 데이터를 분할하여 전송할 경우 마지막 정보임을 나타내는 플래그(분할 패킷의 처음과 중간:0, 단일 또는 마지막 패킷:1) */
+////
+////    uint8_t currTime[4];        /* 현재시간, time_t형, Big Endian */
+////} tsc_cvim_hdr_t, *ptsc_cvim_hdr_t;
+//
+//        final int SIGNAL_STATUS_SIZE = 5;
+//        int remainLength = buffer.length - idx;
+//        if (statusCount * SIGNAL_STATUS_SIZE != remainLength) {
+//            log.error("Signal Status Data length error: {} EA, {}, {}", statusCount, statusCount * SIGNAL_STATUS_SIZE, remainLength);
+//            return;
+//        }
+//
+//        log.info("SEQ\t신호등정보\t방향\t시간정보신뢰성\t보행자   \t비보호신호\t신호등상태\t표출\t잔여\t방향코드");
+//        for (int ii = 0; ii < statusCount; ii++) {
+//            int dirInfo = buffer[idx++] & 0xFF;
+//            int sttsInfo = buffer[idx++] & 0xFF;
+//            int displayTm = buffer[idx++] & 0xFF;
+//            int remainTm = buffer[idx++] & 0xFF;
+//            int dirCode = buffer[idx++] & 0xFF;
+//
+//            int dirAdd     = ((dirInfo) & 0x0F);        //3 ~ 0, 방향추가정보, 해당 방향에 연등지 없음(0), 해당 방향의 첫번째 연등지(1), 해당 방향의 두번째 연등지(2)
+//            int lightsType = ((dirInfo >> 4) & 0x0F);   //7 ~ 4, 신호등 정보, ■ 미지정(0), 직진(1), 좌회전(2), 보행자(3), 자전거(4), 우회전(5), 버스(6), 유턴(7)
+//
+//            int lighting   = ((sttsInfo     ) & 0x07);  //2 ~ 0, 신호등 상태, ■ 소등(0), 적색점등(1), 황색점등(2), 녹색점등(3), 적색점멸(4), 황색점멸(5), 녹색점멸(6)
+//            int unprotect  = ((sttsInfo >> 3) & 0x01);  //3, 비보호 상태, ■ 신호등 정보 유턴/좌회전에 대한 비보호 여부, ■ 비보호 아님(0), 비보호(1)
+//            int walkerPush = ((sttsInfo >> 6) & 0x01);  //6, 보행자(푸쉬 또는 자동검지), ■ 없음(0), 버튼 눌림 or 자동검지(1)
+//            int timeFlag   = ((sttsInfo >> 7) & 0x01);  //7, 시간 정보 신뢰성, ■ 고정신호시간(0), 가변신호시간(1)
+//
+//            String plightInfo;
+//            switch (lightsType)
+//            {
+//                case 0: plightInfo = "미지정(0)"; break;
+//                case 1: plightInfo = "직진(1)  "; break;
+//                case 2: plightInfo = "좌회전(2)"; break;
+//                case 3: plightInfo = "보행자(3)"; break;
+//                case 4: plightInfo = "자전거(4)"; break;
+//                case 5: plightInfo = "우회전(5)"; break;
+//                case 6: plightInfo = "버스(6)  "; break;
+//                case 7: plightInfo = "유턴(7)  "; break;
+//                default: plightInfo = "XXX(" + lightsType + ")"; break;
+//            }
+//            String ptimeFlag;
+//            switch (timeFlag)
+//            {
+//                case 0: ptimeFlag = "고정신호(0)"; break;
+//                case 1: ptimeFlag = "가변신호(1)"; break;
+//                default: ptimeFlag = "XXX(" + timeFlag + ")"; break;
+//            }
+//            String pwalkerPush;
+//            switch (walkerPush)
+//            {
+//                case 0: pwalkerPush = "없음(0)    "; break;
+//                case 1: pwalkerPush = "자동검지(1)"; break;
+//                default: pwalkerPush = "XXX(" + walkerPush + ")"; break;
+//            }
+//            String punprotect;
+//            switch (unprotect)
+//            {
+//                case 0: punprotect = "아님(0)  "; break;
+//                case 1: punprotect = "비보호(1)"; break;
+//                default: punprotect = "XXX(" + unprotect + ")"; break;
+//            }
+//            String plighting;
+//            switch (lighting)
+//            {
+//                case 0: plighting = "소등(0)    "; break;
+//                case 1: plighting = "적색점등(1)"; break;
+//                case 2: plighting = "황색점등(2)"; break;
+//                case 3: plighting = "녹색점등(3)"; break;
+//                case 4: plighting = "적색점멸(4)"; break;
+//                case 5: plighting = "황색점멸(5)"; break;
+//                case 6: plighting = "녹색점멸(6)"; break;
+//                default: plighting = "XXX(" + lighting + ")"; break;
+//            }
+//            log.info("{}\t{}\t{}\t{}\t{}\t{}\t{}\t{}\t{}\t{}",
+//                    String.format("%3d", ii),
+//                    plightInfo,
+//                    dirAdd,
+//                    ptimeFlag,
+//                    pwalkerPush,
+//                    punprotect,
+//                    plighting,
+//                    displayTm,
+//                    remainTm,
+//                    dirCode);
+//        }
+////        typedef struct _tsc_cvim_stts_s
+////        {
+////            uint8_t dirAdd      : 4;    /* 3 ~ 0, 방향추가정보, 해당 방향에 연등지 없음(0), 해당 방향의 첫번째 연등지(1), 해당 방향의 두번째 연등지(2) */
+////            uint8_t lightInfo   : 4;    /* 7 ~ 4, 신호등 정보, ■ 미지정(0), 직진(1), 좌회전(2), 보행자(3), 자전거(4), 우회전(5), 버스(6), 유턴(7) */
+////
+////            uint8_t lighting    : 3;    /* 2 ~ 0, 신호등 상태, ■ 소등(0), 적색점등(1), 황색점등(2), 녹색점등(3), 적색점멸(4), 황색점멸(5), 녹색점멸(6) */
+////            uint8_t unprotect   : 1;    /* 3, 비보호 상태, ■ 신호등 정보 유턴/좌회전에 대한 비보호 여부, ■ 비보호 아님(0), 비보호(1) */
+////            uint8_t Reserved0   : 2;    /* 5 ~ 4, 예비, ■ 예비 */
+////            uint8_t walkerPush  : 1;    /* 6, 보행자(푸쉬 또는 자동검지), ■ 없음(0), 버튼 눌림 or 자동검지(1) */
+////            uint8_t timeFlag    : 1;    /* 7, 시간 정보 신뢰성, ■ 고정신호시간(0), 가변신호시간(1) */
+////
+////            uint8_t displayTm;          /* 표출 시간, ■ 초 */
+////            uint8_t remainTm;           /* 잔여 시간, ■ 초 */
+////            uint8_t dirCode;            /* 방향 코드, ■ 출력지정 테이블에 지정된 방향코드 */
+////        } tsc_cvim_stts_t, *ptsc_cvim_stts_t;
+//
+//    }
+}

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

@@ -0,0 +1,9 @@
+spring:
+  application:
+    name: tsi-consumer
+  main:
+    web-application-type: none
+    banner-mode: off
+  output:
+    ansi:
+      enabled: always

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

@@ -0,0 +1,23 @@
+<?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-consumer"/>
+    <property name="ROOT_LOG_LEVEL"  value="DEBUG"/>
+    <property name="LOG_CHARSET"     value="UTF-8" />
+
+    <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>
+
+    <root level="INFO" additivity="true">
+        <appender-ref ref="CONSOLE"/>
+    </root>
+
+</configuration>

+ 148 - 0
src/test/java/com/tsi/comm/consumer/TsiCommConsumerApplicationTests.java

@@ -0,0 +1,148 @@
+package com.tsi.comm.consumer;
+
+import com.tsi.app.common.utils.ByteUtils;
+import com.tsi.app.common.utils.CRC16Utils;
+import com.tsi.app.common.utils.HexString;
+import com.tsi.comm.consumer.protocol.TsiCpuPacket;
+import lombok.extern.slf4j.Slf4j;
+import org.junit.Test;
+import org.springframework.boot.test.context.SpringBootTest;
+
+import java.net.InetAddress;
+import java.net.UnknownHostException;
+import java.util.concurrent.Executors;
+import java.util.concurrent.ThreadFactory;
+import java.util.concurrent.ThreadPoolExecutor;
+import java.util.concurrent.TimeUnit;
+
+@Slf4j
+@SpringBootTest
+public class TsiCommConsumerApplicationTests {
+
+    //@Test
+    void contextLoads() {
+    }
+
+    @Test
+    public void test1() {
+        String hostName;
+        String hostAddress;
+        try {
+            InetAddress localhost = InetAddress.getLocalHost();
+            hostName = localhost.getHostName();
+            hostAddress = localhost.getHostAddress();
+        } catch (UnknownHostException e) {
+            hostName = "localhost";
+            hostAddress = "127.0.0.1";
+        }
+        System.out.println("Your current IP address : " + hostAddress);
+        System.out.println("Your current Hostname : " + hostName);
+
+        InetAddress ip;
+        String hostname;
+        try {
+            ip = InetAddress.getLocalHost();
+            hostname = ip.getHostName();
+            System.out.println("Your current IP address : " + ip);
+            System.out.println("Your current Hostname : " + hostname);
+
+        } catch (UnknownHostException e) {
+
+            e.printStackTrace();
+        }
+    }
+    class WorkerThreadTask implements Runnable {
+
+        private ThreadPoolExecutor processExecutor;
+
+        public WorkerThreadTask(ThreadPoolExecutor processExecutor, int idx) {
+            Thread.currentThread().setName(String.format("worker-pool-%02d", idx));
+            this.processExecutor = processExecutor;
+        }
+
+        @Override
+        public void run() {
+            while (true) {
+                log.error("{}, corePoolSize: {}, activeCount: {}, maximumPoolSize: {}, poolSize: {}, taskCount: {}",
+                        Thread.currentThread().getName(),
+                        processExecutor.getCorePoolSize(),
+                        processExecutor.getActiveCount(),
+                        processExecutor.getMaximumPoolSize(),
+                        processExecutor.getPoolSize(),
+                        processExecutor.getTaskCount());
+                try {
+                    Thread.sleep(1000);
+                    if (processExecutor.awaitTermination(1L, TimeUnit.MILLISECONDS))
+                        log.info("Terminated");
+
+                } catch (InterruptedException e) {
+                    e.printStackTrace();
+                }
+            }
+        }
+    }
+    class NamedThreadsFactory implements ThreadFactory {
+
+        private int count = 0;
+        private String Name = "MyThread-";
+
+        @Override
+        public Thread newThread(Runnable r) {
+            return new Thread(r, Name + ++count); // Mythread-x 형태로 쓰레드 이름 설정
+        }
+    }
+
+    @Test
+    public void testThread() throws InterruptedException {
+        int threadPoolSize = Runtime.getRuntime().availableProcessors() * 10;
+        ThreadPoolExecutor processExecutor = (ThreadPoolExecutor) Executors.newFixedThreadPool(1);
+        log.info("corePoolSize: {}, activeCount: {}, maximumPoolSize: {}, poolSize: {}, taskCount: {}",
+                processExecutor.getCorePoolSize(),
+                processExecutor.getActiveCount(),
+                processExecutor.getMaximumPoolSize(),
+                processExecutor.getPoolSize(),
+                processExecutor.getTaskCount());
+
+        for (int ii = 0; ii < threadPoolSize; ii++) {
+            log.info("Thread Start: {}", ii);
+            processExecutor.execute(new WorkerThreadTask(processExecutor, ii));
+            /*processExecutor.execute(() -> {
+                while (true) {
+                    try {
+                        log.error("{}, corePoolSize: {}, activeCount: {}, maximumPoolSize: {}, poolSize: {}, taskCount: {}",
+                                Thread.currentThread().getName(),
+                                processExecutor.getCorePoolSize(),
+                                processExecutor.getActiveCount(),
+                                processExecutor.getMaximumPoolSize(),
+                                processExecutor.getPoolSize(),
+                                processExecutor.getTaskCount());
+                        Thread.sleep(1000);
+                    }
+                    catch (Exception e) {
+                        log.error("{}", e.getMessage(), e);
+                    }
+                }
+            });*/
+        }
+        Thread.sleep(20000);
+    }
+
+    @Test
+    public void checkSumTest() {
+        long nodeId = 110000001;
+        String strHex = "7E7E004E1301068E77810002310C60F1375E10CB280B0A20CB321F0A30CB320D0A10CA03011420CA32011430CA322B1410C9280B1E20C9321F1E30C9320D1E10C903012820C928012830C9282B28FD89";
+        byte[] packet = ByteUtils.hexToByteArray(strHex);
+        log.error("{}", HexString.fromBytes(packet));
+        int dataLength = ByteUtils.getUnsignedShort(packet, TsiCpuPacket.INDEX_LENGTH);
+        log.error("dataLength: {}, packetLength: {}", dataLength, packet.length);
+        int recvCheckSum = ByteUtils.getUnsignedShort(packet, packet.length-2);
+        int calcCheckSum = CRC16Utils.CRC16_ccitt_cvim(packet, 2, dataLength-2);
+        if (recvCheckSum != calcCheckSum) {
+            log.info("Node: {}, Check Sum Error: {},{}, recv: {}, calc: {}", nodeId, 0xFD89, 0x89FD, recvCheckSum, calcCheckSum);
+        }
+        else {
+            log.info("Node: {}, Check Sum OK: recv: {}, calc: {}", nodeId, recvCheckSum, calcCheckSum);
+        }
+    }
+
+}

+ 59 - 0
start.sh

@@ -0,0 +1,59 @@
+#!/bin/sh
+
+ACTIVE_PROFILE=seoul
+#ACTIVE_PROFILE=seoul,mongodb
+SERVICE_HOME=$(dirname $0)
+
+usage() {
+	echo "Usage:" $0 "[comm/data]"
+	echo "RUN tsi-comm-server:" $0 "comm"
+	echo "RUN tsi-data-broker:" $0 "data"
+	exit
+}
+
+case $1 in
+  comm)
+    SERVICE_NAME=tsi-comm-server
+    SERVICE_VERSION=0.0.1
+    ;;
+  data)
+    SERVICE_NAME=tsi-data-broker
+    SERVICE_VERSION=0.0.1
+    ;;
+  *)
+    usage
+    ;;
+esac
+
+
+EXE_NAME=$SERVICE_NAME-$SERVICE_VERSION.jar
+PID_NAME=$SERVICE_NAME.pid
+SERVICE_PID=$SERVICE_HOME/conf/$PID_NAME
+
+export JAVA_OPT="-server"
+#export JAVA_OPT="$JAVA_OPT -Xms4096m -Xmx4096m"
+export JAVA_OPT="$JAVA_OPT -Xlog:gc*:file=logs/${SERVICE_NAME}/${SERVICE_NAME}.gc.log"
+export CONFIG_OPT="-Dspring.profiles.active=${ACTIVE_PROFILE}"
+#export CONFIG_OPT="--spring.config.location=conf//$SERVICE_NAME.yml"
+
+if [ ! -z "$SERVICE_PID" ]; then
+  if [ -f "$SERVICE_PID" ]; then
+    echo "$SERVICE_NAME is already running...."
+    exit
+  fi
+fi
+
+#nohup java $JAVA_OPT -jar ./$EXE_NAME $CONFIG_OPT 1> /dev/null 2>&1 &
+#java $JAVA_OPT -jar ./$EXE_NAME $CONFIG_OPT &
+java $JAVA_OPT -javaagent:./jmx_prometheus_javaagent-0.20.0.jar=12345:config.yaml -jar $CONFIG_OPT ./$EXE_NAME &
+
+echo "$SERVICE_NAME is started...."
+
+sleep 1
+
+ps -eaf | grep $SERVICE_NAME | grep -v grep |wc -l
+
+sleep 1
+
+ps -eaf | grep $SERVICE_NAME | grep -v grep
+

+ 9 - 0
stat.sh

@@ -0,0 +1,9 @@
+#!/bin/sh
+
+export SERVICE_NAME=tsi-
+
+ps -eaf | grep $SERVICE_NAME | grep -v grep | grep -v tail | grep -v kafka | grep java | wc -l
+
+sleep 1
+
+ps -eaf | grep $SERVICE_NAME | grep -v grep | grep -v tail | grep -v kafka | grep java

+ 54 - 0
stop.sh

@@ -0,0 +1,54 @@
+#!/bin/sh
+
+SERVICE_HOME=$(dirname $0)
+
+usage() {
+        echo "Usage:" $0 "[comm/data]"
+        echo "STOP tsi-comm-server:" $0 "comm"
+        echo "STOP tsi-data-broker:" $0 "data"
+        exit
+}
+
+case $1 in
+  comm)
+    SERVICE_NAME=tsi-comm-server
+    SERVICE_VERSION=0.0.1
+    ;;
+  data)
+    SERVICE_NAME=tsi-data-broker
+    SERVICE_VERSION=0.0.1
+    ;;
+  *)
+    usage
+    ;;
+esac
+
+
+EXE_NAME=$SERVICE_NAME-$SERVICE_VERSION.jar
+PID_NAME=$SERVICE_NAME.pid
+SERVICE_PID=$SERVICE_HOME/conf/$PID_NAME
+
+if [ ! -z "$SERVICE_PID" ]; then
+  if [ -f "$SERVICE_PID" ]; then
+    kill -15 `cat "$SERVICE_PID"` >/dev/null 2>&1
+    echo "$SERVICE_NAME stopping.........."
+  else
+    echo "$SERVICE_NAME is not running...."
+    exit
+  fi
+fi
+
+LOOP=$(seq 0 9)
+for i in $LOOP
+do
+  sleep 1
+  if [ -f "$SERVICE_PID" ]; then
+    echo "$SERVICE_NAME stopping.........."
+  else
+    echo "$SERVICE_NAME stopped.........."
+    exit
+  fi
+done
+
+echo "$SERVICE_NAME cannot be terminated......."
+ps -eaf | grep $SERVICE_NAME | grep -v grep

+ 104 - 0
tsi-agent.sh

@@ -0,0 +1,104 @@
+#!/bin/bash
+
+SSIP_API_URI="http://10.4.4.40:8444/api/system-status"
+SSIP_API_TIMEOUT=3
+HEADER_CONTEXT_TYPE="Content-Type: application/json"
+
+# Check hostname
+name=$HOSTNAME
+echo -e "Hostname:" $name
+
+# Check OS Type
+otype=$(uname -o)
+echo -e "Operating System Type:" $otype
+
+# Check OS Release Version and Name
+oname=`cat /etc/os-release | grep 'NAME' | grep -v 'PRETTY_NAME' | grep -v 'CODENAME' | cut -f2 -d\"`
+over=`cat /etc/os-release | grep 'VERSION' | grep -v '_' | cut -f2 -d\"`
+echo "OS Name:" $oname
+echo "OS Version:" $over
+
+# Check Architecture
+oarch=$(uname -m)
+echo "Architecture:" $oarch
+
+# Check Kernel Release
+kernel=$(uname -r)
+echo "Kernel Release:" $kernel
+
+# Check Internal IP
+iip=$(hostname -I)
+echo "Internal IP:" $iip
+
+# Check Internal IP
+#eip=$(dig +short myip.opendns.com @resolver1.opendns.com)
+eip=1.1.1.1
+echo "External IP:" $eip
+
+run_monitoring() {
+    totalmem=`free -m | grep ^Mem | awk '{print $2}'`
+    usedmem=`free -m | grep ^Mem | awk '{print $3}'`
+    freemem=`free -m | grep ^Mem | awk '{print $4}'`
+    cachemem=`free -m | grep ^Mem | awk '{print $6}'`
+    availablemem=`free -m | grep ^Mem | awk '{print $7}'`
+
+    swapmem=`free -m | grep ^Swap | awk '{print $2}'`
+    usedswap=`free -m | grep ^Swap | awk '{print $3}'`
+
+    cpucnt=`cat /proc/cpuinfo | grep 'processor' | wc -l`
+    uptimes=`uptime -s`
+
+    echo "cpuCnt:" ${cpucnt}
+
+    #usecpurate=`top -b -n 1 | grep Cpu | awk '{print $8}' | tr -d "%id," | awk '{print 100-$1}'`
+    usecpurate=`mpstat 1 1 | tail -1 | awk '{print 100-$NF}'`
+    echo "useCpuRate:" ${usecpurate}
+    tasks=`ps aux | grep -v ps | wc -l`
+    threads=200
+
+    #loadavg=`uptime | awk '{print $10}' | cut -f 1 -d ','`
+    loadavg=`cat /proc/loadavg | awk '{print $1}'`
+    echo "loadAvg:" ${loadavg}
+    
+    #DISK 사용율
+    totaldisk=`df -P | grep -v ^Filesystem | awk '{sum += $2} END { print sum; }'`
+    useddisk=`df -P | grep -v ^Filesystem | awk '{sum += $3} END { print sum; }'`
+    useddiskrate=$((100*$useddisk/$totaldisk))
+    echo DISK: $(($totaldisk/1024/1024)) GB, Used DISK: $(($useddisk/1024/1024)) GB, Rate: $useddiskrate %
+
+    # Call System Status Save REST API
+    PAYLOAD='{"hostName"      : "'${name}'", 
+              "osType"        : "'${otype}'", 
+              "osName"        : "'${oname}'", 
+              "osVersion"     : "'${over}'", 
+              "osArch"        : "'${oarch}'", 
+              "kernelRelease" : "'${kernel}'", 
+              "internalIp"    : "'${iip}'", 
+              "externalIp"    : "'${eip}'",
+              "totalMem"      : "'${totalmem}'",
+              "swapMem"       : "'${swapmem}'",
+              "totalDisk"     : "'${totaldisk}'",
+              "cpuCnt"        : "'${cpucnt}'",
+              "upTimes"       : "'${uptimes}'",
+              "usedDisk"      : "'${useddisk}'",
+              "usedMem"       : "'${usedmem}'",
+              "freeMem"       : "'${freemem}'",
+              "cacheMem"      : "'${cachemem}'",
+              "availableMem"  : "'${availablemem}'",
+              "usedSwap"      : "'${usedswap}'",
+              "tasks"         : "'${tasks}'",
+              "threads"       : "'${threads}'",
+              "useCpuRate"    : "'${usecpurate}'",
+              "loadAvg"       : "'${loadavg}'"
+	    }'
+
+    api_result=$(curl -d "${PAYLOAD}" -X POST $SSIP_API_URI -H "$HEADER_CONTEXT_TYPE" --connect-timeout $SSIP_API_TIMEOUT)
+
+    # Result
+    echo ""
+    echo ${api_result}
+    echo ""
+}
+
+run_monitoring
+