This commit is contained in:
zzp 2024-09-04 14:38:10 +08:00
commit a1adfd9cbe
126 changed files with 11965 additions and 0 deletions

170
.gitignore vendored Normal file
View File

@ -0,0 +1,170 @@
#################
## Eclipse
#################
_site
*.iml
.idea/
target/
*.log
*.gz
out/
*.pydevproject
.project
.metadata
bin/
tmp/
*.tmp
*.bak
*.swp
*~.nib
.classpath
.settings/
.loadpath
# External tool builders
.externalToolBuilders/
# Locally stored "Eclipse launch configurations"
*.launch
# CDT-specific
.cproject
# PDT-specific
.buildpath
#################
## Visual Studio
#################
## Ignore Visual Studio temporary files, build results, and
## files generated by popular Visual Studio add-ons.
# User-specific files
*.suo
*.user
*.sln.docstates
# Build results
[Dd]ebug/
[Rr]elease/
*_i.c
*_p.c
*.ilk
*.meta
*.obj
*.pch
*.pdb
*.pgc
*.pgd
*.rsp
*.sbr
*.tlb
*.tli
*.tlh
*.vspscc
.builds
*.dotCover
#packages/
# Visual C++ cache files
ipch/
*.aps
*.ncb
*.opensdf
*.sdf
# Visual Studio profiler
*.psess
*.vsp
# ReSharper is a .NET coding add-in
_ReSharper*
# Installshield output folder
[Ee]xpress
# DocProject is a documentation generator add-in
DocProject/buildhelp/
DocProject/Help/*.HxT
DocProject/Help/*.HxC
DocProject/Help/*.hhc
DocProject/Help/*.hhk
DocProject/Help/*.hhp
DocProject/Help/Html2
DocProject/Help/html
# Click-Once directory
publish
# Others
[Bb]in
[Oo]bj
# sql
TestResults
*.Cache
ClientBin
stylecop.*
~$*
*.dbmdl
Generated_Code #added for RIA/Silverlight projects
# Backup & report files from converting an old project file to a newer
# Visual Studio version. Backup files are not needed, because we have git ;-)
_UpgradeReport_Files/
Backup*/
UpgradeLog*.XML
############
## Windows
############
# Windows image file caches
Thumbs.db
# Folder config file
Desktop.ini
#############
## Python
#############
*.py[co]
# Packages
*.egg
*.egg-info
dist
build
eggs
parts
bin
var
sdist
develop-eggs
.installed.cfg
# Installer logs
pip-log.txt
# Unit test / coverage reports
.coverage
.tox
#Translations
*.mo
#Mr Developer
.mr.developer.cfg
# Mac crap
.DS_Store
.gradle

BIN
gradle/wrapper/gradle-wrapper.jar vendored Normal file

Binary file not shown.

View File

@ -0,0 +1,7 @@
distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
distributionUrl=https\://services.gradle.org/distributions/gradle-8.8-bin.zip
networkTimeout=10000
validateDistributionUrl=true
zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists

249
gradlew vendored Normal file
View File

@ -0,0 +1,249 @@
#!/bin/sh
#
# Copyright © 2015-2021 the original 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.
#
##############################################################################
#
# Gradle start up script for POSIX generated by Gradle.
#
# Important for running:
#
# (1) You need a POSIX-compliant shell to run this script. If your /bin/sh is
# noncompliant, but you have some other compliant shell such as ksh or
# bash, then to run this script, type that shell name before the whole
# command line, like:
#
# ksh Gradle
#
# Busybox and similar reduced shells will NOT work, because this script
# requires all of these POSIX shell features:
# * functions;
# * expansions «$var», «${var}», «${var:-default}», «${var+SET}»,
# «${var#prefix}», «${var%suffix}», and «$( cmd )»;
# * compound commands having a testable exit status, especially «case»;
# * various built-in commands including «command», «set», and «ulimit».
#
# Important for patching:
#
# (2) This script targets any POSIX shell, so it avoids extensions provided
# by Bash, Ksh, etc; in particular arrays are avoided.
#
# The "traditional" practice of packing multiple parameters into a
# space-separated string is a well documented source of bugs and security
# problems, so this is (mostly) avoided, by progressively accumulating
# options in "$@", and eventually passing that to Java.
#
# Where the inherited environment variables (DEFAULT_JVM_OPTS, JAVA_OPTS,
# and GRADLE_OPTS) rely on word-splitting, this is performed explicitly;
# see the in-line comments for details.
#
# There are tweaks for specific operating systems such as AIX, CygWin,
# Darwin, MinGW, and NonStop.
#
# (3) This script is generated from the Groovy template
# https://github.com/gradle/gradle/blob/HEAD/platforms/jvm/plugins-application/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt
# within the Gradle project.
#
# You can find Gradle at https://github.com/gradle/gradle/.
#
##############################################################################
# Attempt to set APP_HOME
# Resolve links: $0 may be a link
app_path=$0
# Need this for daisy-chained symlinks.
while
APP_HOME=${app_path%"${app_path##*/}"} # leaves a trailing /; empty if no leading path
[ -h "$app_path" ]
do
ls=$( ls -ld "$app_path" )
link=${ls#*' -> '}
case $link in #(
/*) app_path=$link ;; #(
*) app_path=$APP_HOME$link ;;
esac
done
# This is normally unused
# shellcheck disable=SC2034
APP_BASE_NAME=${0##*/}
# Discard cd standard output in case $CDPATH is set (https://github.com/gradle/gradle/issues/25036)
APP_HOME=$( cd "${APP_HOME:-./}" > /dev/null && pwd -P ) || exit
# Use the maximum available, or set MAX_FD != -1 to use that value.
MAX_FD=maximum
warn () {
echo "$*"
} >&2
die () {
echo
echo "$*"
echo
exit 1
} >&2
# OS specific support (must be 'true' or 'false').
cygwin=false
msys=false
darwin=false
nonstop=false
case "$( uname )" in #(
CYGWIN* ) cygwin=true ;; #(
Darwin* ) darwin=true ;; #(
MSYS* | MINGW* ) msys=true ;; #(
NONSTOP* ) nonstop=true ;;
esac
CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar
# Determine the Java command to use to start the JVM.
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
if [ ! -x "$JAVACMD" ] ; then
die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME
Please set the JAVA_HOME variable in your environment to match the
location of your Java installation."
fi
else
JAVACMD=java
if ! command -v java >/dev/null 2>&1
then
die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
Please set the JAVA_HOME variable in your environment to match the
location of your Java installation."
fi
fi
# Increase the maximum file descriptors if we can.
if ! "$cygwin" && ! "$darwin" && ! "$nonstop" ; then
case $MAX_FD in #(
max*)
# In POSIX sh, ulimit -H is undefined. That's why the result is checked to see if it worked.
# shellcheck disable=SC2039,SC3045
MAX_FD=$( ulimit -H -n ) ||
warn "Could not query maximum file descriptor limit"
esac
case $MAX_FD in #(
'' | soft) :;; #(
*)
# In POSIX sh, ulimit -n is undefined. That's why the result is checked to see if it worked.
# shellcheck disable=SC2039,SC3045
ulimit -n "$MAX_FD" ||
warn "Could not set maximum file descriptor limit to $MAX_FD"
esac
fi
# Collect all arguments for the java command, stacking in reverse order:
# * args from the command line
# * the main class name
# * -classpath
# * -D...appname settings
# * --module-path (only if needed)
# * DEFAULT_JVM_OPTS, JAVA_OPTS, and GRADLE_OPTS environment variables.
# For Cygwin or MSYS, switch paths to Windows format before running java
if "$cygwin" || "$msys" ; then
APP_HOME=$( cygpath --path --mixed "$APP_HOME" )
CLASSPATH=$( cygpath --path --mixed "$CLASSPATH" )
JAVACMD=$( cygpath --unix "$JAVACMD" )
# Now convert the arguments - kludge to limit ourselves to /bin/sh
for arg do
if
case $arg in #(
-*) false ;; # don't mess with options #(
/?*) t=${arg#/} t=/${t%%/*} # looks like a POSIX filepath
[ -e "$t" ] ;; #(
*) false ;;
esac
then
arg=$( cygpath --path --ignore --mixed "$arg" )
fi
# Roll the args list around exactly as many times as the number of
# args, so each arg winds up back in the position where it started, but
# possibly modified.
#
# NB: a `for` loop captures its iteration list before it begins, so
# changing the positional parameters here affects neither the number of
# iterations, nor the values presented in `arg`.
shift # remove old arg
set -- "$@" "$arg" # push replacement arg
done
fi
# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"'
# Collect all arguments for the java command:
# * DEFAULT_JVM_OPTS, JAVA_OPTS, JAVA_OPTS, and optsEnvironmentVar are not allowed to contain shell fragments,
# and any embedded shellness will be escaped.
# * For example: A user cannot expect ${Hostname} to be expanded, as it is an environment variable and will be
# treated as '${Hostname}' itself on the command line.
set -- \
"-Dorg.gradle.appname=$APP_BASE_NAME" \
-classpath "$CLASSPATH" \
org.gradle.wrapper.GradleWrapperMain \
"$@"
# Stop when "xargs" is not available.
if ! command -v xargs >/dev/null 2>&1
then
die "xargs is not available"
fi
# Use "xargs" to parse quoted args.
#
# With -n1 it outputs one arg per line, with the quotes and backslashes removed.
#
# In Bash we could simply go:
#
# readarray ARGS < <( xargs -n1 <<<"$var" ) &&
# set -- "${ARGS[@]}" "$@"
#
# but POSIX shell has neither arrays nor command substitution, so instead we
# post-process each arg (as a line of input to sed) to backslash-escape any
# character that might be a shell metacharacter, then use eval to reverse
# that process (while maintaining the separation between arguments), and wrap
# the whole thing up as a single "set" statement.
#
# This will of course break if any of these variables contains a newline or
# an unmatched quote.
#
eval "set -- $(
printf '%s\n' "$DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS" |
xargs -n1 |
sed ' s~[^-[:alnum:]+,./:=@_]~\\&~g; ' |
tr '\n' ' '
)" '"$@"'
exec "$JAVACMD" "$@"

92
gradlew.bat vendored Normal file
View File

@ -0,0 +1,92 @@
@rem
@rem Copyright 2015 the original author or authors.
@rem
@rem Licensed under the Apache License, Version 2.0 (the "License");
@rem you may not use this file except in compliance with the License.
@rem 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, software
@rem distributed under the License is distributed on an "AS IS" BASIS,
@rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
@rem See the License for the specific language governing permissions and
@rem limitations under the License.
@rem
@if "%DEBUG%"=="" @echo off
@rem ##########################################################################
@rem
@rem Gradle startup script for Windows
@rem
@rem ##########################################################################
@rem Set local scope for the variables with windows NT shell
if "%OS%"=="Windows_NT" setlocal
set DIRNAME=%~dp0
if "%DIRNAME%"=="" set DIRNAME=.
@rem This is normally unused
set APP_BASE_NAME=%~n0
set APP_HOME=%DIRNAME%
@rem Resolve any "." and ".." in APP_HOME to make it shorter.
for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi
@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m"
@rem Find java.exe
if defined JAVA_HOME goto findJavaFromJavaHome
set JAVA_EXE=java.exe
%JAVA_EXE% -version >NUL 2>&1
if %ERRORLEVEL% equ 0 goto execute
echo. 1>&2
echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 1>&2
echo. 1>&2
echo Please set the JAVA_HOME variable in your environment to match the 1>&2
echo location of your Java installation. 1>&2
goto fail
:findJavaFromJavaHome
set JAVA_HOME=%JAVA_HOME:"=%
set JAVA_EXE=%JAVA_HOME%/bin/java.exe
if exist "%JAVA_EXE%" goto execute
echo. 1>&2
echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% 1>&2
echo. 1>&2
echo Please set the JAVA_HOME variable in your environment to match the 1>&2
echo location of your Java installation. 1>&2
goto fail
:execute
@rem Setup the command line
set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar
@rem Execute Gradle
"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %*
:end
@rem End local scope for the variables with windows NT shell
if %ERRORLEVEL% equ 0 goto mainEnd
:fail
rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of
rem the _cmd.exe /c_ return code!
set EXIT_CODE=%ERRORLEVEL%
if %EXIT_CODE% equ 0 set EXIT_CODE=1
if not ""=="%GRADLE_EXIT_CONSOLE%" exit %EXIT_CODE%
exit /b %EXIT_CODE%
:mainEnd
if "%OS%"=="Windows_NT" endlocal
:omega

106
pom.xml Normal file
View File

@ -0,0 +1,106 @@
<?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 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>com.cisdi.data</groupId>
<artifactId>dacoo-data-sdk-yongfeng</artifactId>
<version>1.0-SNAPSHOT</version>
<properties>
<maven.compiler.source>8</maven.compiler.source>
<maven.compiler.target>8</maven.compiler.target>
</properties>
<dependencies>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.13.2</version>
<scope>test</scope>
</dependency>
<!-- <dependency>-->
<!-- <groupId>org.springframework.boot</groupId>-->
<!-- <artifactId>spring-boot-starter-web</artifactId>-->
<!-- </dependency>-->
<dependency>
<groupId>org.apache.tomcat.embed</groupId>
<artifactId>tomcat-embed-core</artifactId>
<version>8.5.51</version>
</dependency>
<dependency>
<groupId>org.apache.tomcat.embed</groupId>
<artifactId>tomcat-embed-el</artifactId>
<version>8.5.51</version>
</dependency>
<dependency>
<groupId>org.apache.tomcat.embed</groupId>
<artifactId>tomcat-embed-websocket</artifactId>
<version>8.5.51</version>
</dependency>
<dependency>
<groupId>org.apache.tomcat</groupId>
<artifactId>tomcat-annotations-api</artifactId>
<version>8.5.51</version>
</dependency>
<dependency>
<groupId>com.cisdi.data</groupId>
<artifactId>dacoo-data-common</artifactId>
<version>1.0-SNAPSHOT</version>
</dependency>
<dependency>
<groupId>com.cisdi.data</groupId>
<artifactId>dacoo-data-sdk</artifactId>
<version>1.0-SNAPSHOT</version>
<exclusions>
<exclusion>
<artifactId>netty-all</artifactId>
<groupId>io.netty</groupId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>io.netty</groupId>
<artifactId>netty-all</artifactId>
<version>4.1.97.Final</version>
</dependency>
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-dbcp2</artifactId>
<version>2.8.0</version>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>5.1.46</version>
</dependency>
<!-- https://mvnrepository.com/artifact/com.google.guava/guava -->
<dependency>
<groupId>com.google.guava</groupId>
<artifactId>guava</artifactId>
<version>27.0-jre</version>
</dependency>
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>easyexcel</artifactId>
<version>1.1.2-beta5</version>
</dependency>
<dependency>
<groupId>org.java-websocket</groupId>
<artifactId>Java-WebSocket</artifactId>
<version>1.3.8</version>
</dependency>
<!-- https://mvnrepository.com/artifact/org.projectlombok/lombok -->
<!-- https://mvnrepository.com/artifact/org.projectlombok/lombok -->
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>1.18.28</version>
<scope>provided</scope>
</dependency>
</dependencies>
</project>

28
rfid测试说明.txt Normal file
View File

@ -0,0 +1,28 @@
心跳报文
02486561727442656103
一个标签
02524630313030303103
--2条电文
0252463031303030310302524830333030303103
-- 4条电文
02524630313030303103025248303330303031030252463031303030310302524830333030303103
-- 4条电文心跳2
025246303130303031030252483033303030310302524630313030303103025248303330303031030248656172744265610302486561727442656103
一个标签+心跳+ 一个标签
02524630313030303103024865617274426561030252463031303030310302524630313030303103025246303130303031030252463031303030310302524630313030303103025246303130303031030252483033303030310302524630313030303103025248303330303031030248656172744265610302486561727442656103
-- 启用心跳
{"enableHeartbeat":true,"heartbeatMaxLostCount":3,"heartbeatTimeInMs":5000}
--多个serverId
{"serverList":["10.233.8.22:2112","10.233.8.23:2112","10.233.8.24:2112","10.233.8.25:2112"]}
--启用心跳+ 多个server
{"enableHeartbeat":true,"heartbeatMaxLostCount":3,"heartbeatTimeInMs":5000,"serverList":["10.233.8.22:2112","10.233.8.23:2112","10.233.8.24:2112","10.233.8.25:2112"]}

2
settings.gradle Normal file
View File

@ -0,0 +1,2 @@
rootProject.name = 'dacoo-data-sdk-DI-client'

View File

@ -0,0 +1,209 @@
package com.cisdi.data.AMETEKSurfaceVision;
import com.alibaba.fastjson.JSON;
import com.cisdi.data.AMETEKSurfaceVision.gateway.SurfaceVisionAliveCheckTask;
import com.cisdi.data.AMETEKSurfaceVision.gateway.SurfaceVisionChannelInitializer;
import com.cisdi.data.AMETEKSurfaceVision.gateway.SurfaceVisionFrameDecoder;
import com.cisdi.data.AMETEKSurfaceVision.gateway.SurfaceVisionIoSession;
import com.cisdi.data.AMETEKSurfaceVision.gateway.SurfaceVisionSessionFactory;
import com.cisdi.data.AMETEKSurfaceVision.gateway.SurfaceVisionSocketReturnMessage;
import com.cisdi.data.common.exception.BusinessException;
import com.cisdi.data.sdk.consts.ServiceName;
import com.cisdi.data.sdk.enums.GatewayState;
import com.cisdi.data.sdk.gateway.base.SocketGatewayBase;
import com.cisdi.data.sdk.gateway.netty.IoSession;
import com.cisdi.data.sdk.gateway.netty.SessionFactory;
import com.cisdi.data.sdk.gateway.netty.TcpIoService;
import com.cisdi.data.sdk.gateway.netty.impl.DefaultTcpIoService;
import com.cisdi.data.sdk.param.ListenSocketParam;
import com.cisdi.data.sdk.procotol.message.SocketReturnMessage;
import com.cisdi.data.sdk.service.RouteService;
import com.cisdi.data.sdk.vo.DeviceVo;
import com.cisdi.data.sdk.vo.ExeResultVo;
import com.google.common.collect.Sets;
import java.util.List;
import java.util.Set;
import java.util.concurrent.BlockingQueue;
import java.util.concurrent.LinkedBlockingQueue;
import java.util.concurrent.atomic.AtomicBoolean;
import lombok.SneakyThrows;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.BeanUtils;
/**
* 表检仪tcp协议 平台server rfid客户端
*
* @author tzz
*/
public class AMETEKSurfaceVisionGateway extends SocketGatewayBase {
private static Logger logger = LoggerFactory.getLogger(AMETEKSurfaceVisionGateway.class);
private TcpIoService ioService = null;
private SessionFactory sessionFactory = null;
private AtomicBoolean shouldRun = new AtomicBoolean(false);
private String deviceId;
private BlockingQueue<SocketReturnMessage> sendQueue = new LinkedBlockingQueue<>(1);
/**
* 下发命令超时时间单位毫秒
*/
private static int maxSendTime = 5000;
private static final int sleepInternal = 100;
//10毫秒
@SneakyThrows
@Override
public ExeResultVo sendReturnMessage(SocketReturnMessage returnMsg) {
logger.info("send msg is :{}", returnMsg);
//阻塞队列容量为1若上一个命令未发送则阻塞
sendQueue.put(returnMsg);
ExeResultVo sendResult = new ExeResultVo();
sendResult.setSuccess(false);
try {
SurfaceVisionSocketReturnMessage sendMsg = new SurfaceVisionSocketReturnMessage();
BeanUtils.copyProperties(returnMsg, sendMsg);
sendMsg.setSendReturnFlag(false);
//发送下发命令
List<IoSession> sessions = sessionFactory.getSessions();
SurfaceVisionIoSession ioSession = (SurfaceVisionIoSession) sessions.get(0);
logger.info("send msg SurfaceVisionIoSession is :{}", ioSession);
ioSession.send(sendMsg);
//等待下发命令返回若等待时间超过最大等待时长直接返回下发失败,每隔sleepInternal时间判断一次
long sendTime = System.currentTimeMillis();
while (!sendMsg.getSendReturnFlag()) {
long now = System.currentTimeMillis();
if ((now - sendTime) > (maxSendTime)) {
sendResult.setMessage("下发命令响应超时,超时时间为:" + maxSendTime + "ms");
ioSession.setCurrentSend(null);
return sendResult;
}
Thread.sleep(sleepInternal);
}
ioSession.setCurrentSend(null);
logger.info("send result is :{}", sendMsg.getRealData());
sendResult = sendMsg.getRealData();
}catch (Exception e){
logger.error("下发中断,异常为: ", e);
sendResult.setMessage("下发异常中断");
}finally {
//空出阻塞队列
sendQueue.take();
}
return sendResult;
}
@Override
public void start() {
if(state == GatewayState.RUNNING) {
return;
}
//配置信息校验
ListenSocketParam socketParam = JSON.parseObject(getInstanceVo().getParameter(), ListenSocketParam.class);
maxSendTime = socketParam.getTimeout();
if (StringUtils.isEmpty(socketParam.getListenIp()) || socketParam.getListenPort() == null) {
throw new BusinessException("未正确配置监听ip地址和监听端口。");
}
logger.info("AMETEKSurfaceVision网关:{}读取启动配置参数:{}",instanceVo.getRunId(), getInstanceVo().getParameter());
//读取网关连接配置参数
RouteService routeService = (RouteService) serviceProvider.getByName(ServiceName.Route);
List<DeviceVo> deviceVos = routeService.findByRunId(instanceVo.getRunId());
//一个网关连接只能配置一个设备
if(deviceVos.size() > 1) {
throw new BusinessException("网关Id:" +instanceVo.getRunId() + "为AMETEKSurfaceVision网关只允许关联一个设备Id");
}
deviceId = deviceVos.size() > 0 ? deviceVos.get(0).getDeviceId() : null;
if(StringUtils.isEmpty(deviceId)) {
throw new BusinessException("runId=" + getInstanceVo().getRunId() + "未正确配置网关和设备关联");
}
//创建session工厂并初始化
DefaultTcpIoService defaultIoService = new DefaultTcpIoService();
SessionFactory factory = new SurfaceVisionSessionFactory(deviceId);
factory.init(serviceProvider, this);
//初始化channel
SurfaceVisionChannelInitializer<SurfaceVisionFrameDecoder> channelInitializer =
new SurfaceVisionChannelInitializer<>(factory);
//初始化ioService
defaultIoService.init(instanceVo, factory, channelInitializer);
ioService = defaultIoService;
sessionFactory = factory;
//启动监听
boolean open = ioService.open();
if(open == true) {
state = GatewayState.RUNNING;
logger.info("AMETEKSurfaceVision网关:{}启动成功 参数:{}", instanceVo.getRunId(), getInstanceVo().getParameter());
instanceVo.setLogOpen(true);
//心跳机制
shouldRun.set(true);
//
// Integer keepAlive = socketParam.getKeepAlive();
//
// if(keepAlive == null || keepAlive < 10) {
// keepAlive = 10;
// }else if (keepAlive > 60) {
// keepAlive = 60;
// }
//
// SurfaceVisionAliveCheckTask task = new SurfaceVisionAliveCheckTask(keepAlive, shouldRun, factory);
//
// Thread thread = new Thread(task, "ametek-surface-alive-check-thread-" + getInstanceVo().getRunId());
// thread.start();
}else {
logger.info("AMETEKSurfaceVision网关:{}启动失败 参数:{}", instanceVo.getRunId(), getInstanceVo().getParameter());
}
}
@Override
public void shutdown() {
if(state == GatewayState.CLOSED) {
return;
}
//关闭channel
if(sessionFactory != null) {
for (IoSession ioSession : sessionFactory.getSessions()) {
SurfaceVisionIoSession imsIoSession = (SurfaceVisionIoSession)ioSession;
imsIoSession.close();
}
}
//关闭监听和会话
boolean close = ioService.close();
if(close == true) {
sessionFactory = null;
state = GatewayState.CLOSED;
shouldRun.set(false);
logger.info("AMETEKSurfaceVision网关:{}关闭成功", instanceVo.getRunId());
}else {
logger.info("AMETEKSurfaceVision网关:{}关闭失败", instanceVo.getRunId());
}
}
@Override
public Set<String> getActiveDeviceIds() {
Set<String> set = Sets.newHashSet();
set.add(deviceId);
return set;
}
}

View File

@ -0,0 +1,41 @@
package com.cisdi.data.AMETEKSurfaceVision;
import com.cisdi.data.AMETEKSurfaceVision.gateway.SurfaceVisionConstants;
import java.util.Map;
import com.cisdi.data.sdk.gateway.message.SocketMessage;
import com.cisdi.data.sdk.procotol.SocketProtocol;
import com.cisdi.data.sdk.procotol.base.ProtocolBase;
import com.cisdi.data.sdk.procotol.message.SocketReturnMessage;
import com.cisdi.data.sdk.vo.DecodeVo;
import com.cisdi.data.sdk.vo.ReturnVo;
/**
* 表检仪协议发送给平台的数据编解码
*
* @author tzz
*/
public class AMETEKSurfaceVisionSocketProtocol extends ProtocolBase implements SocketProtocol {
@SuppressWarnings("unchecked")
@Override
public DecodeVo deCode(SocketMessage message) {
DecodeVo vo = new DecodeVo();
Object object = message.getPropsMap().get(SurfaceVisionConstants.S_V_SEND_PLATFORM_DATA);
Map<String, Object> map = (Map<String, Object>)object;
vo.setData(map);
return vo;
}
@Override
public SocketReturnMessage enCode(ReturnVo returnVo) {
SocketReturnMessage message = new SocketReturnMessage();
message.setDeviceId(returnVo.getDeviceId());
message.setMsgId(returnVo.getMsgId());
message.setMsgKey(returnVo.getMsgKey());
message.getPropsMap().put(SurfaceVisionConstants.S_V_SEND_DATA, returnVo.getValue());
return message;
}
}

View File

@ -0,0 +1,98 @@
package com.cisdi.data.AMETEKSurfaceVision;
import java.util.ArrayList;
import java.util.List;
/**
* 实例点位信息
*
* @author tzz
*/
public class DynamicCodeActionParamDTO {
public enum PropertyType {
BYTE,
BOOLEAN,
SHORT,
INT,
FLOAT,
DOUBLE,
STRING,
LONG,
PLACEHOLDER;
}
private List<PropertyConfig> propertyList;
public void appendProperty(PropertyConfig propertyConfig) {
if (propertyConfig == null) {
return;
}
if (propertyList == null) {
propertyList = new ArrayList<>();
}
propertyList.add(propertyConfig);
}
public static class PropertyConfig{
/** 属性Id*/
private String propertyId;
/** 属性类型*/
private PropertyType propertyType;
/**长度*/
private Integer length;
public String getPropertyId() {
return propertyId;
}
public void setPropertyId(String propertyId) {
this.propertyId = propertyId;
}
public PropertyType getPropertyType() {
return propertyType;
}
public void setPropertyType(PropertyType propertyType) {
this.propertyType = propertyType;
}
public Integer getLength() {
return length;
}
public void setLength(Integer length) {
this.length = length;
}
@Override
public String toString() {
return "PropertyConfig{" +
"propertyId='" + propertyId + '\'' +
", propertyType=" + propertyType +
", length=" + length +
'}';
}
}
public List<PropertyConfig> getPropertyList() {
return propertyList;
}
public void setPropertyList(List<PropertyConfig> propertyList) {
this.propertyList = propertyList;
}
@Override
public String toString() {
return "DynamicCodeActionParamDTO{" +
"propertyList=" + propertyList +
'}';
}
}

View File

@ -0,0 +1,70 @@
package com.cisdi.data.AMETEKSurfaceVision.gateway;
import com.cisdi.data.sdk.gateway.netty.IoSession;
import com.cisdi.data.sdk.gateway.netty.SessionFactory;
import java.util.List;
import java.util.concurrent.atomic.AtomicBoolean;
import lombok.extern.slf4j.Slf4j;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
* 保活时间检测如果超过指定时间则关闭连接
* @author tzz
*
*/
@Slf4j
public class SurfaceVisionAliveCheckTask implements Runnable {
private SessionFactory sessionFactory;
private AtomicBoolean shouldRun = null;
/**
* 会话允许的保活时间单位秒
*/
private int keepAlive;
private static final double multiply = 2;
private static final int sleepInternal = 1000; // 1秒
public SurfaceVisionAliveCheckTask(int keepAlive, AtomicBoolean shouldRun, SessionFactory sessionFactory) {
super();
this.keepAlive = keepAlive;
this.shouldRun = shouldRun;
this.sessionFactory = sessionFactory;
}
@Override
public void run() {
log.info("启动SurfaceVision心跳及检测心跳线程");
while (shouldRun != null && shouldRun.get() == true) {
try {
long now = System.currentTimeMillis();
List<IoSession> sessions = sessionFactory.getSessions();
for (IoSession ioSession : sessions) {
SurfaceVisionIoSession session = (SurfaceVisionIoSession)ioSession;
log.info("{} 定时心跳发送检测", session.gwPrefix());
session.sendBeat();
// 超出指定倍数心跳时间关闭通道
if((now - session.getLastAliveTime()) > (multiply * keepAlive * 1000)) {
session.close();
log.warn("{} 超出指定倍数{}心跳时间{},单位秒,关闭通道",
session.gwPrefix(), multiply, keepAlive);
}
}
Thread.sleep(sleepInternal);
} catch (Exception e) {
log.warn(e.getLocalizedMessage(), e);
}
}
log.info("结束SurfaceVision保活超时检测线程");
}
}

View File

@ -0,0 +1,51 @@
package com.cisdi.data.AMETEKSurfaceVision.gateway;
import com.cisdi.data.sdk.gateway.netty.SessionFactory;
import com.cisdi.data.sdk.gateway.netty.impl.AbstractChannelInitializer;
import com.cisdi.data.sdk.gateway.netty.impl.AbstractIoChannelHandler;
import com.cisdi.data.sdk.gateway.netty.impl.DefaultIoChannelHandler;
import io.netty.channel.Channel;
import io.netty.channel.ChannelHandler;
import io.netty.handler.timeout.IdleStateHandler;
import java.util.ArrayList;
import java.util.List;
/**
* 表检仪协议通道初始化
*
* @author tzz
*/
public class SurfaceVisionChannelInitializer<I> extends AbstractChannelInitializer<I> {
private SessionFactory factory;
/**
* 构造通道初始化器对象
* @param factory 会话工厂
*/
public SurfaceVisionChannelInitializer(SessionFactory factory) {
this.factory = factory;
}
@SuppressWarnings("unchecked")
@Override
protected AbstractIoChannelHandler<I> getTailHandler() {
return new DefaultIoChannelHandler(factory);
}
@Override
protected List<ChannelHandler> getHandlers() {
List<ChannelHandler> handlers = new ArrayList<ChannelHandler>();
handlers.add(new SurfaceVisionFrameDecoder());
return handlers;
}
@Override
protected IdleStateHandler getIdleStateHandler() {
return new IdleStateHandler(15, 15, 30);
}
@Override
protected ChannelHandler getSslChannelHandler(Channel socketChannel) {
return null;
}
}

View File

@ -0,0 +1,73 @@
package com.cisdi.data.AMETEKSurfaceVision.gateway;
/**
* 存储表检仪协议常量信息
*
* @author tzz
*/
public final class SurfaceVisionConstants {
//下发命令返回消息头类型
/**
* 非Query类型命令下发返回消息头使用starWith判断
*/
public static final String RETURN_HEADER1 = "REPLY_";
/**
* 默认下发返回消息头应为下发命令报错时消息返回头使用equals判断
*/
public static final String RETURN_HEADER2 = "REPLY";
/**
* Query类型命令下发返回消息头使用equals判断
*/
public static final String RETURN_HEADER3 = "RESULT";
/**
* 命令下发返回成功状态值ok代表成功
*/
public static final String RETURN_OK = "OK";
/**
* 消息分隔符
*/
public static final String SEPARATE1 = "\\|";
/**
* 消息分隔符
*/
public static final char SEPARATE = '|';
/**
* 消息结束符|以外
*/
public static final char[] END = {'$','\r','\n'};
/**
* Query类型命令下发消息头使用starWith判断
*/
public static final String QUERY = "QUERY";
/**
* 下发命令计数器最大值
*/
public static final int MAX_COUNT = 100;
/**
* 下发命令正常返回消息最小字段数
*/
public static final int MIN_NORMAL_RETURN = 3;
/**
* 下发命令数据KEY
*/
public static final String S_V_SEND_DATA = "surfaceVisionSendData";
/**
* 返回给平台数据KEY
*/
public static final String S_V_SEND_PLATFORM_DATA = "surfaceVisionSendPlatformData";
/** 心跳符,$的16进制 */
public static final byte BEAT_BYTE = 0x07;
}

View File

@ -0,0 +1,49 @@
package com.cisdi.data.AMETEKSurfaceVision.gateway;
import com.cisdi.data.AMETEKSurfaceVision.DynamicCodeActionParamDTO.PropertyConfig;
import com.cisdi.data.common.exception.BusinessException;
import io.netty.buffer.ByteBuf;
import io.netty.buffer.Unpooled;
import java.nio.charset.StandardCharsets;
import java.util.List;
import java.util.Map;
/**
* 表检仪编码
*
* @author zhongda
*/
public class SurfaceVisionEncoder {
/**
* 下发命令编码
* @param msgKey 消息头也是平台电文ID
* @param propsMap 下发消息
* @param propertyConfigList 下发消息点位配置表
* @param count 下发消息replayId
*/
public static ByteBuf Encode(String msgKey, Map<String, Object> propsMap, List<PropertyConfig> propertyConfigList, int count) {
StringBuffer stringBuffer = new StringBuffer();
//组装消息头
stringBuffer.append(msgKey).append(SurfaceVisionConstants.SEPARATE);
//非Query命令添加replayId
if (!msgKey.startsWith(SurfaceVisionConstants.QUERY)){
stringBuffer.append(count).append(SurfaceVisionConstants.SEPARATE);
}
//组装消息体
for (PropertyConfig propertyConfig : propertyConfigList){
String key = propertyConfig.getPropertyId();
stringBuffer.append(propsMap.get(key))
.append(SurfaceVisionConstants.SEPARATE);
}
//组装消息结尾
stringBuffer.append(String.valueOf(SurfaceVisionConstants.END));
//UTF_8编码下发消息
byte[] bytes = stringBuffer.toString().getBytes(StandardCharsets.UTF_8);
ByteBuf wrappedBuffer = Unpooled.wrappedBuffer(bytes);
return wrappedBuffer;
}
}

View File

@ -0,0 +1,59 @@
package com.cisdi.data.AMETEKSurfaceVision.gateway;
import io.netty.buffer.ByteBuf;
import io.netty.buffer.Unpooled;
import io.netty.channel.ChannelHandlerContext;
import io.netty.handler.codec.ByteToMessageDecoder;
import java.util.List;
/**
* 表检仪协议帧解码
*
* @author tzz
*/
public class SurfaceVisionFrameDecoder extends ByteToMessageDecoder {
/** 结束符除|第一位,$的16进制 */
private byte end = 0x24;
/** 结束符除|第二位,\r的16进制 */
private byte end1 = 0x0D;
/** 结束符除|第三位,\n的16进制 */
private byte end2 = 0x0A;
@Override
protected void decode(ChannelHandlerContext ctx, ByteBuf bufferIn, List<Object> out) throws Exception {
if (bufferIn.readableBytes() < 1){
return;
}
final int beginIndex = bufferIn.readerIndex();
int length = 0;
for (int i = 0; i + 2 < bufferIn.readableBytes(); i += 1) {
byte curByte = bufferIn.getByte(beginIndex + i);
//判断是否为结束符若为结束符读取从beginIndex开始的所有数据
if (curByte == end){
if (end1 == bufferIn.getByte(beginIndex + i + 1) &&
end2 == bufferIn.getByte(beginIndex + i + 2)){
length = i + 3;
byte[] bytes = new byte[i+3];
bufferIn.readBytes(bytes);
ByteBuf copiedBuff = Unpooled.copiedBuffer(bytes);
out.add(copiedBuff);
break;
}
}
if (i + 3 == bufferIn.readableBytes()){
return;
}
}
//若未结束重置读索引
bufferIn.readerIndex(beginIndex + length);
//解决可能得粘包和拆包问题
decode(ctx, bufferIn, out);
return;
}
}

View File

@ -0,0 +1,82 @@
package com.cisdi.data.AMETEKSurfaceVision.gateway;
import java.util.List;
import java.util.Map;
import lombok.ToString;
/**
* @author tzz
*/
@ToString
public class SurfaceVisionFrameInputVo {
/** 电文ID */
private String msgKey;
/** 下发命令返回ID */
private Integer ReplayId;
/** 下发命令返回状态值,true:成功,false:失败 */
private Boolean status;
/** 下发命令返回描述 */
private String description;
/** 是否为心跳信息 */
private Boolean beatType = false;
/** 通过命令上传的返回的数据值,按照顺序填入 */
private List<String> data;
/** 通过命令上传的返回的数据值与配置点位的点位id对应按照顺序对应 */
private Map<String, Object> returnData;
public String getMsgKey() {
return msgKey;
}
public Integer getReplayId() {
return ReplayId;
}
public Boolean getStatus() {
return status;
}
public String getDescription() {
return description;
}
public List<String> getData() {
return data;
}
public Boolean getBeatType() {
return beatType;
}
public Map<String, Object> getReturnData() {
return returnData;
}
public void setReturnData(Map<String, Object> returnData) {
this.returnData = returnData;
}
public void setBeatType(Boolean beatType) {
this.beatType = beatType;
}
public void setMsgKey(String msgKey) {
this.msgKey = msgKey;
}
public void setReplayId(Integer replayId) {
ReplayId = replayId;
}
public void setStatus(Boolean status) {
this.status = status;
}
public void setDescription(String description) {
this.description = description;
}
public void setData(List<String> data) {
this.data = data;
}
}

View File

@ -0,0 +1,291 @@
package com.cisdi.data.AMETEKSurfaceVision.gateway;
import com.alibaba.fastjson.JSON;
import com.cisdi.data.AMETEKSurfaceVision.DynamicCodeActionParamDTO;
import com.cisdi.data.AMETEKSurfaceVision.DynamicCodeActionParamDTO.PropertyConfig;
import com.cisdi.data.common.exception.BusinessException;
import com.cisdi.data.sdk.consts.ServiceName;
import com.cisdi.data.sdk.gateway.message.SocketMessage;
import com.cisdi.data.sdk.gateway.netty.IoSession;
import com.cisdi.data.sdk.gateway.netty.impl.AbstractIoSession;
import com.cisdi.data.sdk.service.DynamicCodecService;
import com.cisdi.data.sdk.service.SendService;
import com.cisdi.data.sdk.service.Service;
import com.cisdi.data.sdk.vo.ExeResultVo;
import io.netty.buffer.ByteBuf;
import io.netty.buffer.Unpooled;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
* 表检仪协议会话
*
* @author tzz
*/
public class SurfaceVisionIoSession extends AbstractIoSession implements IoSession {
private long lastAliveTime = System.currentTimeMillis();
private static Logger logger = LoggerFactory.getLogger(SurfaceVisionIoSession.class);
private String deviceId = null;
private String gwPrefixCache = null;
private final static byte[] beat = {0x07,0x7C,0x24,0x0D,0x0A};
private int count = 1;
// 初始化为0的原子整型变量作为计数器,用作发送命令的replayId,初始值为1
/** 当前下发命令replayId */
private Integer currentCount = -1;
public void setCurrentSend(SurfaceVisionSocketReturnMessage currentSend) {
this.currentSend = currentSend;
}
/** 当前下发命令信息 */
private SurfaceVisionSocketReturnMessage currentSend = null;
public void increment() {
if (count < SurfaceVisionConstants.MAX_COUNT) {
count++;
// 自增1并返回新值
}
else {
count = 1;
}
}
public int getCount() {
return count;
// 获取当前计数器的值
}
public SurfaceVisionIoSession(String deviceId) {
this.deviceId = deviceId;
}
@Override
public String[] getDeviceIds() {
return new String[0];
}
/** 获取当前下发电文点位配置信息 */
private List<PropertyConfig> getPropertyConfig(String msgKeyName){
//获取DynamicService
Service service = serviceProvider.getByName(ServiceName.DynamicCodec);
if (service == null || !(service instanceof DynamicCodecService)) {
throw new BusinessException("获取DynamicService失败");
}
//获取网关ID
String runId = socketGateway.getInstanceVo().getRunId();
//获取点位配置信息
DynamicCodecService dynamicCodecService = (DynamicCodecService)service;
String actionParam = dynamicCodecService.findByRunIdAndMsgKey(runId, msgKeyName);
DynamicCodeActionParamDTO dto = null;
try {
dto = JSON.parseObject(actionParam, DynamicCodeActionParamDTO.class);
} catch (Exception e) {
throw new BusinessException("连接id:" + runId + "电文号:" + msgKeyName + "json转换错误", e);
}
if (dto == null || dto.getPropertyList() == null || dto.getPropertyList().isEmpty()) {
throw new BusinessException("连接id:" + runId + "电文号:" + msgKeyName + "属性列表为空");
}
//返回点位信息
return dto.getPropertyList();
}
@Override
public void onRead(Object message) {
//获取表检仪上送或返回消息
ByteBuf inBuf = (ByteBuf) message;
int length = inBuf.readableBytes();
//将消息头和消息体拆包解析出消息头信息
SurfaceVisionFrameInputVo vo = SurfaceVisionVoDecoder.Decode(inBuf);
logger.info("AMETEKSurfaceVision收到 msg: {}", vo);
//消息头也是电文信息
String msgKey = vo.getMsgKey();
try {
//通过消息头判断返回消息类型
if(vo.getBeatType()){
//判断是否心跳信息
lastAliveTime = System.currentTimeMillis();
logger.info("接收到心跳消息,当前时间为:{}", lastAliveTime);
} else if (msgKey.startsWith(SurfaceVisionConstants.RETURN_HEADER1)) {
//非Query命令正常返回消息
//解码
SurfaceVisionVoDecoder.DecodeReturn(vo);
//组装返回信息判断replayId是否一致
ExeResultVo sendResult = new ExeResultVo();
if (!currentCount.equals(vo.getReplayId())) {
logger.info("AMETEKSurfaceVision收到 msgkey: {} 消息:{}, ReplayId{} 与实际发送下去的:{},不一致"
, msgKey, vo, vo.getReplayId(), currentCount);
sendResult.setSuccess(false);
sendResult.setMessage("返回消息replayId与发送消息replayId不符");
} else {
sendResult.setSuccess(vo.getStatus());
sendResult.setMessage(vo.getDescription());
}
//组装返回结果
returnData(sendResult);
} else if (SurfaceVisionConstants.RETURN_HEADER2.equals(msgKey)) {
//下发命令异常返回消息
//解码
SurfaceVisionVoDecoder.DecodeReturnError(vo);
ExeResultVo sendResult = new ExeResultVo();
sendResult.setSuccess(vo.getStatus());
sendResult.setMessage(vo.getDescription());
//组装返回结果
returnData(sendResult);
} else if (SurfaceVisionConstants.RETURN_HEADER3.equals(msgKey)) {
//Query命令返回
//解码
SurfaceVisionVoDecoder.DecodeReturnQuery(vo);
ExeResultVo sendResult = new ExeResultVo();
sendResult.setSuccess(vo.getStatus());
sendResult.setMessage(vo.getDescription());
Map<Object, Object> queryData = new HashMap<>();
queryData.putAll(vo.getReturnData());
sendResult.setData(queryData);
//组装返回结果
returnData(sendResult);
} else {
//主动上报消息
//解码
SurfaceVisionVoDecoder.DecodeData(vo, getPropertyConfig(msgKey));
Map<String, Object> realDataMap = vo.getReturnData();
//数据发送到平台
if (vo != null && serviceProvider != null && socketGateway != null) {
SendService service = (SendService) serviceProvider.getByName(ServiceName.Send);
//组装数据包
SocketMessage socketMessage = socketGateway.buildSocketMessage();
socketMessage.setDeviceId(deviceId);
socketMessage.getPropsMap().put(SurfaceVisionConstants.S_V_SEND_PLATFORM_DATA, realDataMap);
socketMessage.setMsgKey(msgKey);
//发送数据
service.sendMessage(socketMessage);
} else {
logger.info("AMETEKSurfaceVision收到 msgkey: {} 消息:{}, 但是不能发到平台", msgKey, JSON.toJSONString(realDataMap));
}
}
}catch (Exception e){
logger.error("AMETEKSurfaceVision接收消息匹配错误, msgKey: {}, msg:{}, error", msgKey, vo, e);
}
if(socketGateway!= null && Boolean.TRUE.equals(socketGateway.getInstanceVo().getLogOpen())) {
logger.info("AMETEKSurfaceVision {} 报文长度:{} vo:{} ", getChannel(), length, JSON.toJSONString(vo));
}
}
/** 设置当前下发命令返回信息 */
private void returnData(ExeResultVo sendResult) {
if(currentSend == null){
throw new BusinessException("下发返回消息没有对应的下发命令");
}
currentSend.setRealData(sendResult);
currentSend.setSendReturnFlag(true);
currentSend = null;
}
@Override
public void onOpen() {
super.onOpen();
logger.info("建立连接channel:{}", getChannel());
}
@Override
public void onClose() {
super.onClose();
}
public void close() {
if(getChannel() != null) {
try {
getChannel().close().sync();
} catch (InterruptedException e) {
logger.warn(e.getLocalizedMessage(), e);
}
}
}
public String gwPrefix() {
if(gwPrefixCache != null) {
return gwPrefixCache;
}
gwPrefixCache = "";
if(socketGateway != null && socketGateway.getInstanceVo() != null) {
gwPrefixCache = "网关Id:" + socketGateway.getInstanceVo().getRunId() + "连接:" + getChannel() + " ";
}else {
gwPrefixCache = "连接:" + getChannel() + " ";
}
return gwPrefixCache;
}
public long getLastAliveTime() {
return lastAliveTime;
}
@Override
public void send(Object message) {
//下发命令
SurfaceVisionSocketReturnMessage returnMsg = (SurfaceVisionSocketReturnMessage) message;
String msgKey = returnMsg.getMsgKey();
//与AMETEKSurfaceVisionSocketProtocol类对应
Map<String, Object> propsMap = (Map<String, Object>)
returnMsg.getPropsMap().get(SurfaceVisionConstants.S_V_SEND_DATA);
//获取下发点位配置
List<PropertyConfig> propertyConfigList = getPropertyConfig(msgKey);
//获取计数器值作为下发命令replayId
int c = getCount();
logger.info("下发数据, 数据:{}, 点位配置:{}, 返回ID:{}", propsMap, propertyConfigList, c);
ByteBuf byteBuf = SurfaceVisionEncoder.Encode(msgKey, propsMap, propertyConfigList, c);
logger.info("下发数据的byteBuf:{}", byteBuf);
//下发命令编码后发送
getChannel().writeAndFlush(byteBuf);
logger.info("下发数据成功");
//缓存当前下发命令信息和replayId
currentSend = returnMsg;
currentCount = c;
//计数器自增
increment();
}
public void sendBeat() {
logger.info("发送心跳");
ByteBuf byteBuf = Unpooled.wrappedBuffer(beat);
getChannel().writeAndFlush(byteBuf);
logger.info("心跳发送成功");
}
}

View File

@ -0,0 +1,26 @@
package com.cisdi.data.AMETEKSurfaceVision.gateway;
import com.cisdi.data.sdk.gateway.netty.IoSession;
import com.cisdi.data.sdk.gateway.netty.impl.AbstractSessionFactory;
import java.util.UUID;
/**
* 表检仪协议会话工厂
*
* @author tzz
*/
public class SurfaceVisionSessionFactory extends AbstractSessionFactory {
private String deviceId;
public SurfaceVisionSessionFactory(String deviceId) {
this.deviceId = deviceId;
}
@Override
public IoSession newSession() {
IoSession session = new SurfaceVisionIoSession(deviceId);
session.init(UUID.randomUUID().toString(), provider, socketGateway);
sessionSet.add(session);
return session;
}
}

View File

@ -0,0 +1,41 @@
package com.cisdi.data.AMETEKSurfaceVision.gateway;
import com.alibaba.fastjson.JSON;
import com.cisdi.data.sdk.procotol.message.SocketReturnMessage;
import com.cisdi.data.sdk.vo.ExeResultVo;
/**
* 表检仪协议下发消息及返回信息
*
* @author tzz
*/
public class SurfaceVisionSocketReturnMessage extends SocketReturnMessage {
/** 下发消息返回消息 */
ExeResultVo realData;
/** 下发消息返回标志 */
boolean sendReturnFlag;
public SurfaceVisionSocketReturnMessage() {
}
public ExeResultVo getRealData() {
return this.realData;
}
public void setRealData(ExeResultVo realData) {
this.realData = realData;
}
public boolean getSendReturnFlag() {
return this.sendReturnFlag;
}
public void setSendReturnFlag(boolean sendReturnFlag) {
this.sendReturnFlag = sendReturnFlag;
}
@Override
public String toString() {
return JSON.toJSONString(this);
}
}

View File

@ -0,0 +1,226 @@
package com.cisdi.data.AMETEKSurfaceVision.gateway;
import com.alibaba.fastjson.JSON;
import com.cisdi.data.AMETEKSurfaceVision.DynamicCodeActionParamDTO.PropertyConfig;
import com.cisdi.data.AMETEKSurfaceVision.DynamicCodeActionParamDTO.PropertyType;
import com.cisdi.data.common.exception.BusinessException;
import com.cisdi.data.sdk.procotol.message.SocketReturnMessage;
import io.netty.buffer.ByteBuf;
import io.netty.buffer.Unpooled;
import java.nio.charset.StandardCharsets;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import org.springframework.beans.BeanUtils;
/**
* 表检仪解码
*
* @author zhongda
*/
public class SurfaceVisionVoDecoder {
/** 将消息头和消息体拆包,解析出消息头信息 */
public static SurfaceVisionFrameInputVo Decode(ByteBuf in) {
SurfaceVisionFrameInputVo vo = new SurfaceVisionFrameInputVo();
//消息体部分
int length;
if (in == null) {
throw new BusinessException("ByteBuf 入参为null");
} else if (in.readableBytes() > 4) {
length = in.readableBytes();
}
else {
throw new BusinessException("报文长度不匹配 ,期望大于4实际" + in.readableBytes());
}
//去掉结束符
byte[] headerBytes = new byte[length - 4];
in.readBytes(headerBytes);
//将数据流转为字符串UTF_8编码
String strData = new String(headerBytes, StandardCharsets.UTF_8);
//以分隔符分割数据
List<String> data = Arrays.asList(strData.split(SurfaceVisionConstants.SEPARATE1, -1));
//获取报文头
vo.setMsgKey(data.get(0));
//去掉报文头
vo.setData(data.subList(1, data.size()));
//判断是否为心跳帧
byte[] header = data.get(0).getBytes(StandardCharsets.UTF_8);
if (header.length == 1 && header[0] == SurfaceVisionConstants.BEAT_BYTE){
vo.setBeatType(true);
}
return vo;
}
/** 非Query命令正常返回消息解码 */
public static void DecodeReturn(SurfaceVisionFrameInputVo vo) {
List<String> data = vo.getData();
if (data.size() < SurfaceVisionConstants.MIN_NORMAL_RETURN){
throw new BusinessException("返回消息不标准msg" + JSON.toJSONString(data));
}
vo.setReplayId(Integer.valueOf(data.get(0)));
vo.setStatus(SurfaceVisionConstants.RETURN_OK.equalsIgnoreCase(data.get(1)));
vo.setDescription(data.get(2));
}
/** 命令异常返回消息解码 */
public static void DecodeReturnError(SurfaceVisionFrameInputVo vo) {
List<String> data = vo.getData();
int size = data.size();
if (size < SurfaceVisionConstants.MIN_NORMAL_RETURN){
throw new BusinessException("返回消息不标准msg" + JSON.toJSONString(data));
}
StringBuffer message = new StringBuffer();
message.append(data.get(size - 1))
.append(":")
.append(data.get(size - 2));
vo.setReplayId(0);
vo.setStatus(false);
vo.setDescription(message.toString());
}
/** Query命令返回消息解码 */
public static void DecodeReturnQuery(SurfaceVisionFrameInputVo vo) {
List<String> data = vo.getData();
int size = data.size();
if (size < 2){
throw new BusinessException("返回查询消息不标准msg" + JSON.toJSONString(data));
}
Map<String, Object> queryData = new HashMap<>();
queryData.put("result", data.get(size - 1));
vo.setReplayId(0);
vo.setStatus(true);
vo.setReturnData(queryData);
}
/** 上送消息解码 */
public static void DecodeData(SurfaceVisionFrameInputVo vo, List<PropertyConfig> propertyConfigs) {
List<String> data = vo.getData();
//判断上送消息字段数是否与点位配置信息字段数一致
if (data.size() != propertyConfigs.size()){
StringBuffer stringBuffer = new StringBuffer();
stringBuffer.append("报文数据字段数与点位配置不一致 ,电文ID")
.append(vo.getMsgKey())
.append(",电文字段数:")
.append(data.size())
.append(", 点位字段数:")
.append(propertyConfigs.size());
throw new BusinessException(stringBuffer.toString());
}
Map<String, Object> valueMap = new HashMap<>();
//按照点位配置字段顺序获取上送信息
for (int i = 0; i < data.size(); i++){
String value = data.get(i);
PropertyConfig propertyConfig = propertyConfigs.get(i);
PropertyType propertyType = propertyConfig.getPropertyType();
String propertyId = propertyConfig.getPropertyId();
formatValue(valueMap, value, propertyType, propertyId);
}
vo.setReturnData(valueMap);
}
/** 更具字段类型格式化数据值 */
private static void formatValue(Map<String, Object> valueMap, String value, PropertyType propertyType, String propertyId) {
switch (propertyType){
case INT: {
valueMap.put(propertyId, Integer.valueOf(value));
break;
}
case BYTE: {
valueMap.put(propertyId, Byte.valueOf(value));
break;
}
case BOOLEAN: {
valueMap.put(propertyId, Boolean.valueOf(value));
break;
}
case SHORT: {
valueMap.put(propertyId, Short.valueOf(value));
break;
}
case FLOAT: {
valueMap.put(propertyId, Float.valueOf(value));
break;
}
case DOUBLE: {
valueMap.put(propertyId, Double.valueOf(value));
break;
}
case LONG: {
valueMap.put(propertyId, Long.valueOf(value));
break;
}
default:{
valueMap.put(propertyId, value);
break;
}
}
}
public static void main(String[] args) throws Exception {
//标签读取
SurfaceVisionFrameDecoder surfaceVisionFrameDecoder = new SurfaceVisionFrameDecoder();
// String str = "DEFECT|1|3|2011-03-19 15:21:45|2.54|1.73|252.76|$\r\n";
//粘包
String str = "DEFECT|1|3|2011-03-19 15:21:45||1.23||$\r\nDEFECT|1|3|2011-03-19 15:21:45||1.23||";
// String str = "DEFECT|1|3|2011-03-19 15:21:45|2.54|1.73|252.76|$\r\n";
byte[] bytes = str.getBytes(StandardCharsets.UTF_8);
ByteBuf copiedBuff = Unpooled.copiedBuffer(bytes);
List<Object> out = new ArrayList<Object>();
surfaceVisionFrameDecoder.decode(null, copiedBuff, out);
ByteBuf bufferIn = (ByteBuf) out.get(0);
SurfaceVisionFrameInputVo vo = Decode(bufferIn);
String msgKey = vo.getMsgKey();
SocketReturnMessage returnMsg = new SocketReturnMessage();
returnMsg.setMsgKey("1");
returnMsg.setMsgId("2");
returnMsg.setData(new byte[3]);
SurfaceVisionSocketReturnMessage sendMsg = new SurfaceVisionSocketReturnMessage();
BeanUtils.copyProperties(returnMsg, sendMsg);
sendMsg.setSendReturnFlag(true);
String msgKey1 = "test";
Map<String, Object> propsMap = new HashMap<>();
propsMap.put("id1", 1);
propsMap.put("id2", 2.33);
propsMap.put("id3", "value");
List<PropertyConfig> propertyConfigList = new ArrayList<>();
PropertyConfig propertyConfig1 = new PropertyConfig();
propertyConfig1.setPropertyId("id1");
propertyConfigList.add(propertyConfig1);
PropertyConfig propertyConfig2 = new PropertyConfig();
propertyConfig2.setPropertyId("id2");
propertyConfigList.add(propertyConfig2);
PropertyConfig propertyConfig3 = new PropertyConfig();
propertyConfig3.setPropertyId("id3");
propertyConfigList.add(propertyConfig3);
int count = 1;
SurfaceVisionEncoder.Encode(msgKey1, propsMap, propertyConfigList, count);
}
}

View File

@ -0,0 +1,354 @@
package com.cisdi.data.DHV;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.cisdi.data.DHV.gateway.vo.dhv.OtherParamVO;
import com.cisdi.data.common.exception.BusinessException;
import com.cisdi.data.sdk.consts.ServiceName;
import com.cisdi.data.sdk.enums.GatewayState;
import com.cisdi.data.sdk.gateway.base.PulledHttpGatewayBase;
import com.cisdi.data.sdk.param.PullHttpParam;
import com.cisdi.data.sdk.procotol.message.HttpReturnMessage;
import com.cisdi.data.sdk.service.RouteService;
import com.cisdi.data.sdk.vo.DeviceVo;
import com.cisdi.data.sdk.vo.ExeResultVo;
import com.cisdi.data.DHV.gateway.impl.dhv.YFDHVPullTask;
import com.cisdi.data.DHV.gateway.vo.PullHttpTaskStartVo;
import com.cisdi.data.DHV.gateway.vo.dhv.MPSVO;
import com.cisdi.data.DHV.gateway.vo.dhv.MPVVO;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.nio.charset.StandardCharsets;
import java.util.*;
import java.util.concurrent.atomic.AtomicBoolean;
/**
* @author jianghc
* @function: YFDHealthVibrationGateway永锋现场-设备健康振动数据接入网关入口
* @date 2022年05月05日 09:29
*/
public class YFDHealthVibrationGateway extends PulledHttpGatewayBase {
private static Logger logger = LoggerFactory.getLogger(YFDHealthVibrationGateway.class);
//设备id
private String deviceId;
//设备当前是否运行
private AtomicBoolean shouldRun = null;
// 允许最小的拉取间隔为1毫秒
private static final int Min_Pull_Internal = 1;
// 允许最小的超时时间间隔为1000毫秒
private static final int Min_Timeout = 1000;
@Override
public ExeResultVo sendReturnMessage(HttpReturnMessage httpReturnMessage) {
return null;
}
@Override
public void start() {
if (state == GatewayState.RUNNING) {
return;
}
try {
startInternal();
state = GatewayState.RUNNING;
logger.info("永峰设备健康振动数据http拉取网关:{}启动成功", instanceVo.getRunId());
} catch (Exception e) {
logger.error("永峰设备健康振动数据http拉取网关:{}启动失败", instanceVo.getRunId());
logger.error(e.getLocalizedMessage(), e);
}
}
private void startInternal() {
httpParam = JSON.parseObject(instanceVo.getParameter(), PullHttpParam.class);
if (StringUtils.isEmpty(httpParam.getPullLocation())) {
throw new BusinessException("未正确配置拉取地址。");
}
if (httpParam.getPullInternal() == null) {
throw new BusinessException("未正确配置拉取间隔");
}
if (httpParam.getTimeout() == null) {
throw new BusinessException("未正确配置拉取超时时间");
}
httpParam.setPullInternal(httpParam.getPullInternal() < Min_Pull_Internal ?
Min_Pull_Internal : httpParam.getPullInternal());
httpParam.setTimeout(httpParam.getTimeout() < Min_Timeout ? Min_Timeout : httpParam.getTimeout());
RouteService routeService = (RouteService) serviceProvider.getByName(ServiceName.Route);
List<DeviceVo> deviceVos = routeService.findByRunId(instanceVo.getRunId());
if (deviceVos.size() > 1) {
throw new BusinessException("网关Id:" + instanceVo.getRunId() + "为永峰设备健康振动数据http拉取网关只允许关联一个设备Id");
}
deviceId = deviceVos.size() > 0 ? deviceVos.get(0).getDeviceId() : null;
logger.info("永峰设备健康振动数据http拉取网关:{}读取启动配置参数:{}", getInstanceVo().getRunId(), httpParam);
closePrevState();
shouldRun = new AtomicBoolean(true);
// DynamicCodecService dynamicCodecService = (DynamicCodecService) serviceProvider.getByName(ServiceName.DynamicCodec);
// if (dynamicCodecService == null || !(dynamicCodecService instanceof DynamicCodecService)) {
// throw new BusinessException("获取JDynamicCodecService失败");
// }
// String tagConfig = dynamicCodecService.findByRunIdAndMsgKeyNoCache(getInstanceVo().getRunId(),"mps.MPS");
// if (Strings.isEmpty(tagConfig)) {
// throw new BusinessException("未正确配置当前DHV所需配置");
// }else{
// logger.info("点位配置信息:"+tagConfig);
// }
// 启动线程
PullHttpTaskStartVo startVo = new PullHttpTaskStartVo();
startVo.setDeviceId(deviceId);
startVo.setGatewayBase(this);
startVo.setServiceProvider(serviceProvider);
startVo.setHttpParam(httpParam);
startVo.setShouldRun(shouldRun);
//其他参数
OtherParamVO otherParamVO = null;
if (httpParam.getOtherParameter() != null && httpParam.getOtherParameter().trim().length() > 0) {
String otherParameter = httpParam.getOtherParameter();
otherParamVO = parseOtherParameter(otherParameter);
} else {
throw new BusinessException("永峰设备健康振动数据Http网关其他参数配置异常!");
}
// 启动拉取ids的线程
YFDHVPullTask idsTask = new YFDHVPullTask(startVo, otherParamVO);
Thread idsThread = new Thread(idsTask, "永峰-设备健康振动数据网关");
idsThread.start();
state = GatewayState.RUNNING;
}
/**
* @param otherParameter
* @return com.cisdi.data.yongfeng.gateway.vo.dhv.OtherParamVO
* @function: 解析其他参数
* @author jianghc
* @date 2022/5/6 16:41
*/
private OtherParamVO parseOtherParameter(String otherParameter) {
MPSVO mpsvo = new MPSVO();
List<MPVVO> mpvvoList = new ArrayList<>();
JSONObject jsonObject = null;
try {
jsonObject = JSONObject.parseObject(otherParameter);
} catch (Exception ex) {
throw new BusinessException("永峰设备健康振动数据Http网关其他参数配置异常!");
}
Object obj = jsonObject.get("mps");
if (obj != null && obj instanceof JSONObject) {
JSONObject databaseName = (JSONObject) obj;
Object dbNames = databaseName.get("databaseName");
if (dbNames instanceof JSONArray) {
JSONArray jsonArray = (JSONArray) dbNames;
List<String> dbNameList = new ArrayList<>();
for (int i = 0; i < jsonArray.size(); i++) {
dbNameList.add((String) jsonArray.get(i));
}
mpsvo.setDatabaseName(dbNameList);
} else if (dbNames instanceof String) {
List<String> dbNameList = new ArrayList<>();
dbNameList.add((String) dbNames);
mpsvo.setDatabaseName(dbNameList);
}
}
Object obj1 = jsonObject.get("mpv");
if (obj1 != null && obj1 instanceof JSONArray) {
JSONArray jsonArray = (JSONArray) obj1;
for (int i = 0; i < jsonArray.size(); i++) {
JSONObject obj2 = (JSONObject) jsonArray.get(i);
MPVVO mpvvo = new MPVVO();
String databaseName = obj2.getString("databaseName");
if (databaseName != null && databaseName.trim().length() > 0) {
mpvvo.setDatabaseName(databaseName);
} else {
mpvvo.setDatabaseName(null);
}
String measuringPointNumberOrTechID = obj2.getString("measuringPointNumberOrTechID");
if (measuringPointNumberOrTechID != null && measuringPointNumberOrTechID.trim().length() > 0) {
mpvvo.setMeasuringPointNumberOrTechID(measuringPointNumberOrTechID);
} else {
if (databaseName != null && databaseName.trim().length() > 0) {
throw new BusinessException("永峰设备健康振动数据Http网关其他参数配置异常!");
}
mpvvo.setMeasuringPointNumberOrTechID(null);
}
String assignmentTechIDorName = obj2.getString("assignmentTechIDorName");
if (assignmentTechIDorName != null && assignmentTechIDorName.trim().length() > 0) {
mpvvo.setAssignmentTechIDorName(assignmentTechIDorName);
} else {
if (databaseName != null && databaseName.trim().length() > 0) {
throw new BusinessException("永峰设备健康振动数据Http网关其他参数配置异常!");
}
mpvvo.setAssignmentTechIDorName(null);
}
Boolean ShortMem = obj2.getBoolean("ShortMem");
if (ShortMem != null && ShortMem.equals(Boolean.TRUE)) {
mpvvo.setShortMem(Boolean.TRUE);
} else if (ShortMem != null && ShortMem.equals(Boolean.FALSE)) {
mpvvo.setShortMem(Boolean.FALSE);
} else {
mpvvo.setShortMem(null);
}
mpvvo.setMaxCount(obj2.getInteger("MaxCount"));
Boolean LongMem = obj2.getBoolean("LongMem");
if (LongMem != null && LongMem.equals(Boolean.TRUE)) {
mpvvo.setLongMem(Boolean.TRUE);
} else if (LongMem != null && LongMem.equals(Boolean.FALSE)) {
mpvvo.setLongMem(Boolean.FALSE);
} else {
mpvvo.setLongMem(null);
}
String StartDateTime = obj2.getString("StartDateTime");
if (StartDateTime != null && StartDateTime.trim().length() > 0) {
mpvvo.setStartDateTime(StartDateTime);
} else {
mpvvo.setStartDateTime(null);
}
String StopDateTime = obj2.getString("StopDateTime");
if (StopDateTime != null && StopDateTime.trim().length() > 0) {
mpvvo.setStopDateTime(StopDateTime);
} else {
mpvvo.setStopDateTime(null);
}
mpvvo.setMpktTech(obj2.getInteger("MpktTech"));
String Expand = obj2.getString("Expand");
if (Expand != null && Expand.trim().length() > 0) {
mpvvo.setExpand(Expand);
} else {
mpvvo.setExpand(null);
}
mpvvoList.add(mpvvo);
}
} else if (obj1 != null && obj1 instanceof JSONObject) {
JSONObject obj2 = (JSONObject) obj1;
MPVVO mpvvo = new MPVVO();
String databaseName = obj2.getString("databaseName");
if (databaseName != null && databaseName.trim().length() > 0) {
mpvvo.setDatabaseName(databaseName);
} else {
mpvvo.setDatabaseName(null);
}
String measuringPointNumberOrTechID = obj2.getString("measuringPointNumberOrTechID");
if (measuringPointNumberOrTechID != null && measuringPointNumberOrTechID.trim().length() > 0) {
mpvvo.setMeasuringPointNumberOrTechID(measuringPointNumberOrTechID);
} else {
if (databaseName != null && databaseName.trim().length() > 0) {
throw new BusinessException("永峰设备健康振动数据Http网关其他参数配置异常!");
}
mpvvo.setMeasuringPointNumberOrTechID(null);
}
String assignmentTechIDorName = obj2.getString("assignmentTechIDorName");
if (assignmentTechIDorName != null && assignmentTechIDorName.trim().length() > 0) {
mpvvo.setAssignmentTechIDorName(assignmentTechIDorName);
} else {
if (databaseName != null && databaseName.trim().length() > 0) {
throw new BusinessException("永峰设备健康振动数据Http网关其他参数配置异常!");
}
mpvvo.setAssignmentTechIDorName(null);
}
Boolean ShortMem = obj2.getBoolean("ShortMem");
if (ShortMem != null && ShortMem.equals(Boolean.TRUE)) {
mpvvo.setShortMem(Boolean.TRUE);
} else if (ShortMem != null && ShortMem.equals(Boolean.FALSE)) {
mpvvo.setShortMem(Boolean.FALSE);
} else {
mpvvo.setShortMem(null);
}
mpvvo.setMaxCount(obj2.getInteger("MaxCount"));
Boolean LongMem = obj2.getBoolean("LongMem");
if (LongMem != null && LongMem.equals(Boolean.TRUE)) {
mpvvo.setLongMem(Boolean.TRUE);
} else if (LongMem != null && LongMem.equals(Boolean.FALSE)) {
mpvvo.setLongMem(Boolean.FALSE);
} else {
mpvvo.setLongMem(null);
}
String StartDateTime = obj2.getString("StartDateTime");
if (StartDateTime != null && StartDateTime.trim().length() > 0) {
mpvvo.setStartDateTime(StartDateTime);
} else {
mpvvo.setStartDateTime(null);
}
String StopDateTime = obj2.getString("StopDateTime");
if (StopDateTime != null && StopDateTime.trim().length() > 0) {
mpvvo.setStopDateTime(StopDateTime);
} else {
mpvvo.setStopDateTime(null);
}
mpvvo.setMpktTech(obj2.getInteger("MpktTech"));
String Expand = obj2.getString("Expand");
if (Expand != null && Expand.trim().length() > 0) {
mpvvo.setExpand(Expand);
} else {
mpvvo.setExpand(null);
}
mpvvoList.add(mpvvo);
}
if ((mpsvo.getDatabaseName() == null || mpsvo.getDatabaseName().size() < 1) && (mpvvoList.size() < 1)) {
throw new BusinessException("永峰设备健康振动数据Http网关其他参数配置异常!");
}
String user = jsonObject.getString("user");
String pass = jsonObject.getString("pass");
String Authorization = null;
if (user != null) {
Authorization = "Basic " + new String(Base64.getEncoder().encode((user + ":" + pass).getBytes(StandardCharsets.UTF_8)));
} else {
Authorization = "Basic ";
}
String emptyanddefault = jsonObject.getString("emptyanddefault");
OtherParamVO otherParamVO = new OtherParamVO();
otherParamVO.setMpsvo(mpsvo);
otherParamVO.setMpvvoList(mpvvoList);
otherParamVO.setAuthorization(Authorization);
otherParamVO.setEmptyanddefault(emptyanddefault);
return otherParamVO;
}
@Override
public void shutdown() {
if (state == GatewayState.CLOSED) {
return;
}
closePrevState();
logger.info("永峰设备健康振动数据http拉取网关:{}关闭中", getInstanceVo().getRunId());
state = GatewayState.CLOSED;
logger.info("永峰设备健康振动数据http拉取网关:{}关闭成功", getInstanceVo().getRunId());
}
private void closePrevState() {
if (shouldRun != null) {
shouldRun.set(false);
shouldRun = null;
}
}
@Override
public Set<String> getActiveDeviceIds() {
Set<String> set = new HashSet<String>();
if (deviceId != null) {
set.add(deviceId);
}
return set;
}
}

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,42 @@
package com.cisdi.data.DHV.gateway.config;
import com.google.common.collect.Maps;
import okhttp3.ConnectionPool;
import okhttp3.OkHttpClient;
import java.util.Map;
import java.util.concurrent.TimeUnit;
/**
* @author jianghc
* @function:
* @date 2022年05月07日 10:26
*/
public class YFHttpClient {
private static Map<Integer, OkHttpClient> map = Maps.newConcurrentMap();
public static OkHttpClient get(Integer timeout) {
OkHttpClient okHttpClient = map.get(timeout);
if(okHttpClient != null) {
return okHttpClient;
}
OkHttpClient.Builder builder = new OkHttpClient.Builder();
builder.connectTimeout(timeout, TimeUnit.MILLISECONDS)
.readTimeout(timeout, TimeUnit.MILLISECONDS)
.writeTimeout(timeout,TimeUnit.MILLISECONDS)
.connectionPool(new ConnectionPool(15, 1, TimeUnit.MINUTES))
.retryOnConnectionFailure(true);
okHttpClient = builder.build();
map.put(timeout, okHttpClient);
return okHttpClient;
}
}

View File

@ -0,0 +1,26 @@
package com.cisdi.data.DHV.gateway.impl;
import com.cisdi.data.DHV.gateway.vo.dhv.OtherParamVO;
import com.cisdi.data.common.exception.BusinessException;
import com.cisdi.data.DHV.gateway.vo.PullHttpTaskStartVo;
/**
* @author jianghc
* @function:
* @date 2022年05月05日 09:37
*/
public class HttpPullTaskBase {
/**
* 线程启动参数
*/
protected PullHttpTaskStartVo startVo = null;
protected void checkInitParam(PullHttpTaskStartVo taskStartVo, OtherParamVO otherParamVO) {
if(taskStartVo.getShouldRun() == null
|| taskStartVo.getShouldRun() == null
|| taskStartVo.getHttpParam() == null) {
throw new BusinessException("永峰设备健康振动数据Http拉取线程启动参数缺失。");
}
this.startVo = taskStartVo;
}
}

View File

@ -0,0 +1,575 @@
package com.cisdi.data.DHV.gateway.impl.dhv;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.cisdi.data.DHV.gateway.config.YFHttpClient;
import com.cisdi.data.DHV.gateway.impl.HttpPullTaskBase;
import com.cisdi.data.DHV.gateway.vo.PullHttpTaskStartVo;
import com.cisdi.data.DHV.gateway.vo.dhv.*;
import com.cisdi.data.common.exception.BusinessException;
import com.cisdi.data.sdk.consts.ServiceName;
import com.cisdi.data.sdk.gateway.base.PulledHttpGatewayBase;
import com.cisdi.data.sdk.gateway.message.HttpMessage;
import com.cisdi.data.sdk.gateway.message.Message;
import com.cisdi.data.sdk.gateway.message.MessageBatch;
import com.cisdi.data.sdk.service.SendService;
import com.cisdi.data.sdk.service.ServiceProvider;
import okhttp3.OkHttpClient;
import okhttp3.Response;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.io.IOException;
import java.nio.charset.StandardCharsets;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.*;
/**
* @author jianghc
* @function:
* @date 2022年05月05日 10:32
*/
public class YFDHVPullTask extends HttpPullTaskBase implements Runnable {
private Logger logger = LoggerFactory.getLogger(YFDHVPullTask.class);
//请求测点状态的URL地址
private String[] DHV_MPS_URL = null;
//获取teachName的URL地址
private String[] DHV_MET_URL = null;
//请求测点总值的URL地址
private String[] DHV_MPV_URL = null;
//测点的ID
private String[] measuringPointNumberOrTechIDs = null;
//base64编码的user:password
private String Authorization;
//DHV请求必须携带的头部参数
private String emptyanddefault;
//超时时间
private Integer timeOut;
//其他参数中配置的数据库
private List<String> dbNames;
//判断当前是否获取了db-测点id-测点方法的一个标志在网关启动的时候执行一次后变成true并装入下面三个容器中
private boolean metPara = false;
private List<String> dbNameList;
private List<String> itemIdList;
private List<String> methodNameList;
//连接管理中的拉取地址以上所有的URL地址都是用这个地址为前缀拼接成的
private String url;
public YFDHVPullTask(PullHttpTaskStartVo pullHttpTaskStartVo, OtherParamVO otherParamVO) {
checkInitParam(pullHttpTaskStartVo, otherParamVO);
url = startVo.getHttpParam().getPullLocation();
if (url == null) {
logger.error("拉取地址不能为空!");
throw new BusinessException("拉取地址不能为空!");
}
if (url.endsWith("/")) {
url = url.substring(0, url.length() - 1);
}
dbNames = otherParamVO.getMpsvo().getDatabaseName();
int dbNamesLen = dbNames.size();
if (dbNamesLen > 0) {
DHV_MPS_URL = new String[dbNamesLen];
for (int i = 0; i < dbNamesLen; i++) {
DHV_MPS_URL[i] = url + String.format(YFDHV.YF_DHV_MPS, dbNames.get(i));
}
}
Authorization = otherParamVO.getAuthorization();
emptyanddefault = otherParamVO.getEmptyanddefault() == null ? "1" : otherParamVO.getEmptyanddefault();
timeOut = startVo.getHttpParam().getTimeout();
}
@Override
public void run() {
OkHttpClient httpClient = YFHttpClient.get(startVo.getHttpParam().getPullInternal());
if (DHV_MPS_URL != null) {
for (int i = 0; i < DHV_MPS_URL.length; i++) {
logger.info("MPS采集地址" + DHV_MPS_URL[i]);
}
} else {
logger.info("您尚未配置采集地址");
}
//在这个驱动中我们只请求如下时间范围的数据从当前时间往前数半个小时第一次请求这样
//以后每个半个小时请求一次每次的请求时间范围是上一次的请求时间到当前时间点通常会比半个小时多一点点
//多出来的时间是上一次请求的耗时时间
LocalDateTime endTime = null;
LocalDateTime startTime = null;
while (startVo.getShouldRun().get() == true) {
logger.info("即将采集设备数据......");
LocalDateTime end_time_temp = null;
if (endTime != null) {
end_time_temp = endTime;
}
endTime = LocalDateTime.now();
if (startTime == null) {
startTime = endTime.minusMinutes(30);
} else {
startTime = end_time_temp;
}
Map<String, String> mpsJsonStringMap = MPSRequest(httpClient);
if (DHV_MET_URL == null) {
Construct_DHV_MET_URL();
}
if (DHV_MPV_URL == null) {
METRequest(httpClient);
}
Map<String, JSONObject> mpvJsonArrayMap = MPVRequest(httpClient, startTime, endTime);
if (mpsJsonStringMap != null && mpsJsonStringMap.size() > 0) {
for (int i = 0; i < mpsJsonStringMap.size(); i++) {
String msgKey = dbNames.get(i) + YFDHV.YF_Separator + YFDHV.YF_MPS;
sendToNextMQ(mpsJsonStringMap.get(dbNames.get(i)), msgKey);
}
}
if (mpvJsonArrayMap != null && mpvJsonArrayMap.size() > 0) {
List<String> dbNameList = new ArrayList<>(mpvJsonArrayMap.keySet());
for (int i = 0; i < dbNameList.size(); i++) {
String dbName = dbNameList.get(i);
sendToNextMQ(mpvJsonArrayMap.get(dbName).toJSONString(), dbName);
}
}
try {
Thread.sleep(startVo.getHttpParam().getPullInternal());
} catch (InterruptedException e) {
logger.error("休眠异常");
throw new BusinessException("休眠异常");
}
}
}
/**
* @param httpClient
* @return java.lang.String
* @function: 终极奥义之通过DHV_MPS_URL地址获取测点状态信息
* @author jianghc
* @date 2022/5/24 16:16
*/
private Map<String, String> MPSRequest(OkHttpClient httpClient) {
if (!metPara) {
dbNameList = new ArrayList<>();
itemIdList = new ArrayList<>();
}
if (DHV_MPS_URL == null) {
return null;
}
Map<String, String> mpsJsonMap = new HashMap<>();
int DHV_MPS_URL_Len = DHV_MPS_URL.length;
for (int i = 0; i < DHV_MPS_URL_Len; i++) {
okhttp3.Request request = new okhttp3.Request.Builder()
.header("Authorization", Authorization)
.header("emptyanddefault", emptyanddefault)
.url(DHV_MPS_URL[i])
.get()
.build();
Response response = null;
try {
Long currentTime_start = System.currentTimeMillis();
Long currentTime_end = 0l;
response = httpClient.newCall(request).execute();
currentTime_end = System.currentTimeMillis();
if (currentTime_end - currentTime_start > timeOut) {
logger.error("地址:" + DHV_MPS_URL[i] + "请求超时!");
throw new BusinessException("地址:" + DHV_MPS_URL[i] + "请求超时!");
}
} catch (Exception e) {
logger.error("被请求的接口:" + DHV_MPS_URL[i] + "请求超时," + e.getMessage());
throw new BusinessException("被请求的接口:" + DHV_MPS_URL[i] + "请求超时," + e.getMessage());
}
if (response.isSuccessful()) {
String jsonString = null;
try {
jsonString = new String(response.body().bytes(), StandardCharsets.UTF_8);
} catch (Exception ex) {
logger.error("MPS响应数据解析异常");
throw new BusinessException("MPS响应数据解析异常");
}
Object jsonArrayObject = ((JSONObject) JSONObject.parse(jsonString)).get("values");
JSONObject resJson = new JSONObject();
if (jsonArrayObject instanceof JSONArray) {
JSONArray jsonArray = (JSONArray) jsonArrayObject;
for (int j = 0; j < jsonArray.size(); j++) {
JSONObject jsonObject = (JSONObject) jsonArray.get(j);
MPSItem[] mpsItems = MPSItem.values();
MPSItem primary = MPSItem.getPrimary();
Object primaryValue = jsonObject.get(primary.toString());
String mp = jsonObject.getString(MPSItem.getPrimary().getMpsItem());
if (!AllowMeasuringPoint.allowMeasuringPoint(mp)) {
continue;
}
for (MPSItem mpsItem : mpsItems) {
String key = dbNames.get(i) + YFDHV.YF_Separator + primaryValue + YFDHV.YF_Separator + mpsItem.getMpsItem();
Object value = jsonObject.get(mpsItem.toString());
resJson.fluentPut(key, value);
}
resJson.fluentPut(dbNames.get(i) + YFDHV.YF_Separator + primaryValue + YFDHV.YF_Separator + YFDHV.DateTime
, LocalDateTime.now());//注意测点状态时间是系统生成的没有从接口中获取到
if (!metPara) {
String mpx = jsonObject.getString(MPSItem.getPrimary().getMpsItem());
if (!AllowMeasuringPoint.allowMeasuringPoint(mpx)) {
continue;
}
dbNameList.add(dbNames.get(i));
itemIdList.add(mpx);
}
}
} else {
logger.warn("地址:" + DHV_MPS_URL[i] + " 未采集到数据!");
}
if (resJson.size() > 0) {
mpsJsonMap.put(dbNames.get(i), resJson.toJSONString());
}
}
}
if (!metPara) {
StringBuilder stringBuffer = new StringBuilder("\n");
stringBuffer.append("测点状态采集点信息:\n");
stringBuffer.append("=======================================================================================\n");
for (int i = 0; i < dbNameList.size(); i++) {
stringBuffer.append("数据库:" + dbNameList.get(i) + " 测点状态id:" + itemIdList.get(i) + "\n");
}
stringBuffer.append("=======================================================================================\n");
logger.info(stringBuffer.toString());
metPara = true;
}
if (mpsJsonMap.size() > 0) {
return mpsJsonMap;
} else {
return null;
}
}
/**
* @function: 构造DHV_MET_URL的请求地址
* @author jianghc
* @date 2022/5/24 16:12
*/
private void Construct_DHV_MET_URL() {
if (itemIdList == null || itemIdList.size() == 0) {
return;
}
int itemIdList_len = itemIdList.size();
DHV_MET_URL = new String[itemIdList_len];
for (int i = 0; i < itemIdList.size(); i++) {
String measuringPointNumberOrTechID = itemIdList.get(i);
if (measuringPointNumberOrTechID.contains("#")) {
measuringPointNumberOrTechID = measuringPointNumberOrTechID.replace("#", "%23");
}
DHV_MET_URL[i] = url + String.format(YFDHV.YF_DHV_METH, dbNameList.get(i), measuringPointNumberOrTechID);
}
StringBuilder stringBuffer = new StringBuilder("\n");
stringBuffer.append("获取测点总值需要的方法请求路径包含:\n");
stringBuffer.append("=======================================================================================\n");
for (int i = 0; i < DHV_MET_URL.length; i++) {
stringBuffer.append(DHV_MET_URL[i] + "\n");
}
stringBuffer.append("=======================================================================================\n");
logger.info(stringBuffer.toString());
}
/**
* @param httpClient
* @function: 主要要来获取dbNameListitemIdListmethodNameList
* @author jianghc
* @date 2022/5/24 16:12
*/
private void METRequest(OkHttpClient httpClient) {
List<String> dbNameList_temp = new ArrayList<>();
List<String> itemIdList_temp = new ArrayList<>();
if (DHV_MET_URL == null) {
return;
}
methodNameList = new ArrayList<>();
int DHV_MET_URL_len = DHV_MET_URL.length;
for (int i = 0; i < DHV_MET_URL_len; i++) {
okhttp3.Request request = new okhttp3.Request.Builder()
.header("Authorization", Authorization)
.header("emptyanddefault", emptyanddefault)
.url(DHV_MET_URL[i])
.get()
.build();
Response response = null;
try {
response = httpClient.newCall(request).execute();
} catch (IOException ex) {
throw new BusinessException("接口:" + DHV_MET_URL[i] + "请求失败!");
}
if (response != null && response.isSuccessful()) {
String jsonString = null;
try {
jsonString = new String(response.body().bytes(), StandardCharsets.UTF_8);
} catch (Exception ex) {
logger.error("MPS响应数据解析异常");
throw new BusinessException("MPS响应数据解析异常");
}
JSONObject jsonObject = (JSONObject) JSONObject.parse(jsonString);
JSONArray jsonArray = (JSONArray) jsonObject.get("values");
if (jsonArray != null && jsonArray.size() > 0) {
for (int j = 0; j < jsonArray.size(); j++) {
JSONObject jsonObject_val = (JSONObject) jsonArray.get(j);
String TechName = jsonObject_val.getString("TechName");
if (!AllowMethod.allowMethod(TechName)) {
logger.info(TechName + "方法不匹配");
continue;
}
dbNameList_temp.add(dbNameList.get(i));
itemIdList_temp.add(itemIdList.get(i));
methodNameList.add(TechName);
}
}
}
}
dbNameList = null;
dbNameList = dbNameList_temp;
itemIdList = null;
itemIdList = itemIdList_temp;
StringBuilder stringBuilder = new StringBuilder("\n");
measuringPointNumberOrTechIDs = new String[dbNameList.size()];
stringBuilder.append("测点总值需要的参数:\n");
stringBuilder.append("=======================================================================================\n");
for (int i = 0; i < dbNameList.size(); i++) {
measuringPointNumberOrTechIDs[i] = dbNameList.get(i) + YFDHV.YF_Separator + itemIdList.get(i) + YFDHV.YF_Separator + methodNameList.get(i);
stringBuilder.append("数据库:" + dbNameList.get(i)
+ " 测点总值id:" + itemIdList.get(i)
+ " 方法:" + methodNameList.get(i) + "\n");
}
stringBuilder.append("=======================================================================================\n");
logger.info(stringBuilder.toString());
Construct_DHV_MPV_URL();
}
/**
* @function: 构造DHV_MPV_URL的请求地址
* @author jianghc
* @date 2022/5/24 16:14
*/
private void Construct_DHV_MPV_URL() {
if (methodNameList == null) {
return;
}
int methodNameList_len = methodNameList.size();
DHV_MPV_URL = new String[methodNameList_len];
for (int i = 0; i < methodNameList_len; i++) {
String measuringPointNumberOrTechID = itemIdList.get(i);
if (measuringPointNumberOrTechID.contains("#")) {
measuringPointNumberOrTechID = measuringPointNumberOrTechID.replace("#", "%23");
}
DHV_MPV_URL[i] = url + String.format(YFDHV.YF_DHV_MPV, dbNameList.get(i), measuringPointNumberOrTechID, methodNameList.get(i));
DHV_MPV_URL[i] += "?ShortMem=true&LongMem=true&Expand=result";
}
StringBuilder stringBuilder = new StringBuilder("\n");
stringBuilder.append("测点总值请求路径(该请求路径不含时间参数 &StartDateTime &StopDateTime :\n");
stringBuilder.append("=======================================================================================\n");
for (int i = 0; i < DHV_MPV_URL.length; i++) {
stringBuilder.append(DHV_MPV_URL[i] + "\n");
}
stringBuilder.append("=======================================================================================\n");
logger.info(stringBuilder.toString());
}
/**
* @param httpClient
* @param start
* @param end
* @return Map<String, JSONArray>
* @function: 终极奥义之通过DHV_MPV_URL信息获取测点总值信息
* @author jianghc
* @date 2022/5/24 16:14
*/
private Map<String, JSONObject> MPVRequest(OkHttpClient httpClient, LocalDateTime start, LocalDateTime end) {
String startTime = start.format(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss"));
String endTime = end.format(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss"));
if (DHV_MPV_URL == null) {
return null;
}
int DHV_MPV_URL_Len = DHV_MPV_URL.length;
Map<String, JSONObject> jsonArrayResObj = new HashMap<>();
JSONObject resJson = null;
for (int i = 0; i < DHV_MPV_URL_Len; i++) {
String msgKey = dbNameList.get(i) + YFDHV.YF_Separator + itemIdList.get(i) + YFDHV.YF_Separator + YFDHV.YF_MPV;
resJson = jsonArrayResObj.get(msgKey);
if (resJson == null) {
resJson = new JSONObject();
}
okhttp3.Request request = new okhttp3.Request.Builder()
.header("Authorization", Authorization)
.header("emptyanddefault", emptyanddefault)
//.url(DHV_MPV_URL[i] + "&StartDateTime=2020-01-01 00:00:01" + "&StopDateTime=" + endTime)
.url(DHV_MPV_URL[i] + "&StartDateTime=" + startTime + "&StopDateTime=" + endTime)
.get()
.build();
Response response = null;
try {
Long currentTime_start = System.currentTimeMillis();
Long currentTime_end = 0l;
response = httpClient.newCall(request).execute();
currentTime_end = System.currentTimeMillis();
if (currentTime_end - currentTime_start > timeOut) {
logger.error("地址:" + DHV_MPV_URL[i] + "请求超时!");
throw new BusinessException("地址:" + DHV_MPV_URL[i] + "请求超时!");
}
} catch (Exception e) {
logger.error("地址:" + DHV_MPV_URL[i] + "请求超时!" + e.getMessage());
throw new BusinessException("地址:" + DHV_MPV_URL[i] + "请求超时!");
}
MPVItem[] mpvItems = MPVItem.values();
if (response.isSuccessful()) {
MPVItem primary = MPVItem.getPrimary();
String primary_value = measuringPointNumberOrTechIDs[i];
String jsonString = null;
try {
jsonString = new String(response.body().bytes(), StandardCharsets.UTF_8);
} catch (Exception ex) {
logger.error("MPV响应数据解析异常");
throw new BusinessException("MPV响应数据解析异常");
}
Object jsonObject_temp = JSONObject.parse(jsonString);
if (jsonObject_temp instanceof JSONObject) {
JSONObject jsonObject = (JSONObject) jsonObject_temp;
Object jsonArrayObject = jsonObject.get("values");
if (jsonArrayObject != null && jsonArrayObject instanceof JSONArray) {
JSONArray jsonArray = (JSONArray) jsonArrayObject;
for (int j = 0; j < jsonArray.size(); j++) {
Object obj = jsonArray.get(j);
if (j >= 2) {
logger.error("拉取数据过多,请缩短采集时间间隔!");
logger.error("多余数据将不被采集:" + ((JSONObject) obj).toJSONString());
continue;
}
if (obj != null && obj instanceof JSONObject) {
JSONObject jsonObject_value = (JSONObject) obj;
Object obj_Result = jsonObject_value.get("Result");
if (obj_Result != null && obj_Result instanceof JSONObject) {
JSONObject jsonObject_Result = (JSONObject) obj_Result;
//primary_value=数据库.测点.方法
//key-value
//key:数据库.测点.方法.属性
//value:测点
resJson.fluentPut(primary_value + YFDHV.YF_Separator + primary.getMpvItem(),
primary_value.split(YFDHV.YF_EscapeCharacter + YFDHV.YF_Separator)[1]);
Object RPM = jsonObject_Result.get("RPM");
if (RPM != null && RPM instanceof JSONObject) {
JSONObject rpmObj = (JSONObject) RPM;
MPVRPMItem[] mpvrpmItems = MPVRPMItem.values();
for (MPVRPMItem mpvrpmItem : mpvrpmItems) {
String key = primary_value + YFDHV.YF_Separator + mpvrpmItem.getMpvRPMItem();
String value = rpmObj.getString(mpvrpmItem.getMpvRPMItem());
//key-value
//key:数据库.测点.方法.属性
//value:属性值
resJson.fluentPut(key, value);
}
}
//String DateTime_key = primary_value + YFDHV.YF_Separator + MPVItem.DateTime.getMpvItem();
//String DateTime_value = jsonObject_Result.get(MPVItem.DateTime.toString()).toString();
//key-value
//key:数据库.测点.方法.属性
//value:属性值
//resJson.fluentPut(DateTime_key, DateTime_value);
Object obj_Conditions = jsonObject_Result.get("Conditions");
if (obj_Conditions != null && obj_Conditions instanceof JSONObject) {
JSONObject jsonObject_Conditions = (JSONObject) obj_Conditions;
for (MPVItem mpvItem : mpvItems) {
String key = primary_value + YFDHV.YF_Separator + mpvItem.getMpvItem();
Object value = null;
try {
value = jsonObject_Conditions.get(mpvItem.toString());
} catch (Exception ex) {
logger.error("永峰设备健康振动数据Http网关response解析异常");
throw new BusinessException("永峰设备健康振动数据Http网关response解析异常");
}
if (value != null) {
//key-value
//key:数据库.测点.方法.属性
//value:属性值
resJson.fluentPut(key, value);
}
}
}
}
}
}
}
}
}
if (resJson != null && resJson.size() > 0) {
jsonArrayResObj.put(msgKey, resJson);
}
}
if (jsonArrayResObj.size() > 0) {
return jsonArrayResObj;
} else {
return null;
}
}
/**
* @param body
* @param msgKey
* @function: 将数据发送到平台
* @author jianghc
* @date 2022/5/24 16:15
*/
private void sendToNextMQ(Object body, String msgKey) {
ServiceProvider serviceProvider = startVo.getServiceProvider();
PulledHttpGatewayBase gatewayBase = startVo.getGatewayBase();
if (serviceProvider != null && gatewayBase != null && body instanceof String) {
SendService service = (SendService) serviceProvider.getByName(ServiceName.Send);
Message message = null;
HttpMessage httpMessage = gatewayBase.buildHttpMessage();
httpMessage.setDeviceId(startVo.getDeviceId());
httpMessage.setProviderCode(null);
httpMessage.setBody((String) body);
httpMessage.setMsgKey(msgKey);
message = httpMessage;
service.sendMessage(message);
} else if (serviceProvider != null && gatewayBase != null && body instanceof JSONArray) {
SendService service = (SendService) serviceProvider.getByName(ServiceName.Send);
Message message;
JSONArray sendBody = (JSONArray) body;
List<Message> httpMessages = new ArrayList(sendBody.size());
for (Object obj : sendBody) {
HttpMessage httpMessage = gatewayBase.buildHttpMessage();
httpMessage.setDeviceId(startVo.getDeviceId());
httpMessage.setProviderCode(null);
httpMessage.setBody(obj.toString());
httpMessage.setMsgKey(msgKey);
httpMessages.add(httpMessage);
}
MessageBatch<Message> batch = new MessageBatch<>(httpMessages);
message = batch;
service.sendMessage(message);
} else {
logger.info("连接id-{} 拉取采集到值-{}", gatewayBase.getInstanceVo().getRunId(), body);
}
}
}

View File

@ -0,0 +1,55 @@
package com.cisdi.data.DHV.gateway.vo;
import com.cisdi.data.sdk.gateway.base.PulledHttpGatewayBase;
import com.cisdi.data.sdk.param.PullHttpParam;
import com.cisdi.data.sdk.service.ServiceProvider;
import java.util.concurrent.atomic.AtomicBoolean;
public class PullHttpTaskStartVo {
private AtomicBoolean shouldRun;
private ServiceProvider serviceProvider;
private String deviceId;
private PulledHttpGatewayBase gatewayBase;
private PullHttpParam httpParam;
public AtomicBoolean getShouldRun() {
return shouldRun;
}
public void setShouldRun(AtomicBoolean shouldRun) {
this.shouldRun = shouldRun;
}
public ServiceProvider getServiceProvider() {
return serviceProvider;
}
public void setServiceProvider(ServiceProvider serviceProvider) {
this.serviceProvider = serviceProvider;
}
public String getDeviceId() {
return deviceId;
}
public void setDeviceId(String deviceId) {
this.deviceId = deviceId;
}
public PulledHttpGatewayBase getGatewayBase() {
return gatewayBase;
}
public void setGatewayBase(PulledHttpGatewayBase gatewayBase) {
this.gatewayBase = gatewayBase;
}
public PullHttpParam getHttpParam() {
return httpParam;
}
public void setHttpParam(PullHttpParam httpParam) {
this.httpParam = httpParam;
}
}

View File

@ -0,0 +1,33 @@
package com.cisdi.data.DHV.gateway.vo.dhv;
public enum AllowMeasuringPoint {
//1#XB-10V -02,符合规则的测点
RegularExpression1("^([\\s]*)([0-9]+)[#]([A-Z]+)([\\s]*)[-]([\\s]*)([0-9]+)([A-Z]+)([\\s]*)([\\s]*)[-]([\\s]*)([0-9]+)([\\s]*)$"),
//1#XB-ZG1 -05,符合规则的测点
RegularExpression2("^([\\s]*)([0-9]+)[#]([A-Z]+)([\\s]*)[-]([\\s]*)([A-Z]+)([0-9]+)([\\s]*)([\\s]*)[-]([\\s]*)([0-9]+)([\\s]*)$"),
//2#XB-1#GF-05,符合规则的测点
RegularExpression3("^([\\s]*)([0-9]+)[#]([A-Z]+)([\\s]*)[-]([\\s]*)([0-9]+)[#]([A-Z]+)([\\s]*)([\\s]*)[-]([\\s]*)([0-9]+)([\\s]*)$");
private String reg;
AllowMeasuringPoint(String reg) {
this.reg = reg;
}
private String getReg() {
return this.reg;
}
public static boolean allowMeasuringPoint(String mp) {
if (mp == null) {
return true;
}
AllowMeasuringPoint[] allowMeasuringPoints = AllowMeasuringPoint.values();
for (int i = 0; i < allowMeasuringPoints.length; i++) {
if (mp.matches(allowMeasuringPoints[i].getReg())) {
return true;
}
}
return false;
}
}

View File

@ -0,0 +1,40 @@
package com.cisdi.data.DHV.gateway.vo.dhv;
public enum AllowMethod {
// tam1("SPM HD"),
// tam2("HD ENV"),
// tam3("振动低频"),
// tam4("振动高频"),
am1("冲击脉冲频谱"),
am2("振动速度谱"),
am3("冲击脉冲"),
am4("振动速度"),
am5("冲击脉冲谱"),
am6("冲激脉冲频谱"),
am7("振动速度普");
private String method;
AllowMethod(String method) {
this.method = method;
}
private String getMethod(){
return this.method;
}
public static boolean allowMethod(String am) {
if (am == null) {
return false;
}
AllowMethod[] allowMethods=AllowMethod.values();
for (int i=0;i<allowMethods.length;i++) {
if (am.contains(allowMethods[i].getMethod())){
return true;
}
}
return false;
}
}

View File

@ -0,0 +1,23 @@
package com.cisdi.data.DHV.gateway.vo.dhv;
public enum MPSItem {
Number("Number"),
ColorEval("ColorEval");
//DateTime("DateTime");注意测点状态时间是系统生成的没有从接口中获取到
private String mpsItem;
MPSItem(String mpsItem) {
this.mpsItem=mpsItem;
}
public String getMpsItem(){
return mpsItem;
}
public static MPSItem getPrimary() {
return Number;
}
}

View File

@ -0,0 +1,26 @@
package com.cisdi.data.DHV.gateway.vo.dhv;
import java.io.Serializable;
import java.util.List;
/**
* @author jianghc
* @function:
* @date 2022年05月06日 16:23
*/
public class MPSVO implements Serializable {
List<String> databaseName;
public MPSVO(){
}
public List<String> getDatabaseName() {
return databaseName;
}
public void setDatabaseName(List<String> databaseName) {
this.databaseName = databaseName;
}
}

View File

@ -0,0 +1,27 @@
package com.cisdi.data.DHV.gateway.vo.dhv;
public enum MPVItem {
measuringPointNumberOrTechID("measuringPointNumberOrTechID"),
// DateTime("DateTime"),
HDm("HDm"),
HDc("HDc");
// VEL("VEL"),
// DISP("DISP"),
// ACC("ACC"),
// Peak("Peak"),
// PkToPk("PkToPk");
private String mpvItem;
MPVItem(String mpvItem) {
this.mpvItem = mpvItem;
}
public String getMpvItem() {
return this.mpvItem;
}
public static MPVItem getPrimary() {
return measuringPointNumberOrTechID;
}
}

View File

@ -0,0 +1,20 @@
package com.cisdi.data.DHV.gateway.vo.dhv;
public enum MPVRPMItem {
// RPM1("RPM1"),
// RPM2("RPM2"),
// Avg("Avg"),
// Min("Min"),
Max("Max");
// Delta("Delta");
MPVRPMItem(String mpvRPMItem) {
this.mpvRPMItem = mpvRPMItem;
}
private String mpvRPMItem;
public String getMpvRPMItem() {
return this.mpvRPMItem;
}
}

View File

@ -0,0 +1,147 @@
package com.cisdi.data.DHV.gateway.vo.dhv;
import java.io.Serializable;
import java.util.Date;
/**
* @author jianghc
* @function:
* @date 2022年05月06日 16:25
*/
public class MPVVO implements Serializable {
private String databaseName;
private String measuringPointNumberOrTechID;
private String assignmentTechIDorName;
private Boolean shortMem;
private Boolean longMem;
private Integer maxCount;
private String startDateTime;
private String stopDateTime;
private Integer mpktTech;
private String expand;
public String getParameter() {
String para = "?placeholder=placeholder";//该参数无意义用作占位符方便后面拼接url统一 &xxx=yyy
if (shortMem != null) {
para = para + ("&ShortMem=" + shortMem);
} else {
para = para + ("&ShortMem=" + true);
}
if (longMem != null) {
para = para + ("&LongMem=" + longMem);
} else {
para = para + ("&LongMem=" + true);
}
if (maxCount != null) {
para = para + ("&MaxCount=" + maxCount);
}
// if (startDateTime != null) {
// para = para + ("&StartDateTime=" + startDateTime);
//
// }
// if (stopDateTime != null) {
// para = para + ("&StartDateTime=" + startDateTime);
// }
if (mpktTech != null) {
para = para + ("&MpktTech=" + mpktTech);
}
if (expand != null) {
para = para + ("&Expand=" + expand);
}
return para;
}
public MPVVO() {
}
public String getDatabaseName() {
return databaseName;
}
public void setDatabaseName(String databaseName) {
this.databaseName = databaseName;
}
public String getMeasuringPointNumberOrTechID() {
return measuringPointNumberOrTechID;
}
public void setMeasuringPointNumberOrTechID(String measuringPointNumberOrTechID) {
this.measuringPointNumberOrTechID = measuringPointNumberOrTechID;
}
public String getAssignmentTechIDorName() {
return assignmentTechIDorName;
}
public void setAssignmentTechIDorName(String assignmentTechIDorName) {
this.assignmentTechIDorName = assignmentTechIDorName;
}
public boolean isShortMem() {
return shortMem;
}
public void setShortMem(Boolean shortMem) {
this.shortMem = shortMem;
}
public boolean isLongMem() {
return longMem;
}
public void setLongMem(Boolean longMem) {
this.longMem = longMem;
}
public int getMaxCount() {
return maxCount;
}
public void setMaxCount(Integer maxCount) {
this.maxCount = maxCount;
}
public String getStartDateTime() {
return startDateTime;
}
public void setStartDateTime(String startDateTime) {
this.startDateTime = startDateTime;
}
public String getStopDateTime() {
return stopDateTime;
}
public void setStopDateTime(String stopDateTime) {
this.stopDateTime = stopDateTime;
}
public int getMpktTech() {
return mpktTech;
}
public void setMpktTech(Integer mpktTech) {
this.mpktTech = mpktTech;
}
public String getExpand() {
return expand;
}
public void setExpand(String expand) {
this.expand = expand;
}
}

View File

@ -0,0 +1,56 @@
package com.cisdi.data.DHV.gateway.vo.dhv;
import java.io.Serializable;
import java.util.List;
/**
* @author jianghc
* @function: 连接管理中自定义的其他参数
* @date 2022年05月05日 09:48
*/
public class OtherParamVO implements Serializable {
private MPSVO mpsvo;
private List<MPVVO> mpvvoList;
String Authorization;
String emptyanddefault;
public OtherParamVO(){
}
public MPSVO getMpsvo() {
return mpsvo;
}
public void setMpsvo(MPSVO mpsvo) {
this.mpsvo = mpsvo;
}
public List<MPVVO> getMpvvoList() {
return mpvvoList;
}
public void setMpvvoList(List<MPVVO> mpvvoList) {
this.mpvvoList = mpvvoList;
}
public String getAuthorization() {
return Authorization;
}
public void setAuthorization(String authorization) {
Authorization = authorization;
}
public String getEmptyanddefault() {
return emptyanddefault;
}
public void setEmptyanddefault(String emptyanddefault) {
this.emptyanddefault = emptyanddefault;
}
}

View File

@ -0,0 +1,45 @@
package com.cisdi.data.DHV.gateway.vo.dhv;
/**
* @author jianghc
* @function: 设备健康振动数据接入请求接口路径
* @date 2022/5/6 15:46
*/
public interface YFDHV {
//测点状态接口
//{databaseName}
String YF_DHV_MPS = "/databases/%s/measuringpoints";
//测点方法接口
//{dataBaseNamePlaceholder}数据库
//{measuringPointNumberOrTechID}测点编码
String YF_DHV_METH = "/databases/%s/measuringpoints/%s/assignments";
//测点总值接口
//{databaseName}
//{measuringPointNumberOrTechID}
//{assignmentTechIDorName}
String YF_DHV_MPV = "/databases/%s/measuringpoints/%s/assignments/%s/results";
//测点状态电文号=数据库.MPS
String YF_MPS = "MPS";
//测点总值电文号=测点.MPV
String YF_MPV = "MPV";
//分隔符,.作为分隔符
String YF_Separator = ".";
//转义字符split("\\.")时使用
String YF_EscapeCharacter="\\";
//注意测点状态时间是系统生成的没有从接口中获取到
String DateTime = "DateTime";
}

View File

@ -0,0 +1,146 @@
package com.cisdi.data.DIClient;
import com.alibaba.fastjson.JSON;
import com.cisdi.data.DIClient.bean.DIClientCnfg;
import com.cisdi.data.DIClient.bean.PDIOVo;
import com.cisdi.data.DIClient.gateway.DBReader;
import com.cisdi.data.DIClient.gateway.DBTask;
import com.cisdi.data.common.exception.BusinessException;
import com.cisdi.data.sdk.consts.ServiceName;
import com.cisdi.data.sdk.enums.GatewayState;
import com.cisdi.data.sdk.gateway.base.SocketGatewayBase;
import com.cisdi.data.sdk.param.ListenSocketParam;
import com.cisdi.data.sdk.procotol.message.SocketReturnMessage;
import com.cisdi.data.sdk.service.RouteService;
import com.cisdi.data.sdk.vo.DeviceVo;
import com.cisdi.data.sdk.vo.ExeResultVo;
import com.google.common.collect.Sets;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.sql.SQLException;
import java.util.List;
import java.util.Set;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.concurrent.atomic.AtomicLong;
public class DIClientGateway extends SocketGatewayBase {
private static Logger logger = LoggerFactory.getLogger(DIClientGateway.class);
private String deviceId;
private DBTask dbTask = null;
private AtomicLong lastTime=new AtomicLong(0);
private AtomicInteger no=new AtomicInteger(0);
@Override
public ExeResultVo sendReturnMessage(SocketReturnMessage returnMsg) {
ExeResultVo rt = new ExeResultVo();
PDIOVo pdioVo = new PDIOVo();
pdioVo.setQueueId(returnMsg.getMsgKey());
pdioVo.setData(new String(returnMsg.getData()));
Long thisTime=System.currentTimeMillis();
if(thisTime>lastTime.get())
{
lastTime.set(thisTime);
no.set(0);
pdioVo.setSerialNo(0);
pdioVo.setTimeStamp(thisTime);
}
else if(thisTime==lastTime.get())
{
pdioVo.setSerialNo(no.incrementAndGet());
pdioVo.setTimeStamp(thisTime);
}
else
{
pdioVo.setTimeStamp(lastTime.get());
pdioVo.setSerialNo(no.incrementAndGet());
}
pdioVo.setHeader("cisdi");
pdioVo.setStatus("N");
dbTask.sendMessage(pdioVo);
rt.setSuccess(true);
rt.setMessage("DIClient下发数据成功消息体为" + JSON.toJSONString(pdioVo));
logger.info("DIClient下发数据成功消息体为" + JSON.toJSONString(pdioVo));
return rt;
}
@Override
public void start() {
if (state == GatewayState.RUNNING) {
return;
}
ListenSocketParam socketParam = JSON.parseObject(getInstanceVo().getParameter(), ListenSocketParam.class);
String otherParameter = socketParam.getOtherParameter();
DIClientCnfg diClientCnfg = null;
// 处理分组
if (StringUtils.isNotBlank(otherParameter)) {
diClientCnfg = JSON.parseObject(otherParameter, DIClientCnfg.class);
}
if (diClientCnfg == null) {
throw new BusinessException("网关Id:" + instanceVo.getRunId() + "为DIClient网关请配置正确的DIClient配置");
}
RouteService routeService = (RouteService) serviceProvider.getByName(ServiceName.Route);
List<DeviceVo> deviceVos = routeService.findByRunId(instanceVo.getRunId());
if (deviceVos.size() > 1) {
throw new BusinessException("网关Id:" + instanceVo.getRunId() + "为DIClient网关只允许关联一个设备Id");
}
deviceId = deviceVos.size() > 0 ? deviceVos.get(0).getDeviceId() : null;
if (StringUtils.isEmpty(deviceId)) {
throw new BusinessException("runId=" + getInstanceVo().getRunId() + "未正确配置网关和设备关联");
}
logger.info("DIClient网关:{}读取启动配置参数:{}", instanceVo.getRunId(), getInstanceVo().getParameter());
boolean open = false;
DBReader dbReader = new DBReader(diClientCnfg.getDriverClassName(), diClientCnfg.getUrl(), diClientCnfg.getUser(), diClientCnfg.getPwd());
open = dbReader.connectionInternal(0);
if (open == true) {
dbTask = new DBTask(serviceProvider, this, dbReader, diClientCnfg.getCycleTime(), deviceId);
dbTask.start();
state = GatewayState.RUNNING;
logger.info("DIClient网关:{}启动成功 参数:{}", instanceVo.getRunId(), getInstanceVo().getParameter());
} else {
logger.info("DIClient网关:{}启动失败 参数:{}", instanceVo.getRunId(), getInstanceVo().getParameter());
}
}
@Override
public void shutdown() {
if (state == GatewayState.CLOSED) {
return;
}
try {
dbTask.close();
state = GatewayState.CLOSED;
logger.info("网关:" + instanceVo.getRunId() + "关闭成功", instanceVo.getRunId());
} catch (SQLException e) {
logger.error("网关:" + instanceVo.getRunId() + "关闭失败" + e.getLocalizedMessage());
}
}
@Override
public Set<String> getActiveDeviceIds() {
Set<String> set = Sets.newConcurrentHashSet();
if (StringUtils.isNotEmpty(deviceId)) {
set.add(deviceId);
}
return set;
}
}

View File

@ -0,0 +1,52 @@
package com.cisdi.data.DIClient;
import com.alibaba.fastjson.JSON;
import com.cisdi.data.DIClient.bean.DIClientCnfg;
import com.cisdi.data.DIClient.gateway.DBReader;
import com.cisdi.data.DIClient.gateway.DBTask;
import com.cisdi.data.common.exception.BusinessException;
import com.cisdi.data.sdk.enums.GatewayState;
import java.io.UnsupportedEncodingException;
public class DIClientTest {
public static void main(String[] args) throws UnsupportedEncodingException {
char x=0x03;
String test="20210408195055077MR001 N11001001 yf R一级焦炭 Bt 7.000 2 Y99999.0000 0.0000 0.0000 0.0000 B020 ";
String value="7.000 ";
value=value.trim();
int splitIndex = value.length() - 3;
String t="{\"cycleTime\":3000,\"dbName\":\"test\",\"driverClassName\":\"com.mysql.jdbc.Driver\",\"pwd\":\"yLNklB0v6Hu&J2T!\",\"url\":\"jdbc:mysql://10.232.12.58:3306/zgerp?useUnicode=true&characterEncoding=utf8&allowMultiQueries=true&useSSL=false\",\"user\":\"root\"} ";
String prev = value.substring(0, splitIndex-1);
String end = value.substring(splitIndex);
DIClientCnfg diClientCnfg=new DIClientCnfg();
diClientCnfg.setCycleTime((long) 3000);
diClientCnfg.setDbName("test");
diClientCnfg.setDriverClassName("com.mysql.jdbc.Driver");
diClientCnfg.setUrl("jdbc:mysql://10.232.12.58:3306/zgerp?useUnicode=true&characterEncoding=utf8&allowMultiQueries=true&useSSL=false");
diClientCnfg.setUser("root");
diClientCnfg.setPwd("yLNklB0v6Hu&J2T!");
System.out.println(JSON.toJSONString(diClientCnfg));
boolean open = false;
DBReader dbReader=new DBReader(diClientCnfg.getDriverClassName(),diClientCnfg.getUrl(),diClientCnfg.getUser(),diClientCnfg.getPwd());
open=dbReader.connectionInternal(0);
if(open == true) {
DBTask dbTask=new DBTask(null,null,dbReader,diClientCnfg.getCycleTime(),"");
dbTask.start();
try {
Thread.sleep(10000000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("DIClient网关:{}启动成功 参数:{}");
}else {
System.out.println("DIClient网关:{}启动失败 参数:{}");
}
}
}

View File

@ -0,0 +1,31 @@
package com.cisdi.data.DIClient.bean;
public class DBFieldVo {
private String filedName;
private String as;
private boolean orderBy;
public String getFiledName() {
return filedName;
}
public void setFiledName(String filedName) {
this.filedName = filedName;
}
public String getAs() {
return as;
}
public void setAs(String as) {
this.as = as;
}
public boolean isOrderBy() {
return orderBy;
}
public void setOrderBy(boolean orderBy) {
this.orderBy = orderBy;
}
}

View File

@ -0,0 +1,79 @@
package com.cisdi.data.DIClient.bean;
import java.util.List;
import java.util.Map;
public class DBTableTaskCnfg {
private DBTableVo tableName;
private List<DBFieldVo> fieldNames;
private List<String> condition;
private Long cycleTime;
private String taskType;
private String sortType;
private String groupBy;
private String msgKey;
public String getMsgKey() {
return msgKey;
}
public void setMsgKey(String msgKey) {
this.msgKey = msgKey;
}
public DBTableVo getTableName() {
return tableName;
}
public void setTableName(DBTableVo tableName) {
this.tableName = tableName;
}
public List<DBFieldVo> getFieldNames() {
return fieldNames;
}
public void setFieldNames(List<DBFieldVo> fieldNames) {
this.fieldNames = fieldNames;
}
public List<String> getCondition() {
return condition;
}
public void setCondition(List<String> condition) {
this.condition = condition;
}
public Long getCycleTime() {
return cycleTime;
}
public void setCycleTime(Long cycleTime) {
this.cycleTime = cycleTime;
}
public String getTaskType() {
return taskType;
}
public void setTaskType(String taskType) {
this.taskType = taskType;
}
public String getSortType() {
return sortType;
}
public void setSortType(String sortType) {
this.sortType = sortType;
}
public String getGroupBy() {
return groupBy;
}
public void setGroupBy(String groupBy) {
this.groupBy = groupBy;
}
}

View File

@ -0,0 +1,40 @@
package com.cisdi.data.DIClient.bean;
public class DBTableVo {
private DBTableVo leftTable;
private String rightTable;
private String joinType;
private String on;
public DBTableVo getLeftTable() {
return leftTable;
}
public void setLeftTable(DBTableVo leftTable) {
this.leftTable = leftTable;
}
public String getRightTable() {
return rightTable;
}
public void setRightTable(String rightTable) {
this.rightTable = rightTable;
}
public String getJoinType() {
return joinType;
}
public void setJoinType(String joinType) {
this.joinType = joinType;
}
public String getOn() {
return on;
}
public void setOn(String on) {
this.on = on;
}
}

View File

@ -0,0 +1,72 @@
package com.cisdi.data.DIClient.bean;
import java.util.List;
import java.util.Map;
public class DIClientCnfg {
private String dbName;
private String url;
private String user;
private String pwd;
private String driverClassName;
private Long cycleTime;
//TASK名字TASK筛选条件
// Map<String, DBTableTaskCnfg> taskMap;
public Long getCycleTime() {
return cycleTime;
}
public void setCycleTime(Long cycleTime) {
this.cycleTime = cycleTime;
}
public String getDbName() {
return dbName;
}
public void setDbName(String dbName) {
this.dbName = dbName;
}
public String getUrl() {
return url;
}
public void setUrl(String url) {
this.url = url;
}
public String getUser() {
return user;
}
public void setUser(String user) {
this.user = user;
}
public String getPwd() {
return pwd;
}
public void setPwd(String pwd) {
this.pwd = pwd;
}
public String getDriverClassName() {
return driverClassName;
}
public void setDriverClassName(String driverClassName) {
this.driverClassName = driverClassName;
}
// public Map<String, DBTableTaskCnfg> getTaskMap() {
// return taskMap;
// }
//
// public void setTaskMap(Map<String, DBTableTaskCnfg> taskMap) {
// this.taskMap = taskMap;
// }
}

View File

@ -0,0 +1,76 @@
package com.cisdi.data.DIClient.bean;
public class PDIOVo {
private Long timeStamp;
private Integer serialNo;
private String queueId;
private String header;
private String data;
private String status;
private String processTime;
private String description;
public Long getTimeStamp() {
return timeStamp;
}
public void setTimeStamp(Long timeStamp) {
this.timeStamp = timeStamp;
}
public Integer getSerialNo() {
return serialNo;
}
public void setSerialNo(Integer serialNo) {
this.serialNo = serialNo;
}
public String getQueueId() {
return queueId;
}
public void setQueueId(String queueId) {
this.queueId = queueId;
}
public String getHeader() {
return header;
}
public void setHeader(String header) {
this.header = header;
}
public String getData() {
return data;
}
public void setData(String data) {
this.data = data;
}
public String getStatus() {
return status;
}
public void setStatus(String status) {
this.status = status;
}
public String getProcessTime() {
return processTime;
}
public void setProcessTime(String processTime) {
this.processTime = processTime;
}
public String getDescription() {
return description;
}
public void setDescription(String description) {
this.description = description;
}
}

View File

@ -0,0 +1,215 @@
package com.cisdi.data.DIClient.gateway;
import com.cisdi.data.DIClient.bean.PDIOVo;
import com.cisdi.data.common.exception.BusinessException;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.sql.*;
import java.text.DateFormat;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.List;
import java.util.Date;
public class DBReader
{
Logger logger= LoggerFactory.getLogger(DBReader.class);
/**
* JDBC的连接对象实例
*/
private Connection conn = null;
private String driver;
private String url;
private String username;
private String password;
public DBReader(String driver, String url, String username, String password) {
this.driver = driver;
this.url = url;
this.username = username;
this.password = password;
}
public void reconnect()
{
logger.info("由于发生了异常,正在尝试重连");
try {
if(conn!=null&&!conn.isClosed())
{
conn.close();
}
connectionInternal(0);
} catch (SQLException e1) {
e1.printStackTrace();
}
}
public boolean connectionInternal(int reconnectNumber) {
try {
Class.forName(driver);
conn = DriverManager.getConnection(url, username, password);
logger.info("【DI Client】建立与mysql数据库(URL:" + url + ")的连接");
return true;
} catch (Exception e) {
logger.warn(e.getMessage(), e);
logger.error("【DI Client】SQL:连接失败,等待重连,剩余重连次数" + reconnectNumber + " 异常信息:" + e.getLocalizedMessage());
reconnectNumber=reconnectNumber-1;
if (reconnectNumber <= 0) {
logger.error("【DI Client】SQL:重连失败DIClient连接启动失败");
return false;
}
try {
Thread.sleep(10000);
} catch (Exception e1) {
logger.info("【DI Client】SQL:等待失败,进程退出");
}
return this.connectionInternal(reconnectNumber);
}
}
public void close() throws SQLException {
if(conn!=null&&!conn.isClosed())
{
conn.close();
}
}
public int getTotal()
{
String sql = "select count(*) from TBDIPDI where status='N' ";
ResultSet myResult = null;
PreparedStatement pre = null;
try {
pre = conn.prepareStatement(sql);
myResult = pre.executeQuery();
while (myResult.next()) {
return myResult.getInt("count(*)");
}
} catch (Exception e) {
logger.error("【DB】SQL语句" + sql + "执行失败,请检查配置文件是否正确,以及数据表是否更改:" + e.getLocalizedMessage(), e);
reconnect();
} finally {
closeObj(myResult);
closeObj(pre);
}
return 0;
}
public List<PDIOVo> getPDIOs(int limit)
{
List<PDIOVo> rt=new ArrayList<>();
String sql = "select timestamp,serialno,queueid,header,data,status,processtime,description from TBDIPDI where status='N' order by TIMESTAMP,SerialNo asc limit "+limit;
ResultSet myResult = null;
PreparedStatement pre = null;
try {
pre = conn.prepareStatement(sql);
myResult = pre.executeQuery();
while (myResult.next()) {
PDIOVo pdioVo=new PDIOVo();
pdioVo.setTimeStamp(myResult.getLong("timestamp"));
pdioVo.setSerialNo(myResult.getInt("serialno"));
pdioVo.setQueueId(myResult.getString("queueid"));
pdioVo.setHeader(myResult.getString("header"));
pdioVo.setData(myResult.getString("data"));
pdioVo.setStatus(myResult.getString("status"));
pdioVo.setProcessTime(myResult.getString("processtime"));
pdioVo.setDescription(myResult.getString("description"));
rt.add(pdioVo);
}
} catch (Exception e) {
logger.error("【DB】SQL语句" + sql + "执行失败,请检查配置文件是否正确,以及数据表是否更改:" + e.getLocalizedMessage(), e);
reconnect();
} finally {
closeObj(myResult);
closeObj(pre);
}
return rt;
}
private void closeObj(Object obj) {
if (obj == null) {
return;
}
if (obj instanceof PreparedStatement) {
PreparedStatement prepare = (PreparedStatement) obj;
try {
prepare.close();
return;
} catch (Exception e) {
}
}
if (obj instanceof ResultSet) {
ResultSet resultSet = (ResultSet) obj;
try {
resultSet.close();
return;
} catch (Exception e) {
}
}
throw new BusinessException("not support type" + obj.getClass());
}
public void updateStatus(List<PDIOVo> pdioVos,char status,String desc)
{
if(pdioVos==null||pdioVos.size()==0)
{
return;
}
String inStr="(";
for(PDIOVo pdioVo:pdioVos)
{
inStr+="("+pdioVo.getTimeStamp()+","+pdioVo.getSerialNo()+"),";
}
if(inStr.contains("),"))
{
inStr=inStr.substring(0,inStr.length()-1);
}
inStr+=")";
List<PDIOVo> rt=new ArrayList<>();
Date date=new Date();
DateFormat format = new SimpleDateFormat("yyyyMMddHHmmss");
String sql = "update TBDIPDI set status='"+status+"', processtime='"+format.format(date)+"'"+ (StringUtils.isBlank(desc)?"":",description='"+desc+"'") +" where (timestamp,serialno) in "+ inStr;
int myResultCount = 0;
PreparedStatement pre = null;
try {
pre = conn.prepareStatement(sql);
myResultCount = pre.executeUpdate();
if(myResultCount!=pdioVos.size())
{
logger.error("【DB】部分数据更新失败入参"+pdioVos.size()+"条,更新了"+myResultCount+"");
}
} catch (Exception e) {
logger.error("【DB】SQL语句" + sql + "执行失败,请检查配置文件是否正确,以及数据表是否更改:" + e.getLocalizedMessage(), e);
reconnect();
} finally {
closeObj(pre);
}
}
public void addPDIOs(PDIOVo pdioVos)
{
String sql = "insert into TBDIPDO (TBDIPDO.`TimeStamp`,TBDIPDO.SerialNo,TBDIPDO.QueueId,TBDIPDO.Header,TBDIPDO.`Data`,TBDIPDO.`Status`) value ("+pdioVos.getTimeStamp()+","+pdioVos.getSerialNo()+",'"+pdioVos.getQueueId()+"','"+pdioVos.getHeader()+"','"+pdioVos.getData()+"','"+pdioVos.getStatus()+"')";
int myResultCount = 0;
PreparedStatement pre = null;
try {
pre = conn.prepareStatement(sql);
myResultCount = pre.executeUpdate();
if(myResultCount!=1)
{
logger.error("【DB】部分数据插入失败");
}
} catch (Exception e) {
logger.error("【DB】SQL语句" + sql + "执行失败,请检查配置文件是否正确,以及数据表是否更改:" + e.getLocalizedMessage(), e);
reconnect();
} finally {
closeObj(pre);
}
}
}

View File

@ -0,0 +1,137 @@
package com.cisdi.data.DIClient.gateway;
import com.alibaba.fastjson.JSON;
import com.cisdi.data.DIClient.bean.DBFieldVo;
import com.cisdi.data.DIClient.bean.DBTableTaskCnfg;
import com.cisdi.data.DIClient.bean.PDIOVo;
import com.cisdi.data.sdk.consts.ServiceName;
import com.cisdi.data.sdk.gateway.base.SocketGatewayBase;
import com.cisdi.data.sdk.gateway.message.SocketMessage;
import com.cisdi.data.sdk.service.DynamicCodecService;
import com.cisdi.data.sdk.service.SendService;
import com.cisdi.data.sdk.service.ServiceProvider;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.nio.charset.Charset;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.List;
public class DBTask extends Thread {
Logger logger= LoggerFactory.getLogger(DBTask.class);
private ServiceProvider serviceProvider;
private SocketGatewayBase socketGateway;
private DBReader dbReader;
private Long cycleTime;
private boolean shouldRun;
private String deviceId;
private long lastTime=0;
private int lastNo=0;
public DBTask(ServiceProvider serviceProvider, SocketGatewayBase socketGateway, DBReader dbReader,Long cycleTime,String deviceId) {
this.serviceProvider = serviceProvider;
this.socketGateway = socketGateway;
this.dbReader = dbReader;
this.cycleTime=cycleTime;
shouldRun=true;
this.deviceId=deviceId;
}
public boolean close() throws SQLException {
dbReader.close();
shouldRun=false;
return true;
}
public void sendMessage(PDIOVo pdioVo)
{
dbReader.addPDIOs(pdioVo);
}
@Override
public void run() {
while (shouldRun)
{
long startTime=System.currentTimeMillis();
while(true)
{
int total=dbReader.getTotal();
List<PDIOVo> pdioVoList=dbReader.getPDIOs(2000);
if(pdioVoList!=null&&pdioVoList.size()>0)
{
List<PDIOVo> successList=new ArrayList<>();
List<PDIOVo> errorList=new ArrayList<>();
String error="";
if(serviceProvider==null||socketGateway==null)
{
for(PDIOVo pdioVo:pdioVoList)
{
sendMessage(pdioVo);
System.out.println(JSON.toJSONString(pdioVo));
}
}
else
{
SendService service = (SendService)serviceProvider.getByName(ServiceName.Send);
DynamicCodecService dynamicCodecService=(DynamicCodecService)serviceProvider.getByName(ServiceName.DynamicCodec);
for(PDIOVo pdioVo:pdioVoList)
{
try
{
String paramObj = dynamicCodecService.findByRunIdAndMsgKey(socketGateway.getInstanceVo().getRunId(), pdioVo.getQueueId());
if(StringUtils.isBlank(paramObj))
{
continue;
}
}
catch (Exception e)
{
continue;
}
try
{
SocketMessage socketMessage = socketGateway.buildSocketMessage();
socketMessage.setDeviceId(this.deviceId);
socketMessage.setMsgKey(pdioVo.getQueueId());
socketMessage.setData(pdioVo.getData().getBytes("GBK"));
socketMessage.getPropsMap().put("charset", Charset.forName("GBK"));
service.sendMessage(socketMessage);
successList.add(pdioVo);
}
catch (Exception e)
{
pdioVo.setDescription(e.getLocalizedMessage());
errorList.add(pdioVo);
error=e.getLocalizedMessage();
}
}
if(errorList.size() > 0)
{
dbReader.updateStatus(errorList,'E',error);
}
if(successList.size() > 0)
{
dbReader.updateStatus(successList,'O',"");
}
}
}
if(pdioVoList.size()==0||pdioVoList.size()==total)
{
break;
}
}
long endTime=System.currentTimeMillis();
try {
if(endTime-startTime<=cycleTime)
{
Thread.sleep(cycleTime-(endTime-startTime));
}
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}

View File

@ -0,0 +1,64 @@
//package com.cisdi.data.DIClient.gateway;
//
//import org.apache.commons.dbcp2.BasicDataSourceFactory;
//
//import javax.security.auth.login.Configuration;
//import javax.sql.DataSource;
//import java.sql.Connection;
//import java.sql.SQLException;
//import java.util.Properties;
//
//public class MysqlPool {
// private String driver;
// private String url;
// private String username;
// private String password;
// private Long removeTimeOut;
// private int maxTotal;
//
// private DataSource dataSource=null;
//
// public MysqlPool(String driver, String url, String username, String password, Long removeTimeOut, int maxTotal) {
// this.driver = driver;
// this.url = url;
// this.username = username;
// this.password = password;
// this.removeTimeOut = removeTimeOut;
// this.maxTotal = maxTotal;
// }
//
// public boolean init()
// {
// Properties properties=new Properties();
// properties.setProperty("driverClassName",driver);
// properties.setProperty("url",url);
// properties.setProperty("username",username);
// properties.setProperty("password",password);
// properties.setProperty("initialSize",String.valueOf(maxTotal));
// properties.setProperty("maxTotal",String.valueOf(maxTotal));
// properties.setProperty("maxIdle",String.valueOf(maxTotal/2));
// properties.setProperty("minIdle",String.valueOf(maxTotal/4));
// properties.setProperty("maxWaitMillis",String.valueOf(1000));
// properties.setProperty("removeAbandonedTimeout",String.valueOf(removeTimeOut));
// properties.setProperty("removeAbandonedOnMaintenance",String.valueOf(true));
// properties.setProperty("removeAbandonedOnBorrow",String.valueOf(true));
// try {
// dataSource= BasicDataSourceFactory.createDataSource(properties);
// } catch (Exception e) {
// e.printStackTrace();
// }
// return false;
// }
// public Connection getConnection()
// {
// Connection connection=null;
// try
// {
// connection=dataSource.getConnection();
// connection.setAutoCommit(false);
// } catch (SQLException e) {
// e.printStackTrace();
// }
// return connection;
// }
//}

View File

@ -0,0 +1,127 @@
package com.cisdi.data.DIClient.protocol;
import com.alibaba.fastjson.JSON;
import com.cisdi.data.DIClient.protocol.utils.IXComActionParamDTO;
import com.cisdi.data.DIClient.protocol.utils.IXComCodecService;
import com.cisdi.data.common.exception.BusinessException;
import com.cisdi.data.sdk.consts.ServiceName;
import com.cisdi.data.sdk.gateway.message.SocketMessage;
import com.cisdi.data.sdk.procotol.SocketProtocol;
import com.cisdi.data.sdk.procotol.base.ProtocolBase;
import com.cisdi.data.sdk.procotol.message.SocketReturnMessage;
import com.cisdi.data.sdk.service.DynamicCodecService;
import com.cisdi.data.sdk.service.RouteService;
import com.cisdi.data.sdk.vo.DecodeVo;
import com.cisdi.data.sdk.vo.DeviceVo;
import com.cisdi.data.sdk.vo.ReturnVo;
import org.apache.commons.lang3.StringUtils;
import java.io.UnsupportedEncodingException;
import java.nio.charset.Charset;
import java.util.Map;
/**
* @author: lhp
* @date: 2019/10/8
**/
public class IXCom29DStringSocketProtocol extends ProtocolBase implements SocketProtocol {
@Override
public DecodeVo deCode(SocketMessage message) {
if (message == null || message.getRunId() == null || message.getPropsMap() == null || message.getDeviceId() == null) {
throw new BusinessException("解析入参错误1,msg为:" + message.toString());
}
DynamicCodecService service = (DynamicCodecService)serviceProvider.getByName(ServiceName.DynamicCodec);
if (service == null || !(service instanceof DynamicCodecService)) {
throw new BusinessException("获取DynamicCodecService失败");
}
String paramObj = service.findByRunIdAndMsgKey(message.getRunId(), message.getMsgKey());
Charset charset = Charset.forName(String.valueOf(message.getPropsMap().get("charset")));
byte[] data = message.getData();
if(data == null || paramObj == null) {
throw new BusinessException("解析入参错误2,msg为:" + message.toString());
}
IXComActionParamDTO dto = JSON.parseObject(paramObj, IXComActionParamDTO.class);
dto.setMsgKey(message.getMsgKey());
if(dto == null || dto.getPropertyList().size() == 0) {
throw new BusinessException("解析入参错误3,msg为:" + message.toString());
}
DecodeVo vo = new DecodeVo();
IXComCodecService defaultService = new IXComCodecService();
Map<String,Object> map = defaultService.decode(message.getRunId(), dto, data, charset);
vo.setData(map);
return vo;
}
@Override
public SocketReturnMessage enCode(ReturnVo returnVo) {
if (returnVo == null || returnVo.getValue() == null || returnVo.getDeviceId() == null) {
throw new BusinessException("解析入参错误1,msg为:" + JSON.toJSONString(returnVo));
}
DynamicCodecService service = (DynamicCodecService)serviceProvider.getByName(ServiceName.DynamicCodec);
if (service == null || !(service instanceof DynamicCodecService)) {
throw new BusinessException("获取DynamicCodecService失败");
}
RouteService routeService = (RouteService)serviceProvider.getByName(ServiceName.Route);
if (service == null || !(routeService instanceof RouteService)) {
throw new BusinessException("获取RouteService失败");
}
DeviceVo deviceVo=routeService.findDeviceByDeviceId(returnVo.getDeviceId());
if(deviceVo==null|| StringUtils.isBlank(deviceVo.getRunId()))
{
throw new BusinessException("获取DeviceVo失败");
}
String paramObj = service.findByRunIdAndMsgKey(deviceVo.getRunId(), returnVo.getMsgKey());
Charset charset = Charset.forName(String.valueOf(Charset.forName("GBK")));
IXComActionParamDTO dto = JSON.parseObject(paramObj, IXComActionParamDTO.class);
if(dto == null || dto.getPropertyList().size() == 0) {
throw new BusinessException("解析入参错误3,msg为:" + JSON.toJSONString(returnVo));
}
StringBuilder data= new StringBuilder();
for(IXComActionParamDTO.PropertyConfig propertyConfig:dto.getPropertyList())
{
if(!returnVo.getValue().containsKey(propertyConfig.getPropertyId()))
{
throw new BusinessException("解析入参错误4,msg为:" + JSON.toJSONString(returnVo)+"在runId="+deviceVo.getRunId()+";msgKey="+returnVo.getMsgKey()+"的情况下,入参缺失"+propertyConfig.getPropertyId());
}
StringBuilder tmp= new StringBuilder(String.valueOf(returnVo.getValue().get(propertyConfig.getPropertyId())));
int tmpLength= 0;
try {
tmpLength = tmp.toString().getBytes("GBK").length;
} catch (UnsupportedEncodingException e) {
throw new BusinessException("解析入参错误5,msg为:" + JSON.toJSONString(returnVo)+"在runId="+deviceVo.getRunId()+";msgKey="+returnVo.getMsgKey()+"的情况下,入参"+propertyConfig.getPropertyId()+"转换GBK失败"+e.getLocalizedMessage());
}
if(propertyConfig.getFixedLength()!=0&&tmpLength<propertyConfig.getFixedLength())
{
for(int i=0;i<(propertyConfig.getFixedLength()-tmpLength);i++)
{
tmp.append(" ");
}
}
else if(propertyConfig.getFixedLength()!=0&&tmp.length()>propertyConfig.getFixedLength())
{
throw new BusinessException("解析入参错误6,msg为:" + JSON.toJSONString(returnVo)+"在runId="+deviceVo.getRunId()+";msgKey="+returnVo.getMsgKey()+"的情况下,入参过长"+propertyConfig.getPropertyId());
}
data.append(tmp);
}
SocketReturnMessage rt=new SocketReturnMessage();
rt.setDeviceId(returnVo.getDeviceId());
rt.setMsgId(returnVo.getMsgId());
rt.setMsgKey(returnVo.getMsgKey());
rt.setData(data.toString().getBytes());
return rt;
}
}

View File

@ -0,0 +1,133 @@
package com.cisdi.data.DIClient.protocol.utils;
import java.util.ArrayList;
import java.util.List;
/**
* @author: lhp
* @date: 2019/10/8
**/
public class IXComActionParamDTO {
public enum PropertyType {
BYTE,
BOOLEAN,
SHORT,
INT,
FLOAT,
DOUBLE,
STRING,
LONG,
PLACEHOLDER;
}
/**
* 属性列表
*/
private List<PropertyConfig> propertyList;
/**
* 电文号
*/
private String msgKey;
/**
* 是否透传
*/
private Boolean isPassthrough;
public Boolean getIsPassthrough() {
return isPassthrough;
}
public void setIsPassthrough(Boolean isPassthrough) {
this.isPassthrough = isPassthrough;
}
public String getMsgKey() {
return msgKey;
}
public void setMsgKey(String msgKey) {
this.msgKey = msgKey;
}
public void appendProperty(PropertyConfig propertyConfig) {
if (propertyConfig == null) {
return;
}
if (propertyList == null) {
propertyList = new ArrayList<>();
}
propertyList.add(propertyConfig);
}
public static class PropertyConfig{
/** 属性Id*/
private String propertyId;
/** 属性类型*/
private PropertyType propertyType;
/**固定长度*/
private Integer fixedLength;
/**精度*/
private Integer precision;
public String getPropertyId() {
return propertyId;
}
public void setPropertyId(String propertyId) {
this.propertyId = propertyId;
}
public PropertyType getPropertyType() {
return propertyType;
}
public void setPropertyType(PropertyType propertyType) {
this.propertyType = propertyType;
}
public Integer getFixedLength() {
return fixedLength;
}
public void setFixedLength(Integer fixedLength) {
this.fixedLength = fixedLength;
}
public Integer getPrecision() {
return precision;
}
public void setPrecision(Integer precision) {
this.precision = precision;
}
@Override
public String toString() {
return "PropertyConfig [propertyId=" + propertyId + ", propertyType=" + propertyType + ", fixedLength="
+ fixedLength + ", precision=" + precision + "]";
}
}
public List<PropertyConfig> getPropertyList() {
return propertyList;
}
public void setPropertyList(List<PropertyConfig> propertyList) {
this.propertyList = propertyList;
}
@Override
public String toString() {
return "IXComActionParamDTO [propertyList=" + propertyList + ", isPassthrough=" + isPassthrough + "]";
}
}

View File

@ -0,0 +1,141 @@
package com.cisdi.data.DIClient.protocol.utils;
import com.alibaba.fastjson.JSON;
import com.cisdi.data.common.exception.BusinessException;
import com.cisdi.data.sdk.service.DynamicCodecService;
import java.nio.ByteBuffer;
import java.nio.charset.Charset;
import java.util.HashMap;
import java.util.Map;
/**
* @author: lhp
* @date: 2019/10/8
**/
public class IXComCodecService {
public Map<String, Object> decode(String runId, IXComActionParamDTO dto, byte[] data, Charset charset) {
int sumLen = 0;
try{
sumLen = dto.getPropertyList().stream().mapToInt(IXComActionParamDTO.PropertyConfig::getFixedLength).sum();
} catch (Exception e) {
throw new BusinessException("连接id:" + String.valueOf(runId) + "电文号:" + String.valueOf(dto.getMsgKey()) +
" ixcom29d解析数据长度失败", e);
}
if (sumLen != data.length) {
if(dto.getPropertyList().get(dto.getPropertyList().size()-1).getFixedLength()!=0)
{
throw new BusinessException("连接id:" + String.valueOf(runId) + "电文号:" + String.valueOf(dto.getMsgKey()) +
" ixcom29d解析长度与数据长度不一致错误, 解析数据长度为: " + data.length + " 配置长度为: " + sumLen);
}
}
Map<String, Object> map = new HashMap<>();
ByteBuffer byteBuffer = ByteBuffer.wrap(data);
for(int i=0;i<dto.getPropertyList().size();i++)
{
if (dto.getPropertyList().get(i) != null) {
IXComActionParamDTO.PropertyConfig property=dto.getPropertyList().get(i);
if(i==dto.getPropertyList().size()-1&&property.getFixedLength()==0)
{
property.setFixedLength(byteBuffer.array().length-sumLen);
}
Object object = IXComConverterUtils.convertProperty(property, byteBuffer, charset,runId,dto.getMsgKey());
if (object != null) {
map.put(property.getPropertyId(), object);
}
}
}
return map;
}
/**
* 测试类*/
public static class TestDynamicCodecHelperImpl implements DynamicCodecService {
@Override
public String getName() {
return null;
}
@Override
public String findByRunIdAndMsgKey(String runId, String msgKey) {
IXComActionParamDTO dto = new IXComActionParamDTO();
IXComActionParamDTO.PropertyConfig config = new IXComActionParamDTO.PropertyConfig();
config.setPropertyId("boolean");
config.setPropertyType(IXComActionParamDTO.PropertyType.BOOLEAN);
config.setFixedLength(1);
dto.appendProperty(config);
IXComActionParamDTO.PropertyConfig config1 = new IXComActionParamDTO.PropertyConfig();
config1.setPropertyId("short");
config1.setPropertyType(IXComActionParamDTO.PropertyType.SHORT);
config1.setFixedLength(1);
IXComActionParamDTO.PropertyConfig config2 = new IXComActionParamDTO.PropertyConfig();
config2.setPropertyId("int");
config2.setPropertyType(IXComActionParamDTO.PropertyType.INT);
config2.setFixedLength(4);
IXComActionParamDTO.PropertyConfig config3 = new IXComActionParamDTO.PropertyConfig();
config3.setPropertyId("long");
config3.setPropertyType(IXComActionParamDTO.PropertyType.LONG);
config3.setFixedLength(4);
IXComActionParamDTO.PropertyConfig config4 = new IXComActionParamDTO.PropertyConfig();
config4.setPropertyId("string");
config4.setPropertyType(IXComActionParamDTO.PropertyType.STRING);
config4.setFixedLength(10);
IXComActionParamDTO.PropertyConfig config5 = new IXComActionParamDTO.PropertyConfig();
config5.setPropertyId("double");
config5.setPropertyType(IXComActionParamDTO.PropertyType.DOUBLE);
config5.setFixedLength(8);
IXComActionParamDTO.PropertyConfig config6 = new IXComActionParamDTO.PropertyConfig();
config6.setPropertyId("");
config6.setPropertyType(IXComActionParamDTO.PropertyType.PLACEHOLDER);
config6.setFixedLength(6);
dto.appendProperty(config1);
dto.appendProperty(config2);
dto.appendProperty(config3);
dto.appendProperty(config4);
dto.appendProperty(config5);
dto.appendProperty(config6);
return JSON.toJSONString(dto);
}
@Override
public Boolean judgeBigEndianByRunId(String runId) {
return null;
}
@Override
public Boolean judgeBigEndianByDeviceId(String deviceId) {
return true;
}
@Override
public String findByRunIdAndMsgKeyNoCache(String runId, String msgKey) {
// TODO Auto-generated method stub
return null;
}
}
@SuppressWarnings("unused")
public static void main(String[] args) {
IXComCodecService service = new IXComCodecService();
Map<String, Object> map = new HashMap<>();
map.put("boolean", true);
map.put("short", Short.valueOf((short) 0xf2));
map.put("int", Integer.valueOf(0x03));
map.put("long", Long.valueOf(0xf4L));
map.put("string",new String("1234567890"));
map.put("double", Double.valueOf(-123123213.3));
Map<String, Object> map1 = JSON.parseObject(JSON.toJSONString(map));
// System.out.println(Arrays.toString(service.encode(map, "1","2", "1")));
// System.out.println(service.encode(map, "1","2","1").length);
//System.out.println(service.decode(service.encode(map, "1","2","1"), "1", "2", "1"));
}
}

View File

@ -0,0 +1,127 @@
package com.cisdi.data.DIClient.protocol.utils;
import com.cisdi.data.common.exception.BusinessException;
import org.apache.commons.lang3.StringUtils;
import java.math.BigDecimal;
import java.nio.ByteBuffer;
import java.nio.charset.Charset;
/**
* @author: lhp
* @date: 2019/10/8
**/
public class IXComConverterUtils {
private static final char blankspace = ' ';
/**
* 数字数据则在不满位数时左补0
例如421 00421在5位数字值的情况下
-421 -0421
字符串数据则在不够长度时右补空格
例如TSB TSBDDDD在7位字符串值的情况
* @param config
* @param reader
* @return
*/
public static Object convertProperty(IXComActionParamDTO.PropertyConfig config, ByteBuffer reader, Charset charset,String runid,String msgKey) {
char[] buffer = null;
try {
byte[] subBody = new byte[config.getFixedLength()];
reader.get(subBody);
String subValue = new String(subBody, charset);
buffer = subValue.toCharArray();
} catch (Exception e) {
throw new BusinessException("ixcom29d读取字符数组失败" + e.getLocalizedMessage(), e);
}
String value = new String(buffer);
if(config.getPropertyType()!= IXComActionParamDTO.PropertyType.STRING&&StringUtils.isBlank(value))
{
return null;
}
try
{
switch (config.getPropertyType()) {
case BYTE:
return Byte.valueOf(value.trim());
case SHORT:
return Short.valueOf(value.trim());
case INT:
return Integer.valueOf(value.trim());
case LONG:
return Long.valueOf(value.trim());
case BOOLEAN:
value = value.trim().replaceFirst("0*", "");
if("true".equalsIgnoreCase(value) || "1".equals(value)) {
return true;
}else if("false".equalsIgnoreCase(value) || "0".equals(value)) {
return false;
}
break;
case FLOAT:
case DOUBLE:
if(config.getPrecision() != null) {
value=value.trim();
BigDecimal decimal=null;
if(config.getPrecision()!=0)
{
int splitIndex = value.length() - config.getPrecision();
if(splitIndex < 0) {
throw new BusinessException("config:" + config + ",value:" + value + ",precision error");
}
String prev = value.substring(0, splitIndex-1);
String end = value.substring(splitIndex);
decimal= new BigDecimal(prev + "." + end);
}
else
{
decimal=new BigDecimal(value);
}
return decimal;
}else {
return new BigDecimal(value);
}
case STRING:
StringBuilder builder = new StringBuilder();
int index = buffer.length;
for (int i = buffer.length -1 ; i >= 0; i--) {
if(buffer[i] == blankspace) {
index = i;
continue;
}else {
break;
}
}
for (int j = 0; j < index; j++) {
builder.append(buffer[j]);
}
return builder.toString();
case PLACEHOLDER:
return null;
default:
return null;
}
}
catch (Exception e)
{
throw new BusinessException("连接id:" + String.valueOf(runid) + "电文号:" + msgKey +
" 解析数据类型错误属性ID=" + config.getPropertyId()+"属性类型="+config.getPropertyType()+"属性精度="+config.getPrecision()+"属性长度="+config.getFixedLength()+"对应的值="+value+"错误为:"+e.getLocalizedMessage());
}
throw new BusinessException(config.toString() + "解析失败,ixcom29d");
}
}

View File

@ -0,0 +1,138 @@
package com.cisdi.data.HJ212;
import java.util.List;
import java.util.Set;
import java.util.concurrent.atomic.AtomicBoolean;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import com.alibaba.fastjson.JSON;
import com.cisdi.data.HJ212.gateway.AliveCheckTask;
import com.cisdi.data.HJ212.gateway.Hj212ChannelInitializer;
import com.cisdi.data.HJ212.gateway.Hj212FrameDecoder;
import com.cisdi.data.HJ212.gateway.Hj212IoSession;
import com.cisdi.data.HJ212.gateway.Hj212SessionFactory;
import com.cisdi.data.common.exception.BusinessException;
import com.cisdi.data.sdk.consts.ServiceName;
import com.cisdi.data.sdk.enums.GatewayState;
import com.cisdi.data.sdk.gateway.base.SocketGatewayBase;
import com.cisdi.data.sdk.gateway.netty.IoSession;
import com.cisdi.data.sdk.gateway.netty.SessionFactory;
import com.cisdi.data.sdk.gateway.netty.TcpIoService;
import com.cisdi.data.sdk.gateway.netty.impl.DefaultTcpIoService;
import com.cisdi.data.sdk.param.ListenSocketParam;
import com.cisdi.data.sdk.procotol.message.SocketReturnMessage;
import com.cisdi.data.sdk.service.RouteService;
import com.cisdi.data.sdk.vo.DeviceVo;
import com.cisdi.data.sdk.vo.ExeResultVo;
import com.google.common.collect.Sets;
/**
* 扬尘监测网络设备 HJ212协议数据接入
* @author cup
*
*/
public class YfHj212SocketGateway extends SocketGatewayBase {
private static Logger logger = LoggerFactory.getLogger(YfHj212SocketGateway.class);
private TcpIoService ioService = null;
private SessionFactory sessionFactory = null;
private AtomicBoolean shouldRun = null;
private String deviceId;
@Override
public ExeResultVo sendReturnMessage(SocketReturnMessage returnMsg) {
throw new BusinessException("hj212网关不支持下发命令");
}
@Override
public void start() {
if(state == GatewayState.RUNNING) {
return;
}
logger.info("hj212网关:{}读取启动配置参数:{}",instanceVo.getRunId(), getInstanceVo().getParameter());
RouteService routeService = (RouteService)serviceProvider.getByName(ServiceName.Route);
List<DeviceVo> deviceVos = routeService.findByRunId(instanceVo.getRunId());
if(deviceVos.size() > 1) {
throw new BusinessException("网关Id:" +instanceVo.getRunId() + "为hj212网关只允许关联一个设备Id");
}
deviceId = deviceVos.size() > 0 ? deviceVos.get(0).getDeviceId() : null;
if(StringUtils.isEmpty(deviceId)) {
throw new BusinessException("runId=" + getInstanceVo().getRunId() + "未正确配置网关和设备关联");
}
DefaultTcpIoService defaultIoService = new DefaultTcpIoService();
SessionFactory factory = new Hj212SessionFactory(deviceId);
factory.init(serviceProvider, this);
ListenSocketParam socketParam = JSON.parseObject(getInstanceVo().getParameter(), ListenSocketParam.class);
Hj212ChannelInitializer<Hj212FrameDecoder> channelInitializer =
new Hj212ChannelInitializer<Hj212FrameDecoder>(factory);
defaultIoService.init(instanceVo, factory, channelInitializer);
ioService = defaultIoService;
sessionFactory = factory;
boolean open = ioService.open();
if(open == true) {
state = GatewayState.RUNNING;
logger.info("hj212网关:{}启动成功 参数:{}", instanceVo.getRunId(), getInstanceVo().getParameter());
shouldRun = new AtomicBoolean(true);
Integer keepAlive = socketParam.getKeepAlive();
if(keepAlive == null || keepAlive < 120) {
keepAlive = 120;
}else if (keepAlive > 3600) {
keepAlive = 3600;
}
AliveCheckTask task = new AliveCheckTask(keepAlive, shouldRun, factory);
Thread thread = new Thread(task, "hj212-alive-check-thread-" + getInstanceVo().getRunId());
thread.start();
}else {
logger.info("hj212网关:{}启动失败 参数:{}", instanceVo.getRunId(), getInstanceVo().getParameter());
}
}
@Override
public void shutdown() {
if(state == GatewayState.CLOSED) {
return;
}
if(sessionFactory != null) {
for (IoSession ioSession : sessionFactory.getSessions()) {
Hj212IoSession imsIoSession = (Hj212IoSession)ioSession;
imsIoSession.close();
}
}
boolean close = ioService.close();
if(close == true) {
sessionFactory = null;
state = GatewayState.CLOSED;
logger.info("hj212网关:{}关闭成功", instanceVo.getRunId());
}else {
logger.info("hj212网关:{}关闭失败", instanceVo.getRunId());
}
}
@Override
public Set<String> getActiveDeviceIds(){
Set<String> set = Sets.newHashSet();
set.add(deviceId);
return set;
}
}

View File

@ -0,0 +1,68 @@
package com.cisdi.data.HJ212.gateway;
import java.util.List;
import java.util.concurrent.atomic.AtomicBoolean;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import com.cisdi.data.sdk.gateway.netty.IoSession;
import com.cisdi.data.sdk.gateway.netty.SessionFactory;
/**
* 保活时间检测如果超过指定时间则关闭连接
* @author cup
*
*/
public class AliveCheckTask implements Runnable {
private static final Logger logger = LoggerFactory.getLogger(AliveCheckTask.class);
private SessionFactory sessionFactory;
private AtomicBoolean shouldRun = null;
/**
* 会话允许的保活时间单位秒
*/
private int keepAlive;
private static final double multiply = 1.5;
private static final int sleepInternal = 1000; // 1秒
public AliveCheckTask(int keepAlive, AtomicBoolean shouldRun, SessionFactory sessionFactory) {
super();
this.keepAlive = keepAlive;
this.shouldRun = shouldRun;
this.sessionFactory = sessionFactory;
}
@Override
public void run() {
logger.info("启动hj212保活超时检测线程");
while (shouldRun != null && shouldRun.get() == true) {
try {
long now = System.currentTimeMillis();
List<IoSession> sessions = sessionFactory.getSessions();
for (IoSession ioSession : sessions) {
Hj212IoSession session = (Hj212IoSession)ioSession;
// 超出指定倍数保活时间
if((now - session.getLastAliveTime()) > (multiply * keepAlive * 1000)) {
session.close();
logger.warn("{} 超出指定倍数{}保活时间{},单位秒,关闭通道",
session.gwPrefix(), multiply, keepAlive);
}
}
Thread.sleep(sleepInternal);
} catch (Exception e) {
logger.warn(e.getLocalizedMessage(), e);
}
}
logger.info("结束hj212保活超时检测线程");
}
}

View File

@ -0,0 +1,48 @@
package com.cisdi.data.HJ212.gateway;
import java.nio.charset.Charset;
public class CRC16Util {
public static final Charset UTF8 = Charset.forName("UTF-8");
/**
* HJ212污染监测 CRC16校验算法
*
* @param dataBody
* @return CRC16校验码
*/
public static String CRC16(String dataBody) {
Integer[] regs = new Integer[dataBody.length()];
for (int i = 0; i < dataBody.length(); i++) {
regs[i] = (int)dataBody.charAt(i);
}
int por = 0xFFFF;
for (int j = 0; j < regs.length; j++) {
por = por >> 8;
por ^= regs[j];
for (int i = 0; i < 8; i++) {
if ((por & 0x01) == 1) {
por = por >> 1;
por = por ^ 0xa001;
} else
por = por >> 1;
}
}
String result = Integer.toHexString(por).toUpperCase();
while (result.length() < 4) {
result = "0" + result;
}
return result;
}
public static void main(String[] args) {
String body1 =
"QN=20160801085857223;ST=32;CN=1062;PW=100000;MN=010000A8900016F000169DC0;Flag=5;CP=&&RtdInterval=30&&";
System.out.println(CRC16(body1)); // should be 1C80
String body2 = "QN=20120416225111069;ST=91;CN=9021;PW=122333;MN=88888880000006;Flag=1;CP=&&&&";
System.out.println(CRC16(body2)); // should be 4100
}
}

View File

@ -0,0 +1,48 @@
package com.cisdi.data.HJ212.gateway;
import java.util.ArrayList;
import java.util.List;
import com.cisdi.data.sdk.gateway.netty.SessionFactory;
import com.cisdi.data.sdk.gateway.netty.impl.AbstractChannelInitializer;
import com.cisdi.data.sdk.gateway.netty.impl.AbstractIoChannelHandler;
import com.cisdi.data.sdk.gateway.netty.impl.DefaultIoChannelHandler;
import io.netty.channel.Channel;
import io.netty.channel.ChannelHandler;
import io.netty.handler.timeout.IdleStateHandler;
public class Hj212ChannelInitializer<I> extends AbstractChannelInitializer<I> {
private SessionFactory factory;
/**
* 构造通道初始化器对象
* @param factory 会话工厂
*/
public Hj212ChannelInitializer(SessionFactory factory) {
this.factory = factory;
}
@SuppressWarnings("unchecked")
@Override
protected AbstractIoChannelHandler<I> getTailHandler() {
return new DefaultIoChannelHandler(factory);
}
@Override
protected List<ChannelHandler> getHandlers() {
List<ChannelHandler> handlers = new ArrayList<ChannelHandler>();
handlers.add(new Hj212FrameDecoder());
return handlers;
}
@Override
protected IdleStateHandler getIdleStateHandler() {
return new IdleStateHandler(15, 15, 30);
}
@Override
protected ChannelHandler getSslChannelHandler(Channel socketChannel) {
return null;
}
}

View File

@ -0,0 +1,89 @@
package com.cisdi.data.HJ212.gateway;
import com.cisdi.data.common.exception.BusinessException;
import io.netty.buffer.ByteBuf;
import io.netty.channel.ChannelHandlerContext;
import io.netty.handler.codec.ByteToMessageDecoder;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.nio.charset.Charset;
import java.nio.charset.StandardCharsets;
import java.util.List;
/**
* <p>Title: 永峰HJ212协议解码</p>
* <p>Description: 得到一个完整报文长度</p>
*
* @author lhp
* @version 1.0
* @date 2021.05.13
*/
public class Hj212FrameDecoder extends ByteToMessageDecoder {
Logger logger = LoggerFactory.getLogger(Hj212FrameDecoder.class);
// 包头2+数据段长度4+数据段0+CRC校验4+包尾2
private static final short Min_Length = 12;
private static final short Max_Length = 8192;
private Charset charset = StandardCharsets.UTF_8;
@Override
protected void decode(ChannelHandlerContext ctx, ByteBuf bufferIn, List<Object> out) throws Exception {
try {
if (bufferIn.readableBytes() < Min_Length) {
return;
}
final int beginIndex = bufferIn.readerIndex();
byte[] headerBytes = new byte[6];
bufferIn.readBytes(headerBytes);
String header = new String(headerBytes, charset);
// 解析headerString
String lendthString = getString(header, 2, 6);
// 数据段长度
int length = Integer.valueOf(lendthString);
// 数据段长度+其他长度才是总的长度
length += 12;
if (length > Max_Length) {
ctx.close();
throw new BusinessException("超过协议允许最大报文长度,默认为 " + Max_Length + " byte当前为" + length + "byte");
}
if (length < Min_Length) {
ctx.close();
throw new BusinessException(ctx.channel().toString() + "传输数据体长度小于12 此长度为:" + length);
}
if (bufferIn.readableBytes() < length - 6) { // 拆包
bufferIn.readerIndex(beginIndex);
return;
}
bufferIn.readerIndex(beginIndex);
ByteBuf otherByteBufRef = bufferIn.retainedSlice(beginIndex, length);
bufferIn.readerIndex(beginIndex + length);
out.add(otherByteBufRef);
// 处理可能的粘包
decode(ctx, bufferIn, out);
} catch (Exception e) {
logger.error("拆包过程出现异常,原始消息为:{}", bufferIn.toString(charset));
}
}
private String getString(String header, int start, int end) {
char[] dst = new char[end - start];
header.getChars(start, end, dst, 0);
return new String(dst);
}
}

View File

@ -0,0 +1,82 @@
package com.cisdi.data.HJ212.gateway;
import java.util.Map;
public class Hj212FrameInputVo {
/** 请求编码 精确到毫秒的时间戳:QN=YYYYMMDDhhmmsszzz用来唯一标识一次命令交互 */
private String qn;
/** 系统编码 */
private String st;
/** 命令编码,可以作为电文号 */
private String cn;
/** 访问密码 */
private String pw;
/** 设备唯一标识MN */
private String mn;
/** 拆分包及应答标志 */
private Integer flag;
/** 指令参数CP */
private String cp;
/** cp 中包含的 DataTime字段 */
private Long dataTime;
/**
* 通过命令上传的数据
*/
private Map<String, String> dataMap;
public String getQn() {
return qn;
}
public void setQn(String qn) {
this.qn = qn;
}
public String getSt() {
return st;
}
public void setSt(String st) {
this.st = st;
}
public String getCn() {
return cn;
}
public void setCn(String cn) {
this.cn = cn;
}
public String getPw() {
return pw;
}
public void setPw(String pw) {
this.pw = pw;
}
public String getMn() {
return mn;
}
public void setMn(String mn) {
this.mn = mn;
}
public Integer getFlag() {
return flag;
}
public void setFlag(Integer flag) {
this.flag = flag;
}
public String getCp() {
return cp;
}
public void setCp(String cp) {
this.cp = cp;
}
public Long getDataTime() {
return dataTime;
}
public void setDataTime(Long dataTime) {
this.dataTime = dataTime;
}
public Map<String, String> getDataMap() {
return dataMap;
}
public void setDataMap(Map<String, String> dataMap) {
this.dataMap = dataMap;
}
}

View File

@ -0,0 +1,124 @@
package com.cisdi.data.HJ212.gateway;
import java.util.Map;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import com.alibaba.fastjson.JSON;
import com.cisdi.data.sdk.consts.ServiceName;
import com.cisdi.data.sdk.gateway.message.SocketMessage;
import com.cisdi.data.sdk.gateway.netty.IoSession;
import com.cisdi.data.sdk.gateway.netty.impl.AbstractIoSession;
import com.cisdi.data.sdk.service.SendService;
import com.google.common.collect.Maps;
import io.netty.buffer.ByteBuf;
import io.netty.buffer.Unpooled;
/**
*
* <p>Title: Hj212IoSession.java</p>
* @author lhp
* @date 2021年05月13日
* @version 1.0
*/
public class Hj212IoSession extends AbstractIoSession implements IoSession {
private long lastAliveTime = System.currentTimeMillis();
private static Logger logger = LoggerFactory.getLogger(Hj212IoSession.class);
private String deviceId = null;
public Hj212IoSession(String deviceId) {
this.deviceId = deviceId;
}
@Override
public void onRead(Object message) {
int length = ((ByteBuf)message).readableBytes();
ByteBuf inBuf = (ByteBuf)message;
Hj212FrameInputVo vo = Hj212VoDecode.Decode(inBuf);
if(socketGateway!= null && Boolean.TRUE.equals(socketGateway.getInstanceVo().getLogOpen())) {
logger.info("hj212 {} 报文长度:{} vo:{} ", getChannel(), length, JSON.toJSONString(vo));
}
//发送的真正电文数据
Map<String, Object> realDataMap = Maps.newHashMap(vo.getDataMap());
realDataMap.put("dataTime", vo.getDataTime());
realDataMap.put("mn", vo.getMn());
realDataMap.put("qn", vo.getQn());
realDataMap.put("cn", vo.getCn());
String msgKey = String.format("%s_%s", vo.getMn(), vo.getCn());
if(vo != null && serviceProvider != null && socketGateway != null) {
SendService service = (SendService)serviceProvider.getByName(ServiceName.Send);
SocketMessage socketMessage = socketGateway.buildSocketMessage();
socketMessage.setDeviceId(deviceId);
socketMessage.setData(JSON.toJSONString(realDataMap).getBytes(CRC16Util.UTF8));
socketMessage.setMsgKey(msgKey);
service.sendMessage(socketMessage);
}else {
logger.info("hj212收到 msgkey: {} 消息:{}",msgKey, JSON.toJSONString(realDataMap));
}
byte[] backBodys = Hj212VoEncoder.encode(vo.getSt(), vo.getCn(), vo.getPw(), vo.getMn());
ByteBuf wrappedBuffer = Unpooled.wrappedBuffer(backBodys);
getChannel().writeAndFlush(wrappedBuffer);
lastAliveTime = System.currentTimeMillis();
}
@Override
public void onOpen() {
super.onOpen();
logger.info("建立连接channel:{}", getChannel());
}
@Override
public void onClose() {
super.onClose();
}
public void close() {
if(getChannel() != null) {
try {
getChannel().close().sync();
} catch (InterruptedException e) {
logger.warn(e.getLocalizedMessage(), e);
}
}
}
private String gwPrefixCache = null;
public String gwPrefix() {
if(gwPrefixCache != null) {
return gwPrefixCache;
}
gwPrefixCache = "";
if(socketGateway != null && socketGateway.getInstanceVo() != null) {
gwPrefixCache = "网关Id:" + socketGateway.getInstanceVo().getRunId() + "连接:" + getChannel() + " ";
}else {
gwPrefixCache = "连接:" + getChannel() + " ";
}
return gwPrefixCache;
}
public long getLastAliveTime() {
return lastAliveTime;
}
@Override
public String[] getDeviceIds() {
String cpDeviceId = deviceId;
String[] result = new String[cpDeviceId == null ? 0 : 1];
if(cpDeviceId != null) {
result[0] = cpDeviceId;
}
return result;
}
}

View File

@ -0,0 +1,22 @@
package com.cisdi.data.HJ212.gateway;
import java.util.UUID;
import com.cisdi.data.sdk.gateway.netty.IoSession;
import com.cisdi.data.sdk.gateway.netty.impl.AbstractSessionFactory;
public class Hj212SessionFactory extends AbstractSessionFactory {
private String deviceId;
public Hj212SessionFactory(String deviceId) {
this.deviceId = deviceId;
}
@Override
public IoSession newSession() {
IoSession session = new Hj212IoSession(deviceId);
session.init(UUID.randomUUID().toString(), provider, socketGateway);
sessionSet.add(session);
return session;
}
}

View File

@ -0,0 +1,117 @@
package com.cisdi.data.HJ212.gateway;
import java.util.HashMap;
import java.util.Map;
import org.apache.tomcat.util.buf.HexUtils;
import org.apache.tomcat.util.buf.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import com.alibaba.fastjson.JSON;
import com.cisdi.data.common.exception.BusinessException;
import com.cisdi.data.common.utils.Strings;
import io.netty.buffer.ByteBuf;
import io.netty.buffer.Unpooled;
public class Hj212VoDecode {
private static final Logger log = LoggerFactory.getLogger(Hj212VoDecode.class);
public static Hj212FrameInputVo Decode(ByteBuf in) {
byte[] bytes = new byte[in.readableBytes()];
in.readBytes(bytes);
String message = new String(bytes, CRC16Util.UTF8);
String body = message.substring(6, message.length() - 6);
String end = message.substring(message.length() - 6, message.length());
String crcParameter = end.substring(0, 4);
String crcResult = CRC16Util.CRC16(body);
if(Strings.equalsIgnoreCase(crcParameter, crcResult) == false){
log.error("hj212 crc16 check fail, input:{}, input-crc:{},cal-crc:{}", body, crcParameter, crcResult);
throw new BusinessException("crc16 check fail input-crc=" + crcParameter);
}
// 解析body字段
// 字段与其值用=连接在数据区中同一项目的不同分类值间用来分隔不同项目之间用来分隔
Map<String, String> map = new HashMap<String, String>();
String[] bodyItems = Strings.split(body.substring(0,body.length()-2), ';');
for (String item : bodyItems) {
if(item.contains(",")) {
String[] itemBodys = Strings.split(item, ',');
for (String subItem : itemBodys) {
if(subItem.contains("=")) {
int indexOp = subItem.indexOf('=');
map.put(subItem.substring(0, indexOp), subItem.substring(indexOp + 1));
}
}
}else if(item.contains("=")) {
int indexOp = item.indexOf('=');
map.put(item.substring(0, indexOp), item.substring(indexOp + 1));
}
}
Hj212FrameInputVo value = new Hj212FrameInputVo();
value.setCn(map.get("CN"));
value.setQn(map.get("QN"));
value.setSt(map.get("ST"));
value.setPw(map.get("PW"));
value.setMn(map.get("MN"));
if(map.containsKey("Flag")){
value.setFlag(Integer.valueOf(map.get("Flag")));
}
value.setCp(map.get("CP").substring(2));
// &&DataTime=20190425110800
int indexDt = value.getCp().indexOf("DataTime");
if(indexDt >= 0) {
value.setDataTime(Long.valueOf(value.getCp().substring(indexDt + 9, indexDt + 9 + 14)));
}
map.remove("CN");
map.remove("QN");
map.remove("ST");
map.remove("PW");
map.remove("MN");
map.remove("Flag");
map.remove("CP");
value.setDataMap(map);
return value;
}
public static void main(String[] args) {
// 实时数据
// String input = "##0365QN=20190425110900000;ST=22;CN=2011;PW=123456;MN=01004190001003;Flag=5;CP=&&DataTime=20190425110800;a01001-Rtd=0.0,a01001-Flag=N;a01002-Rtd=0.0,a01002-Flag=N;a01006-Rtd=101.09,a01006-Flag=N;a01007-Rtd=0.0,a01007-Flag=N;a01008-Rtd=0,a01008-Flag=N;a34001-Rtd=0.0,a34001-Flag=N;a34002-Rtd=17.8,a34002-Flag=N;a34004-Rtd=7.7,a34004-Flag=N;a50001-Rtd=30.0,a50001-Flag=N;&&0880\r\n";
// String input="##0102QN=20211207181139971;ST=31;CN=1011;PW=123456;MN=YFLGZXJCLT0003;Flag=1;CP=&&SystemTime=20211207181139&&4980\r\n";
// String input="##0453QN=20211207181137957;ST=31;CN=2051;PW=123456;MN=YFLGZXJCLT0003;CP=&&DataTime=20211207180000;01-ZsAvg=1.38,01-ZsMin=1.25,01-ZsMax=1.54,01-Cou=0.18,01-Avg=1.38,01-Min=1.25,01-Max=1.54;B02-Cou=130926.47,B02-Avg=218.21,B02-Min=206.41,B02-Max=230.95;S03-Avg=16.38,S03-Min=16.30,S03-Max=16.44;S05-Avg=2.31,S05-Min=2.31,S05-Max=2.32;S08-Avg=-0.16,S08-Min=-0.17,S08-Max=-0.14;S02-Avg=12.08,S02-Min=11.42,S02-Max=12.79;S01-Avg=21.17,S01-Min=21.16,S01-Max=21.18&&5280\r\n";
// String input="##0279QN=20211207181240386;ST=31;CN=2011;PW=123456;MN=YFLGZXJCLT0003;CP=&&DataTime=20211207181148;01-ZsRtd=1.32,01-Rtd=1.32,01-Flag=N;B02-Rtd=225.99,B02-Flag=N;S03-Rtd=16.29,S03-Flag=N;S05-Rtd=2.31,S05-Flag=N;S08-Rtd=-0.16,S08-Flag=N;S02-Rtd=12.51,S02-Flag=N;S01-Rtd=21.16,S01-Flag=N&&7940\r\n";
// String input="##0275QN=20211208195054384;ST=31;CN=2011;PW=123456;MN=SD371300004744;CP=&&DataTime=20211208194952;01-ZsRtd=0.52,01-Rtd=0.52,01-Flag=N;B02-Rtd=38.10,B02-Flag=N;S03-Rtd=8.66,S03-Flag=N;S05-Rtd=1.23,S05-Flag=N;S08-Rtd=0.00,S08-Flag=N;S02-Rtd=1.20,S02-Flag=N;S01-Rtd=21.61,S01-Flag=N&&4040\r\n";
// String input="##0102QN=20211208194951184;ST=31;CN=1011;PW=123456;MN=SD371300004744;Flag=1;CP=&&SystemTime=20211208194951&&7F80\r\n";
// String input="##0275QN=20211208194952060;ST=31;CN=2011;PW=123456;MN=SD371300004744;CP=&&DataTime=20211208194853;01-ZsRtd=0.52,01-Rtd=0.52,01-Flag=N;B02-Rtd=38.09,B02-Flag=N;S03-Rtd=8.65,S03-Flag=N;S05-Rtd=1.26,S05-Flag=N;S08-Rtd=0.00,S08-Flag=N;S02-Rtd=1.20,S02-Flag=N;S01-Rtd=21.61,S01-Flag=N&&5000\r\n";
String input="##0441QN=20211208195157432;ST=31;CN=2051;PW=123456;MN=SD371300004744;CP=&&DataTime=20211208194000;01-ZsAvg=0.52,01-ZsMin=0.52,01-ZsMax=0.52,01-Cou=0.01,01-Avg=0.52,01-Min=0.52,01-Max=0.52;B02-Cou=22469.20,B02-Avg=37.45,B02-Min=34.90,B02-Max=38.10;S03-Avg=8.66,S03-Min=8.65,S03-Max=8.68;S05-Avg=1.27,S05-Min=1.23,S05-Max=1.29;S08-Avg=0.00,S08-Min=-0.01,S08-Max=0.00;S02-Avg=1.18,S02-Min=1.10,S02-Max=1.20;S01-Avg=21.61,S01-Min=21.60,S01-Max=21.62&&F9C1\r\n";
ByteBuf wrappedBuffer = Unpooled.wrappedBuffer(input.getBytes(CRC16Util.UTF8));
Hj212FrameInputVo decode = Hj212VoDecode.Decode(wrappedBuffer);
wrappedBuffer.release();
System.out.println(JSON.toJSONString(decode));
// String inputDay = "##0638QN=20190425104000000;ST=22;CN=2051;PW=123456;MN=0100410001003;Flag=5;CP=&&DataTime=20190425104000;a01001-Min=0.0,a01001-Avg=0.0,a01001-Max=0.0,a01001-Flag=N;a01002-Min=0.0,a01002-Avg=0.0,a01002-Max=0.0,a01002-Flag=N;a01006-Min=0.00,a01006-Avg=101.08,a01006-Max=101.08,a01006-Flag=N;a01007-Min=0.0,a01007-Avg=0.0,a01007-Max=0.0,a01007-Flag=N;a01008-Min=0,a01008-Avg=0,a01008-Max=0,a01008-Flag=N;a34001-Min=0.0,a34001-Avg=0.0,a34001-Max=0.0,a34001-Flag=N;a34002-Min=0.0,a34002-Avg=21.6,a34002-Max=35.2,a34002-Flag=N;a34004-Min=0.0,a34004-Avg=10.8,a34004-Max=22.7,a34004-Flag=N;a50001-Min=0.0,a50001-Avg=30.0,a50001-Max=30.0,a50001-Flag=N;&&5B40\r\n";
// wrappedBuffer = Unpooled.wrappedBuffer(inputDay.getBytes(CRC16Util.UTF8));
// decode = Hj212VoDecode.Decode(wrappedBuffer);
// wrappedBuffer.release();
// System.out.println(JSON.toJSONString(decode));
// // 实时数据
// String inputTest = "##0365QN=20190425110900000;ST=22;CN=2011;PW=123456;MN=01004190001003;Flag=5;CP=&&DataTime=20190425110800;a01001-Rtd=0.0,a01001-Flag=N;a01002-Rtd=0.0,a01002-Flag=N;a01006-Rtd=101.09,a01006-Flag=N;a01007-Rtd=0.0,a01007-Flag=N;a01008-Rtd=0,a01008-Flag=N;a34001-Rtd=0.0,a34001-Flag=N;a34002-Rtd=17.8,a34002-Flag=N;a34004-Rtd=7.7,a34004-Flag=N;a50001-Rtd=30.0,a50001-Flag=N;&&0880\r\n";
// byte[] inputTestBytes = inputTest.getBytes(CRC16Util.UTF8);
// String hexString = HexUtils.toHexString(inputTestBytes);
// System.out.print(hexString);
}
}

View File

@ -0,0 +1,47 @@
package com.cisdi.data.HJ212.gateway;
import java.nio.charset.StandardCharsets;
import java.text.DateFormat;
import java.text.SimpleDateFormat;
import java.util.Date;
public class Hj212VoEncoder {
private static DateFormat qnFormat = new SimpleDateFormat("yyyyMMddHHmmssSSS");
public static byte[] encode(String st, String cn, String pw, String mn) {
String flag = "4";
String asciiString = combineAsciiString(null, st, cn, pw, mn, flag);
return asciiString.getBytes(StandardCharsets.US_ASCII);
}
private static String combineAsciiString(String qn, String st, String cn, String pw, String mn, String flag) {
Date date = new Date();
StringBuilder builder = new StringBuilder();
builder.append(String.format("QN=%s;", qn == null ? qnFormat.format(date) : qn));
builder.append(String.format("ST=%s;", st));
builder.append(String.format("CN=%s;", cn));
builder.append(String.format("PW=%s;", pw));
builder.append(String.format("MN=%s;", mn));
builder.append(String.format("Flag=%s;", flag));
builder.append("CP=&&&&");
String dataBody = builder.toString();
int dataLength = builder.toString().length();
builder.insert(0, String.format("##%04d", dataLength));
String crc16 = CRC16Util.CRC16(dataBody);
builder.append(crc16 + "\r\n");
return builder.toString();
}
public static void main(String[] args) {
String combine1 = combineAsciiString("20190425110917290", "22", "9014", "123456", "01004190001003", "4");
System.out.println(combine1);
String combine2 = combineAsciiString("20190425110913469", "22", "9014", "123456", "0100410001003", "4");
System.out.println(combine2);
}
}

View File

@ -0,0 +1,62 @@
package com.cisdi.data.HJ212.gateway;
import java.util.concurrent.atomic.AtomicBoolean;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import com.cisdi.data.HJ212.YfHj212SocketGateway;
import com.cisdi.data.sdk.enums.ByteOrder;
import com.cisdi.data.sdk.gateway.netty.SessionFactory;
import com.cisdi.data.sdk.gateway.netty.TcpIoService;
import com.cisdi.data.sdk.gateway.netty.impl.DefaultTcpIoService;
import com.cisdi.data.sdk.vo.GatewayVo;
public class StartHj212Test {
private static Logger logger = LoggerFactory.getLogger(YfHj212SocketGateway.class);
private static TcpIoService ioService = null;
@SuppressWarnings("unused")
private static SessionFactory sessionFactory = null;
public static void main(String[] args) {
DefaultTcpIoService defaultIoService = new DefaultTcpIoService();
SessionFactory factory = new Hj212SessionFactory("10000022");
factory.init(null, null);
Hj212ChannelInitializer<Hj212FrameInputVo> channelInitializer =
new Hj212ChannelInitializer<Hj212FrameInputVo>(factory);
GatewayVo instanceVo = new GatewayVo();
instanceVo.setByteOrder(ByteOrder.BIGENDIAN);
instanceVo.setParameter("{\"listenIp\":\"0.0.0.0\",\"listenPort\":9010,\"threadSize\":50,\"timeout\":2000}");
defaultIoService.init(instanceVo, factory, channelInitializer);
ioService = defaultIoService;
sessionFactory = factory;
boolean open = ioService.open();
if(open == true) {
AtomicBoolean shouldRun = new AtomicBoolean(true);
AliveCheckTask task = new AliveCheckTask(120, shouldRun, factory);
Thread thread = new Thread(task, "Hj212-alive-check-thread");
thread.start();
logger.info("Hj212网关启动成功");
}else {
logger.info("Hj212网关启动失败");
}
try {
Thread.sleep(10000000);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}

View File

@ -0,0 +1,100 @@
package com.cisdi.data.IDCardReader;
import com.alibaba.fastjson.JSON;
import com.cisdi.data.IDCardReader.gateway.impl.ZKIDROnlineClient;
import com.cisdi.data.IDCardReader.gateway.impl.ZKIDROnlineListener;
import com.cisdi.data.IDCardReader.gateway.vo.ZKIDROnlineConfigVo;
import com.cisdi.data.IDCardReader.gateway.vo.ZKIDROnlineResponseVo;
import com.cisdi.data.common.exception.BusinessException;
import com.cisdi.data.emserver.EmiaProSocketGateway;
import com.cisdi.data.sdk.consts.ServiceName;
import com.cisdi.data.sdk.enums.GatewayState;
import com.cisdi.data.sdk.gateway.base.SocketGatewayBase;
import com.cisdi.data.sdk.param.ListenSocketParam;
import com.cisdi.data.sdk.procotol.message.SocketReturnMessage;
import com.cisdi.data.sdk.service.RouteService;
import com.cisdi.data.sdk.vo.DeviceVo;
import com.cisdi.data.sdk.vo.ExeResultVo;
import com.google.common.collect.Sets;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.util.List;
import java.util.Set;
public class IDCardReaderGateway extends SocketGatewayBase {
private static Logger logger = LoggerFactory.getLogger(IDCardReaderGateway.class);
private ZKIDROnlineClient zkidrOnlineClient=null;
private String deviceId;
@Override
public ExeResultVo sendReturnMessage(SocketReturnMessage returnMsg) {
ExeResultVo resultVo = new ExeResultVo();
resultVo.setMessage("该协议不允许下发数据");
resultVo.setSuccess(false);
logger.info("网关:{}->设备,消息:{},结果:{}",instanceVo.getRunId(), returnMsg, resultVo);
return resultVo;
}
@Override
public void start() {
if (state == GatewayState.RUNNING) {
return;
}
ListenSocketParam socketParam = JSON.parseObject(getInstanceVo().getParameter(), ListenSocketParam.class);
String otherParameter = socketParam.getOtherParameter();
ZKIDROnlineConfigVo zkidrOnlineConfigVo = null;
// 处理分组
if (StringUtils.isNotBlank(otherParameter)) {
zkidrOnlineConfigVo = JSON.parseObject(otherParameter, ZKIDROnlineConfigVo.class);
}
if (zkidrOnlineConfigVo == null) {
throw new BusinessException("网关Id:" + instanceVo.getRunId() + "为ZKIDROnline网关请配置正确的ZKIDROnline配置");
}
RouteService routeService = (RouteService) serviceProvider.getByName(ServiceName.Route);
List<DeviceVo> deviceVos = routeService.findByRunId(instanceVo.getRunId());
if (deviceVos.size() > 1) {
throw new BusinessException("网关Id:" + instanceVo.getRunId() + "为ZKIDROnline网关只允许关联一个设备Id");
}
deviceId = deviceVos.size() > 0 ? deviceVos.get(0).getDeviceId() : null;
if (StringUtils.isEmpty(deviceId)) {
throw new BusinessException("runId=" + getInstanceVo().getRunId() + "未正确配置网关和设备关联");
}
logger.info("ZKIDROnline网关:{}读取启动配置参数:{}", instanceVo.getRunId(), getInstanceVo().getParameter());
zkidrOnlineClient=new ZKIDROnlineClient(deviceId,serviceProvider,this,zkidrOnlineConfigVo);
Thread thread=new Thread(zkidrOnlineClient);
thread.start();
state = GatewayState.RUNNING;
}
@Override
public void shutdown() {
if (state == GatewayState.CLOSED) {
return;
}
if(zkidrOnlineClient.close())
{
state=GatewayState.CLOSED;
logger.info("网关:" + instanceVo.getRunId() + "关闭成功", instanceVo.getRunId());
}
}
@Override
public Set<String> getActiveDeviceIds() {
Set<String> set = Sets.newConcurrentHashSet();
if (StringUtils.isNotEmpty(deviceId)) {
set.add(deviceId);
}
return set;
}
}

File diff suppressed because one or more lines are too long

View File

@ -0,0 +1,80 @@
package com.cisdi.data.IDCardReader.gateway.impl;
import com.cisdi.data.IDCardReader.gateway.vo.ZKIDROnlineConfigVo;
import com.cisdi.data.sdk.gateway.base.SocketGatewayBase;
import com.cisdi.data.sdk.service.ServiceProvider;
import org.java_websocket.client.WebSocketClient;
import org.java_websocket.drafts.Draft;
import org.java_websocket.handshake.ServerHandshake;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.net.URI;
import java.net.URISyntaxException;
import java.util.Map;
import java.util.concurrent.atomic.AtomicBoolean;
public class ZKIDROnlineClient implements Runnable{
private String deviceId;
ServiceProvider serviceProvider;
SocketGatewayBase socketGateway;
private ZKIDROnlineConfigVo zkidrOnlineConfigVo;
private ZKIDROnlineListener zkidrOnlineListener=null;
private Logger logger= LoggerFactory.getLogger(ZKIDROnlineClient.class);
private AtomicBoolean shouldRun=new AtomicBoolean(true);
private Boolean isOpen=false;
public Boolean getOpen() {
return isOpen;
}
public Boolean close()
{
zkidrOnlineListener.setShouldRun(false);
shouldRun.set(false);
return zkidrOnlineListener.endListen();
}
public ZKIDROnlineClient(String deviceId, ServiceProvider serviceProvider, SocketGatewayBase socketGateway, ZKIDROnlineConfigVo zkidrOnlineConfigVo) {
this.deviceId = deviceId;
this.serviceProvider = serviceProvider;
this.socketGateway = socketGateway;
this.zkidrOnlineConfigVo = zkidrOnlineConfigVo;
}
@Override
public void run() {
while (shouldRun.get())
{
try {
zkidrOnlineListener=new ZKIDROnlineListener(new URI(zkidrOnlineConfigVo.getUri()),deviceId,socketGateway,serviceProvider,zkidrOnlineConfigVo);
logger.info("ZKIDROnline网关:{}启动成功 参数:{}", socketGateway.getInstanceVo().getRunId(), socketGateway.getInstanceVo().getParameter());
break;
} catch (URISyntaxException e) {
logger.error("连接ID:"+socketGateway.getInstanceVo().getRunId()+"设备ID:"+deviceId+",自动重连设置:"+zkidrOnlineConfigVo.getAutoReconnect()+"启动失败,错误原因:"+e.getMessage());
try {
Thread.sleep(zkidrOnlineConfigVo.getReconnectDelay());
} catch (InterruptedException e1) {
e1.printStackTrace();
}
if(zkidrOnlineConfigVo.getAutoReconnect())
{
logger.info("连接ID:"+socketGateway.getInstanceVo().getRunId()+"设备ID:"+deviceId+",自动重连设置:"+zkidrOnlineConfigVo.getAutoReconnect()+"启动失败,正在重连");
}
else
{
logger.info("ZKIDROnline网关:{}启动失败 参数:{}", socketGateway.getInstanceVo().getRunId(), socketGateway.getInstanceVo().getParameter());
break;
}
}
}
if(zkidrOnlineListener!=null) {
zkidrOnlineListener.start(false);
isOpen=true;
return ;
}
}
}

View File

@ -0,0 +1,224 @@
package com.cisdi.data.IDCardReader.gateway.impl;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.cisdi.data.IDCardReader.gateway.vo.IDCardVo;
import com.cisdi.data.IDCardReader.gateway.vo.ZKIDROnlineConfigVo;
import com.cisdi.data.IDCardReader.gateway.vo.ZKIDROnlineResponseVo;
import com.cisdi.data.sdk.consts.ServiceName;
import com.cisdi.data.sdk.gateway.Gateway;
import com.cisdi.data.sdk.gateway.base.GatewayBase;
import com.cisdi.data.sdk.gateway.base.SocketGatewayBase;
import com.cisdi.data.sdk.gateway.message.SocketMessage;
import com.cisdi.data.sdk.service.SendService;
import com.cisdi.data.sdk.service.ServiceProvider;
import org.java_websocket.WebSocket;
import org.java_websocket.client.WebSocketClient;
import org.java_websocket.handshake.ServerHandshake;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.net.URI;
import java.nio.charset.Charset;
import java.util.concurrent.atomic.AtomicBoolean;
public class ZKIDROnlineListener extends WebSocketClient {
private Integer reconnectCount=0;
private String runId;
private String deviceId;
private Boolean autoReconnect=false;
private Long reconnectDelay =1000L;
private ServiceProvider serviceProvider=null;
private SocketGatewayBase socketGatewayBase=null;
private Logger logger= LoggerFactory.getLogger(ZKIDROnlineListener.class);
private ZKIDROnlineConfigVo zkidrOnlineConfigVo=null;
private Boolean startFlag=false;
private static final String SUCCESS_STR="BeginReadCard Succsefull";
private AtomicBoolean shouldRun=new AtomicBoolean(true);
public void setShouldRun(boolean b)
{
shouldRun.set(b);
}
public ZKIDROnlineListener(URI serverUri,
String deviceId,
SocketGatewayBase socketGateway,
ServiceProvider serviceProvider,
ZKIDROnlineConfigVo zkidrOnlineConfigVo) {
super(serverUri);
if(socketGateway!=null)
{
this.runId=socketGateway.getInstanceVo().getRunId();
}
if(zkidrOnlineConfigVo!=null)
{
this.autoReconnect=zkidrOnlineConfigVo.getAutoReconnect();
this.reconnectDelay =zkidrOnlineConfigVo.getReconnectDelay();
}
this.deviceId=deviceId;
this.socketGatewayBase=socketGateway;
this.serviceProvider=serviceProvider;
this.zkidrOnlineConfigVo=zkidrOnlineConfigVo;
}
public Boolean endListen()
{
startFlag=false;
autoReconnect=false;
this.close();
return true;
}
public boolean start(boolean reconnect)
{
startFlag=false;
while (shouldRun.get())
{
try
{
if(this.getReadyState().equals(READYSTATE.NOT_YET_CONNECTED))
{
logger.info("连接ID:"+runId+"设备ID:"+deviceId+",自动重连设置:"+autoReconnect+"状态为:"+this.getReadyState()+"准备尝试连接");
if(!this.connectBlocking())
{
return false;
}
logger.info("连接ID:"+runId+"设备ID:"+deviceId+",自动重连设置:"+autoReconnect+"正在发送启动消息:"+zkidrOnlineConfigVo.getStartMsg());
this.send(zkidrOnlineConfigVo.getStartMsg());
return true;
}
else if(this.getReadyState().equals(READYSTATE.CLOSED)||this.getReadyState().equals(READYSTATE.CLOSING))
{
logger.info("连接ID:"+runId+"设备ID:"+deviceId+",自动重连设置:"+autoReconnect+"状态为:"+this.getReadyState()+"准备尝试重连");
if(!this.reconnectBlocking())
{
return false;
}
logger.info("连接ID:"+runId+"设备ID:"+deviceId+",自动重连设置:"+autoReconnect+"正在发送启动消息:"+zkidrOnlineConfigVo.getStartMsg());
this.send(zkidrOnlineConfigVo.getStartMsg());
return true;
}
}
catch (Exception e)
{
logger.error("连接ID:"+socketGatewayBase.getInstanceVo().getRunId()+"设备ID:"+deviceId+",自动重连设置:"+zkidrOnlineConfigVo.getAutoReconnect()+"启动失败,错误原因:"+e.getLocalizedMessage());
try {
Thread.sleep(zkidrOnlineConfigVo.getReconnectDelay());
} catch (InterruptedException e1) {
e1.printStackTrace();
}
if(reconnect)
{
logger.info("连接ID:"+socketGatewayBase.getInstanceVo().getRunId()+"设备ID:"+deviceId+",自动重连设置:"+zkidrOnlineConfigVo.getAutoReconnect()+"启动失败,正在重连");
}
else
{
break;
}
}
}
return false;
}
@Override
public void onOpen(ServerHandshake handshakedata) {
logger.info("连接ID:"+runId+"设备ID:"+deviceId+",自动重连设置:"+autoReconnect+"已经打开连接");
}
@Override
public void onMessage(String message) {
if(startFlag)
{
IDCardVo idCardVo=null;
try
{
idCardVo= JSON.parseObject(message,IDCardVo.class);
idCardVo.getCertificate().setReadID(deviceId);
idCardVo.getCertificate().setReadTime(System.currentTimeMillis()+"");
}
catch (Exception e)
{
logger.error("连接ID:"+runId+"设备ID:"+deviceId+",自动重连设置:"+autoReconnect+"解析数据发生异常:"+e.getLocalizedMessage());
}
if(idCardVo!=null&&serviceProvider!=null&&socketGatewayBase!=null)
{
SendService service = (SendService)serviceProvider.getByName(ServiceName.Send);
SocketMessage socketMessage = socketGatewayBase.buildSocketMessage();
socketMessage.setDeviceId(this.deviceId);
socketMessage.setMsgKey("default");
socketMessage.setData(JSON.toJSONString(idCardVo.getCertificate()).getBytes());
socketMessage.getPropsMap().put("charset", Charset.forName("GBK"));
service.sendMessage(socketMessage);
if(socketGatewayBase.getInstanceVo().getLogOpen())
{
logger.error("连接ID:"+runId+"设备ID:"+deviceId+",自动重连设置:"+autoReconnect+"收到数据:"+idCardVo.getCertificate());
}
}
}
else
{
ZKIDROnlineResponseVo zkidrOnlineResponseVo=null;
try
{
zkidrOnlineResponseVo= JSON.parseObject(message,ZKIDROnlineResponseVo.class);
}
catch (Exception e)
{
logger.error("连接ID:"+runId+"设备ID:"+deviceId+",自动重连设置:"+autoReconnect+"收到无法解析的数据:"+message);
}
if(zkidrOnlineResponseVo!=null&&SUCCESS_STR.equals(zkidrOnlineResponseVo.getData()))
{
logger.info("连接ID:"+runId+"设备ID:"+deviceId+",自动重连设置:"+autoReconnect+"请求自动获取身份证信息成功");
startFlag=true;
}
else
{
//this.close();
this.start(true);
}
}
}
@Override
public void onClose(int code, String reason, boolean remote) {
if(startFlag&&remote)
{
logger.info("连接ID:"+runId+"设备ID:"+deviceId+",自动重连设置:"+autoReconnect+"正在尝试重连");
//this.close();
this.start(true);
}
else
{
logger.info("连接ID:"+runId+"设备ID:"+deviceId+",自动重连设置:"+autoReconnect+"正在关闭连接");
}
}
@Override
public void onError(Exception ex) {
logger.error("连接ID:"+runId+"设备ID:"+deviceId+",自动重连设置:"+autoReconnect+"发生异常:"+ex.getLocalizedMessage());
if(autoReconnect)
{
try
{
Thread.sleep(reconnectDelay);
}
catch (InterruptedException e)
{
e.printStackTrace();
}
logger.info("连接ID:"+runId+"设备ID:"+deviceId+",自动重连设置:"+autoReconnect+"正在尝试重连");
//this.close();
this.start(true);
}
else
{
logger.warn("连接ID:"+runId+"设备ID:"+deviceId+",自动重连设置:"+autoReconnect+"未配置重连,连接关闭");
}
}
}

View File

@ -0,0 +1,60 @@
package com.cisdi.data.IDCardReader.gateway.vo;
public class IDCardVo {
public class IDCardDataVo{
private String IDNumber;
private String Name;
private String ReadID;
private String ReadTime;
public String getIDNumber() {
return IDNumber;
}
public void setIDNumber(String IDNumber) {
this.IDNumber = IDNumber;
}
public String getName() {
return Name;
}
public void setName(String name) {
Name = name;
}
public String getReadID() {
return ReadID;
}
public void setReadID(String readID) {
ReadID = readID;
}
public String getReadTime() {
return ReadTime;
}
public void setReadTime(String readTime) {
ReadTime = readTime;
}
}
private Integer ret;
private IDCardDataVo Certificate;
public Integer getRet() {
return ret;
}
public void setRet(Integer ret) {
this.ret = ret;
}
public IDCardDataVo getCertificate() {
return Certificate;
}
public void setCertificate(IDCardDataVo certificate) {
Certificate = certificate;
}
}

View File

@ -0,0 +1,42 @@
package com.cisdi.data.IDCardReader.gateway.vo;
import com.alibaba.fastjson.JSONObject;
public class ZKIDROnlineConfigVo {
private String uri;
private Boolean autoReconnect;
private String startMsg;
private Long reconnectDelay;
public String getStartMsg() {
return startMsg;
}
public void setStartMsg(String startMsg) {
this.startMsg = startMsg;
}
public Long getReconnectDelay() {
return reconnectDelay;
}
public void setReconnectDelay(Long reconnectDelay) {
this.reconnectDelay = reconnectDelay;
}
public String getUri() {
return uri;
}
public void setUri(String uri) {
this.uri = uri;
}
public Boolean getAutoReconnect() {
return autoReconnect;
}
public void setAutoReconnect(Boolean autoReconnect) {
this.autoReconnect = autoReconnect;
}
}

View File

@ -0,0 +1,31 @@
package com.cisdi.data.IDCardReader.gateway.vo;
public class ZKIDROnlineResponseVo {
private String data;
private String dev;
private String ret;
public String getData() {
return data;
}
public void setData(String data) {
this.data = data;
}
public String getDev() {
return dev;
}
public void setDev(String dev) {
this.dev = dev;
}
public String getRet() {
return ret;
}
public void setRet(String ret) {
this.ret = ret;
}
}

View File

@ -0,0 +1,145 @@
package com.cisdi.data.OBLF;
import com.alibaba.fastjson.JSON;
import com.cisdi.data.OBLF.impl.OBLFChannelInitializer;
import com.cisdi.data.OBLF.impl.OBLFIoSession;
import com.cisdi.data.OBLF.impl.OBLFSessionFactory;
import com.cisdi.data.common.exception.BusinessException;
import com.cisdi.data.sdk.consts.ServiceName;
import com.cisdi.data.sdk.enums.GatewayState;
import com.cisdi.data.sdk.gateway.base.SocketGatewayBase;
import com.cisdi.data.sdk.gateway.netty.IoSession;
import com.cisdi.data.sdk.gateway.netty.SessionFactory;
import com.cisdi.data.sdk.gateway.netty.TcpIoService;
import com.cisdi.data.sdk.gateway.netty.impl.DefaultTcpIoService;
import com.cisdi.data.sdk.param.ListenSocketParam;
import com.cisdi.data.sdk.procotol.message.SocketReturnMessage;
import com.cisdi.data.sdk.service.PlatformService;
import com.cisdi.data.sdk.service.RouteService;
import com.cisdi.data.sdk.vo.DeviceVo;
import com.cisdi.data.sdk.vo.ExeResultVo;
import com.cisdi.data.sdk.vo.SslConfigVo;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
/**
* @author cuianbing
* @version 1.0
* @description: 炼钢OBLF750设备
* @date 2021/7/21 11:33
*/
@Slf4j
public class OBLFSocketGateway extends SocketGatewayBase {
TcpIoService ioService = null;
SessionFactory sessionFactory = null;
// 当配置为单个设备模式时此为该设备id
String onlyOneDeviceId = null;
@Override
public ExeResultVo sendReturnMessage(SocketReturnMessage socketReturnMessage) {
throw new BusinessException("OBLF750不支持下发服务");
}
@Override
public void start() {
if (state == GatewayState.RUNNING) {
return;
}
log.info("网关:{}读取启动配置参数:{},是否支持支持多个设备:{}", instanceVo.getRunId(), instanceVo.getParameter(),
instanceVo.getSuportMultiDevice());
// 不支持多个设备必须强制配置一个设备id
if (instanceVo.getSuportMultiDevice() != null && instanceVo.getSuportMultiDevice() == false) {
RouteService routeService = (RouteService) serviceProvider.getByName(ServiceName.Route);
List<DeviceVo> deviceVos = routeService.findByRunId(instanceVo.getRunId());
if (deviceVos.size() > 1) {
throw new BusinessException("网关Id:" + instanceVo.getRunId() + "为OBLF750网关当前配置为只支持单个设备但配置了多个设备。");
}
onlyOneDeviceId = deviceVos.size() > 0 ? deviceVos.get(0).getDeviceId() : null;
if (StringUtils.isEmpty(onlyOneDeviceId)) {
throw new BusinessException("runId=" + getInstanceVo().getRunId() + "未正确配置网关和设备关联");
}
}
DefaultTcpIoService defaultIoService = new DefaultTcpIoService();
SessionFactory factory = new OBLFSessionFactory(onlyOneDeviceId);
factory.init(serviceProvider, this);
SslConfigVo sslConfigVo = null;
ListenSocketParam socketParam = JSON.parseObject(getInstanceVo().getParameter(), ListenSocketParam.class);
if (socketParam != null && Boolean.TRUE.equals(socketParam.getEnableSsl())) {
PlatformService platformService = (PlatformService) serviceProvider.getByName(ServiceName.Platform);
sslConfigVo = platformService.getSslConfig();
}
OBLFChannelInitializer channelInitializer =
new OBLFChannelInitializer(factory, getInstanceVo().getByteOrder(), sslConfigVo);
defaultIoService.init(instanceVo, factory, channelInitializer);
ioService = defaultIoService;
sessionFactory = factory;
boolean open = ioService.open();
if (open == true) {
state = GatewayState.RUNNING;
log.info("OBLF750网关:{}启动成功 参数:{}", instanceVo.getRunId(), getInstanceVo().getParameter());
} else {
log.info("OBLF750网关:{}启动失败 参数:{}", instanceVo.getRunId(), getInstanceVo().getParameter());
}
}
@Override
public void shutdown() {
if (state == GatewayState.CLOSED) {
return;
}
if (sessionFactory != null) {
for (IoSession ioSession : sessionFactory.getSessions()) {
OBLFIoSession XrfIoSession = (OBLFIoSession) ioSession;
XrfIoSession.close();
}
}
boolean close = ioService.close();
if (close == true) {
sessionFactory = null;
state = GatewayState.CLOSED;
log.info("OBLF750网关:{}关闭成功", instanceVo.getRunId());
} else {
log.info("OBLF750网关:{}关闭失败", instanceVo.getRunId());
}
}
@Override
public Set<String> getActiveDeviceIds() {
if (onlyOneDeviceId != null) {
Set<String> set = new HashSet<String>();
set.add(onlyOneDeviceId);
return set;
} else {
return sessionFactory.getActiveDeviceIds();
}
}
}

View File

@ -0,0 +1,75 @@
package com.cisdi.data.OBLF.impl;
import com.cisdi.data.sdk.enums.ByteOrder;
import com.cisdi.data.sdk.gateway.netty.SessionFactory;
import com.cisdi.data.sdk.gateway.netty.impl.AbstractChannelInitializer;
import com.cisdi.data.sdk.gateway.netty.impl.AbstractIoChannelHandler;
import com.cisdi.data.sdk.gateway.netty.impl.DefaultIoChannelHandler;
import com.cisdi.data.sdk.utils.NettySslUtils;
import com.cisdi.data.sdk.vo.SslConfigVo;
import io.netty.channel.Channel;
import io.netty.channel.ChannelHandler;
import io.netty.channel.socket.SocketChannel;
import io.netty.handler.timeout.IdleStateHandler;
import lombok.extern.slf4j.Slf4j;
import java.util.ArrayList;
import java.util.List;
/**
* @author cuianbing
* @version 1.0
* @description: TODO
* @date 2021/7/20 21:27
*/
@Slf4j
public class OBLFChannelInitializer<I> extends AbstractChannelInitializer<I> {
private SessionFactory factory;
private ByteOrder byteOrder;
private SslConfigVo sslConfigVo;
/**
* 构造通道初始化器对象
*
* @param factory 会话工厂
* @param byteOrder 大小端
* @param sslConfig ssl证书配置如果不启用tls传null
*/
public OBLFChannelInitializer(SessionFactory factory,
ByteOrder byteOrder,
SslConfigVo sslConfig) {
this.factory = factory;
this.byteOrder = byteOrder;
this.sslConfigVo = sslConfig;
}
@Override
protected AbstractIoChannelHandler<I> getTailHandler() {
return new DefaultIoChannelHandler(factory);
}
@Override
protected List<ChannelHandler> getHandlers() {
List<ChannelHandler> handlers = new ArrayList<ChannelHandler>();
return handlers;
}
@Override
protected IdleStateHandler getIdleStateHandler() {
return new IdleStateHandler(15, 15, 30);
}
@Override
protected ChannelHandler getSslChannelHandler(Channel socketChannel) {
ChannelHandler sslHandler = null;
try {
if (sslConfigVo != null) {
sslHandler = NettySslUtils.getServerSslHandler((SocketChannel) socketChannel, sslConfigVo);
}
} catch (Exception e) {
log.warn(e.getLocalizedMessage(), e);
}
return sslHandler;
}
}

View File

@ -0,0 +1,169 @@
package com.cisdi.data.OBLF.impl;
import com.alibaba.fastjson.JSON;
import com.cisdi.data.common.exception.BusinessException;
import com.cisdi.data.sdk.consts.ServiceName;
import com.cisdi.data.sdk.gateway.message.SocketMessage;
import com.cisdi.data.sdk.gateway.netty.IoSession;
import com.cisdi.data.sdk.gateway.netty.impl.AbstractIoSession;
import com.cisdi.data.sdk.service.PassthroughService;
import com.cisdi.data.sdk.service.SendService;
import io.netty.buffer.ByteBuf;
import io.netty.buffer.ByteBufAllocator;
import lombok.extern.slf4j.Slf4j;
import java.nio.charset.StandardCharsets;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.concurrent.atomic.AtomicInteger;
/**
* @author cuianbing
* @version 1.0
* @description: TODO
* @date 2021/7/20 21:28
*/
@Slf4j
public class OBLFIoSession extends AbstractIoSession implements IoSession {
private OBLFSessionFactory factory = null;
private String deviceId = null;
/**
* 如果有值代表所有会话都使用这一个设备id且允许多会话共享此一个设备id不除旧会话
*/
private final String onlyOneDeviceId;
private String gwPrefixCache = null;
private ByteBuf allBuf = ByteBufAllocator.DEFAULT.buffer();
public OBLFIoSession(OBLFSessionFactory factory, String onlyOneDeviceId) {
super();
this.factory = factory;
this.onlyOneDeviceId = onlyOneDeviceId;
}
@Override
public String[] getDeviceIds() {
String cpDeviceId = deviceId;
String[] result = new String[cpDeviceId == null ? 0 : 1];
if (cpDeviceId != null) {
result[0] = cpDeviceId;
}
return result;
}
@Override
public void onRead(Object message) {
try {
ByteBuf inBuf = (ByteBuf) message;
if (inBuf != null) {
allBuf.writeBytes(inBuf);
} else {
log.info("电文格式为空");
}
} catch (Exception e) {
log.error("电文格式错误!");
throw new BusinessException("电文格式错误!");
}
}
@Override
public void onOpen() {
super.onOpen();
log.info("建立连接channel:{}", getChannel());
}
@Override
public void onClose() {
log.info("onClose");
Map<String, String> message = decode(allBuf);
if (serviceProvider != null && socketGateway != null) {
SendService service = (SendService) serviceProvider.getByName(ServiceName.Send);
SocketMessage socketMessage = socketGateway.buildSocketMessage();
socketMessage.setDeviceId(onlyOneDeviceId);
socketMessage.setData(JSON.toJSONString(message).getBytes(StandardCharsets.UTF_8));
String analysisProgram = message.get("AnalysisProgram_");
if ("FE 4".equals(analysisProgram)) {
socketMessage.setMsgKey("iron");
} else {
socketMessage.setMsgKey("steel");
}
service.sendMessage(socketMessage);
if (socketGateway.getInstanceVo().getLogOpen()) {
log.info("类似为:{}:发送消息内容{}", message, message.toString());
}
}
super.onClose();
factory = null;
}
public void close() {
if (getChannel() != null) {
try {
getChannel().close().sync();
} catch (InterruptedException e) {
log.warn(e.getLocalizedMessage(), e);
}
}
}
@Override
public void onError(Throwable t) {
// 这里会出现 java.io.IOException: 远程主机强迫关闭了一个现有的连接
log.info("远程主机强迫关闭了一个现有的连接。");
// log.error("session exception:{}", t);
}
public Map<String, String> decode(ByteBuf byteBuf) {
List<Map<String, String>> dataList = new ArrayList<>();
AtomicInteger dataFlag = new AtomicInteger();
String msg = byteBuf.toString(StandardCharsets.UTF_8);
Map<String, String> data = JSON.parseObject(msg, Map.class);
log.debug("收到数据{}", data);
return data;
}
private void passThrough(ByteBuf passthroughBuf) {
try {
if (serviceProvider != null && socketGateway != null) {
PassthroughService service = (PassthroughService) serviceProvider.getByName(ServiceName.Passthrough);
service.transfer(passthroughBuf, socketGateway.getInstanceVo().getPassthroughAddress());
}
} catch (Exception e) {
log.error("协议透传失败:" + e.getLocalizedMessage(), e);
}
}
public String gwPrefix() {
if (gwPrefixCache != null) {
return gwPrefixCache;
}
gwPrefixCache = "";
if (socketGateway != null && socketGateway.getInstanceVo() != null) {
gwPrefixCache = "网关Id:" + socketGateway.getInstanceVo().getRunId() + "连接:" + getChannel() + " ";
} else {
gwPrefixCache = "连接:" + getChannel() + " ";
}
return gwPrefixCache;
}
}

View File

@ -0,0 +1,39 @@
package com.cisdi.data.OBLF.impl;
import com.cisdi.data.sdk.gateway.netty.IoSession;
import com.cisdi.data.sdk.gateway.netty.impl.AbstractSessionFactory;
import lombok.extern.slf4j.Slf4j;
import java.util.UUID;
/**
* @author cuianbing
* @version 1.0
* @description: TODO
* @date 2021/7/20 21:29
*/
@Slf4j
public class OBLFSessionFactory extends AbstractSessionFactory {
private String onlyOneDeviceId;
/**
* @description:
* @param: onlyOneDeviceId 设备唯一ID
* @return: void
* @author cuianbing
* @date: 2021/7/7 22:10
*/
public OBLFSessionFactory(String onlyOneDeviceId) {
this.onlyOneDeviceId = onlyOneDeviceId;
}
@Override
public IoSession newSession() {
IoSession session = new OBLFIoSession(this, onlyOneDeviceId);
session.init(UUID.randomUUID().toString(), provider, socketGateway);
sessionSet.add(session);
return session;
}
}

View File

@ -0,0 +1,21 @@
package com.cisdi.data.OBLF.test;
import com.cisdi.data.sdk.service.Service;
import com.cisdi.data.sdk.service.ServiceProvider;
import lombok.extern.slf4j.Slf4j;
/**
* @author cuianbing
* @version 1.0
* @description: TODO
* @date 2021/7/7 19:17
*/
@Slf4j
public class ServiceProviderTest implements ServiceProvider {
@Override
public Service getByName(String name) {
return null;
}
}

View File

@ -0,0 +1,65 @@
package com.cisdi.data.OBLF.test;
import com.cisdi.data.OBLF.impl.OBLFChannelInitializer;
import com.cisdi.data.OBLF.impl.OBLFSessionFactory;
import com.cisdi.data.sdk.enums.ByteOrder;
import com.cisdi.data.sdk.gateway.netty.SessionFactory;
import com.cisdi.data.sdk.gateway.netty.TcpIoService;
import com.cisdi.data.sdk.gateway.netty.impl.DefaultTcpIoService;
import com.cisdi.data.sdk.vo.GatewayVo;
import io.netty.handler.ssl.OpenSsl;
import lombok.extern.slf4j.Slf4j;
/**
* @author cuianbing
* @version 1.0
* @description: TODO
* @date 2021/7/7 19:28
*/
@Slf4j
public class StartTest {
private static TcpIoService ioService = null;
private static SessionFactory sessionFactory = null;
public static void main(String[] args) {
boolean available = OpenSsl.isAvailable();
log.info("openssl available={}", available);
DefaultTcpIoService defaultIoService = new DefaultTcpIoService();
SessionFactory factory = new OBLFSessionFactory(null);
ServiceProviderTest testServiceProvider = new ServiceProviderTest();
factory.init(testServiceProvider, null);
OBLFChannelInitializer channelInitializer =
new OBLFChannelInitializer(factory, ByteOrder.BIGENDIAN, null);
GatewayVo instanceVo = new GatewayVo();
instanceVo.setByteOrder(ByteOrder.BIGENDIAN);
instanceVo.setParameter("{\"listenIp\":\"0.0.0.0\",\"listenPort\":8888,\"threadSize\":50,\"timeout\":2000}");
defaultIoService.init(instanceVo, factory, channelInitializer);
ioService = defaultIoService;
sessionFactory = factory;
boolean open = ioService.open();
if (open == true) {
log.info("plc网关启动成功");
} else {
log.info("plc网关启动失败");
}
try {
Thread.sleep(10000000);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}

View File

@ -0,0 +1,28 @@
package com.cisdi.data.OBLF.util;
import io.netty.buffer.ByteBuf;
import lombok.extern.slf4j.Slf4j;
import static io.netty.buffer.ByteBufUtil.appendPrettyHexDump;
import static io.netty.util.internal.StringUtil.NEWLINE;
/**
* @author cuianbing
* @version 1.0
* @description: TODO
* @date 2021/7/9 15:32
*/
@Slf4j
public class ByteBufUtil {
public static void log(ByteBuf byteBuf) {
int length = byteBuf.readableBytes();
int row = length / 16 + (length % 15 == 0 ? 0 : 1) + 4;
StringBuilder buf = new StringBuilder(row * 80 * 2)
.append("read index:").append(byteBuf.readerIndex())
.append(" write index:").append(byteBuf.writerIndex())
.append(" capacity:").append(byteBuf.capacity())
.append(NEWLINE);
appendPrettyHexDump(buf, byteBuf);
log.info(buf.toString());
}
}

View File

@ -0,0 +1,27 @@
package com.cisdi.data.OBLF.util;
import lombok.extern.slf4j.Slf4j;
/**
* @author cuianbing
* @version 1.0
* @description: 16进制转换工具类
* @date 2021/7/7 21:41
*/
@Slf4j
public class HexTransform {
/**
* @description:
* @param: hex 16进制字符串
* @param: chartSet 字符集 UTF-8 GB2312 ASCII
* @return: java.lang.String
* @author cuianbing
* @date: 2021/7/7 21:43
*/
public static String HexToString(String hex, String chartSet) {
return null;
}
}

View File

@ -0,0 +1,135 @@
package com.cisdi.data.RFID.gateway;
import io.netty.bootstrap.Bootstrap;
import io.netty.channel.Channel;
import io.netty.channel.ChannelOption;
import io.netty.channel.EventLoopGroup;
import io.netty.channel.epoll.*;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.nio.NioSocketChannel;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.io.IOException;
public class RfidClient {
private static final Logger logger = LoggerFactory.getLogger(RfidClient.class);
private volatile Channel channel = null;
private EventLoopGroup workerGroup = null;
private RfidTaskStartVo startVo;
private Long lastHeartbeatTime = System.currentTimeMillis();
public RfidClient(RfidTaskStartVo startVo) {
this.startVo = startVo;
if (Epoll.isAvailable()) {
logger.info("rfid enable epoll and have tcp SO_KEEPALIVE check");
} else {
logger.info("rfid disable epoll and not have custom SO_KEEPALIVE check");
}
}
public boolean close() {
boolean result = false;
if (workerGroup == null && channel == null) {
return true;
}
if (channel != null) {
try {
channel.close().sync();
channel = null;
result = true;
} catch (Exception e) {
logger.error(e.getLocalizedMessage(), e);
}
}
if (workerGroup != null) {
try {
workerGroup.shutdownGracefully().sync();
workerGroup = null;
result = true;
} catch (InterruptedException e) {
logger.error("永锋物流rfid到 {}:{}的连接关闭失败,{}",
startVo.getSocketParam().getPeerIp(), startVo.getSocketParam().getPeerPort(), e);
}
}
if (channel != null || workerGroup != null) {
logger.info("channel:{},workgoup:{}", channel, workerGroup);
}
return result;
}
public void run() throws IOException {
start();
}
private void start() {
lastHeartbeatTime = System.currentTimeMillis();
if (channel != null) {
close();
}
//设置一个多线程循环器
//启动附注类
Bootstrap bootstrap = new Bootstrap();
bootstrap.option(ChannelOption.SO_KEEPALIVE, true);
if (Epoll.isAvailable()) {
bootstrap.channel(EpollSocketChannel.class);
bootstrap.option(EpollChannelOption.EPOLL_MODE, EpollMode.LEVEL_TRIGGERED);
bootstrap.option(EpollChannelOption.TCP_KEEPIDLE, 10);
bootstrap.option(EpollChannelOption.TCP_KEEPINTVL, 5);
bootstrap.option(EpollChannelOption.TCP_KEEPCNT, 2);
workerGroup = new EpollEventLoopGroup(2);
} else {
workerGroup = new NioEventLoopGroup(2);
bootstrap.channel(NioSocketChannel.class);
}
bootstrap.group(workerGroup);
//指定所使用的NIO传输channel
//指定客户端初始化处理
bootstrap.handler(new RfidClientInitializer(startVo, this));
try {
channel = bootstrap.connect(startVo.getSocketParam().getPeerIp(),
startVo.getSocketParam().getPeerPort()).sync().channel();
//channel.closeFuture().sync(); // 如果会话关闭会退出当前线程
} catch (InterruptedException e) {
logger.warn(e.getMessage(), e);
}
}
public void reconnect() {
logger.info("永锋物流rfid重新连接中......{}:{}", getIp(), getPort());
close();
start();
}
public Channel getChannel() {
return channel;
}
public void setChannel(Channel channel) {
this.channel = channel;
}
public String getIp() {
return startVo.getSocketParam().getPeerIp();
}
public int getPort() {
return startVo.getSocketParam().getPeerPort();
}
public Long getLastHeartbeatTime() {
return lastHeartbeatTime;
}
public void setLastHeartbeatTime(Long lastHeartbeatTime) {
this.lastHeartbeatTime = lastHeartbeatTime;
}
}

View File

@ -0,0 +1,110 @@
package com.cisdi.data.RFID.gateway;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.serializer.SerializerFeature;
import com.cisdi.data.sdk.consts.ServiceName;
import com.cisdi.data.sdk.gateway.message.SocketMessage;
import com.cisdi.data.sdk.service.SendService;
import io.netty.buffer.ByteBuf;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.SimpleChannelInboundHandler;
import io.netty.util.ReferenceCountUtil;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.nio.charset.Charset;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
public class RfidClientHandler extends SimpleChannelInboundHandler<ByteBuf> {
private static final Logger logger = LoggerFactory.getLogger(RfidClientHandler.class);
private static final Charset Encode_Charset = Charset.forName("UTF-8");
private static final String HEARTBEAT_CODE = "HeartBea";
private RfidClient rfidClient;
private RfidTaskStartVo startVo;
public RfidClientHandler(RfidTaskStartVo startVo, RfidClient rfidClient) {
this.startVo = startVo;
this.rfidClient = rfidClient;
}
@Override
protected void channelRead0(ChannelHandlerContext ctx, ByteBuf msg) throws Exception {
try {
List<RfidItemVo> decode = RfidVoDecoder.Decode(msg);
if(decode.size() == 1 && HEARTBEAT_CODE.equalsIgnoreCase(decode.get(0).getCode())) {
logger.info("永锋物流Rfid {},启用心跳:{} 心跳 vo:{}", rfidClient.getChannel(),
startVo.getCustomParam() == null ? false : startVo.getCustomParam().getEnableHeartbeat(),
decode);
rfidClient.setLastHeartbeatTime(System.currentTimeMillis());
return;
}
decode.forEach((RfidItemVo i) -> {
i.setServerIp(startVo.getSocketParam().getPeerIp());
i.setServerPort(startVo.getSocketParam().getPeerPort());
});
if (startVo.getGatewayBase() != null && Boolean.TRUE.equals(startVo.getGatewayBase().getInstanceVo().getLogOpen())) {
logger.info("永锋物流Rfid {} vo:{} ", rfidClient.getChannel(), decode);
}
if (startVo.getGatewayBase() != null && startVo.getServiceProvider() != null) {
Map<String, Object> data = new HashMap<>();
SendService service = (SendService) startVo.getServiceProvider().getByName(ServiceName.Send);
SocketMessage socketMessage = startVo.getGatewayBase().buildSocketMessage();
socketMessage.setDeviceId(startVo.getDeviceId());
socketMessage.setProviderCode(null);
socketMessage.setMsgKey("666");
data.put("data", decode);
String jsonString = JSON.toJSONString(data, SerializerFeature.WriteMapNullValue);
byte[] body = jsonString.getBytes(Encode_Charset);
socketMessage.setData(body);
logger.info("socketMess" + socketMessage.toString());
service.sendMessage(socketMessage);
} else {
logger.info("永锋物流Rfid收到消息{}", decode);
}
} catch (Exception e) {
logger.error(e.getLocalizedMessage(), e);
}
}
@Override
public void channelActive(ChannelHandlerContext ctx) throws Exception {
logger.info("{} channelActive active", ctx.channel());
}
@Override
public void channelInactive(ChannelHandlerContext ctx) throws Exception {
logger.info("{} channelInactive inactive", ctx.channel());
try {
rfidClient.setChannel(null);
logger.info("set channel to null raise reconnect");
} finally {
// 释放引用
rfidClient = null;
}
super.channelInactive(ctx);
}
@Override
public void exceptionCaught(ChannelHandlerContext ctx, Throwable t) throws Exception {
logger.error("exceptionCaught:{}", t);
super.exceptionCaught(ctx, t);
}
@Override
public void userEventTriggered(ChannelHandlerContext ctx, Object evt) throws Exception {
logger.error("userEventTriggered:{}", evt);
super.userEventTriggered(ctx, evt);
}
}

View File

@ -0,0 +1,24 @@
package com.cisdi.data.RFID.gateway;
import io.netty.channel.ChannelInitializer;
import io.netty.channel.ChannelPipeline;
import io.netty.channel.socket.SocketChannel;
public class RfidClientInitializer extends ChannelInitializer<SocketChannel> {
private RfidClient rfidClient;
private RfidTaskStartVo startVo;
public RfidClientInitializer(RfidTaskStartVo startVo, RfidClient rfidClient) {
this.startVo = startVo;
this.rfidClient = rfidClient;
}
@Override
protected void initChannel(SocketChannel socketChannel) throws Exception {
//注册管道
ChannelPipeline pipeline = socketChannel.pipeline();
pipeline.addLast(new RfidFrameDecoder(startVo));
pipeline.addLast("chat", new RfidClientHandler(startVo, rfidClient));
}
}

View File

@ -0,0 +1,81 @@
package com.cisdi.data.RFID.gateway;
import com.alibaba.fastjson.JSON;
import java.io.Serializable;
import java.util.ArrayList;
import java.util.List;
import java.util.stream.Collectors;
/**
* Rfid server有多个所以需要支持配置多个服务端地址的
* @author cup
* @date 2021/03/03
*/
public class RfidCustomParam implements Serializable {
private static final long serialVersionUID = -5017472517219960138L;
/**
* 每个String 192.168.1.5:8823 形式
*/
private List<String> serverList = new ArrayList<String>();
private Boolean enableHeartbeat = Boolean.FALSE;
private Integer heartbeatTimeInMs = 5000;
private Integer heartbeatMaxLostCount = 3;
public List<String> getServerList() {
return serverList;
}
public void setServerList(List<String> serverList) {
this.serverList = serverList;
}
public Boolean getEnableHeartbeat() {
return enableHeartbeat;
}
public void setEnableHeartbeat(Boolean enableHeartbeat) {
this.enableHeartbeat = enableHeartbeat;
}
public Integer getHeartbeatTimeInMs() {
return heartbeatTimeInMs;
}
public void setHeartbeatTimeInMs(Integer heartbeatTimeInMs) {
this.heartbeatTimeInMs = heartbeatTimeInMs;
}
public Integer getHeartbeatMaxLostCount() {
return heartbeatMaxLostCount;
}
public void setHeartbeatMaxLostCount(Integer heartbeatMaxLostCount) {
this.heartbeatMaxLostCount = heartbeatMaxLostCount;
}
@Override
public String toString() {
return JSON.toJSONString(this);
}
public static void main(String[] args){
RfidCustomParam dto = new RfidCustomParam();
dto.getServerList().add("192.168.6.55:10000");
dto.getServerList().add("192.168.6.56:10000");
dto.getServerList().add("192.165.20.111:10000");
dto.getServerList().add("192.165.20.112:10000");
dto.getServerList().add("192.165.20.113:10000");
dto.getServerList().add("192.165.20.119:10000");
dto.getServerList().add("192.165.20.118:10000");
dto.getServerList().add("192.165.20.120:10000");
dto.getServerList().add("192.165.20.121:10000");
dto.getServerList().add("192.165.20.121:10000");
List<String> customParams=dto.getServerList().stream().distinct().collect(Collectors.toList());
System.out.println(customParams);
System.out.println(dto);
}
}

View File

@ -0,0 +1,150 @@
package com.cisdi.data.RFID.gateway;
import com.cisdi.data.common.dto.AlarmDto;
import com.cisdi.data.sdk.consts.ServiceName;
import com.cisdi.data.sdk.service.AlarmService;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.util.Arrays;
import java.util.Date;
public class RfidDaemonTask implements Runnable {
private static final Logger logger = LoggerFactory.getLogger(RfidDaemonTask.class);
private RfidClient rfidClient;
private RfidTaskStartVo startVo;
public RfidDaemonTask(RfidClient rfidClient, RfidTaskStartVo startVo) {
this.rfidClient = rfidClient;
this.startVo = startVo;
}
@Override
public void run() {
String channelInfo = null;
while (startVo.getShouldRun().get() == true) {
channelInfo = String.format("channel:%s, active:%s,open:%s,writable:%s", rfidClient.getChannel(),
rfidClient.getChannel() == null ? "" : rfidClient.getChannel().isActive(),
rfidClient.getChannel() == null ? "" : rfidClient.getChannel().isOpen(),
rfidClient.getChannel() == null ? "" : rfidClient.getChannel().isWritable());
try {
if (rfidClient != null && rfidClient.getChannel() != null
&& rfidClient.getChannel().isActive() == true) {
if (startVo.getGatewayBase() != null
&& Boolean.TRUE.equals(startVo.getGatewayBase().getInstanceVo().getLogOpen())) {
logger.info("当前永锋物流Rfid拉取连接通道处于连接状态连接id:{},连接信息:{}",
startVo.getGatewayBase().getInstanceVo().getRunId(), channelInfo);
}
if(startVo.getCustomParam() != null
&& Boolean.TRUE.equals(startVo.getCustomParam().getEnableHeartbeat())
&& Math.abs(System.currentTimeMillis() - rfidClient.getLastHeartbeatTime()) >
startVo.getCustomParam().getHeartbeatMaxLostCount() * startVo.getCustomParam().getHeartbeatTimeInMs()){
logger.warn("当前永锋物流Rfid拉取连接通道心跳启用且心跳超时触发重连连接id:{},连接信息:{}",
startVo.getGatewayBase().getInstanceVo().getRunId(), channelInfo);
//启用了心跳且心跳时间超时
reconnectToRfid(channelInfo, true);
}
} else if (rfidClient.getChannel() == null) {
String errorMsg = String.format("永锋物流Rfid到%s:%s的连接未建立或已关闭, %s", rfidClient.getIp(),
rfidClient.getPort(), channelInfo);
logger.warn(errorMsg);
sendAlarmToPlatform(errorMsg);
reconnectToRfid(channelInfo, false);
}
else {
String errorMsg = String.format("永锋物流Rfid到%s:%s的连接未建立或已关闭, %s", rfidClient.getIp(),
rfidClient.getPort(), channelInfo);
logger.warn(errorMsg);
sendAlarmToPlatform(errorMsg);
if(startVo.getCustomParam() != null
&& Boolean.TRUE.equals(startVo.getCustomParam().getEnableHeartbeat())
&& Math.abs(System.currentTimeMillis() - rfidClient.getLastHeartbeatTime()) >
startVo.getCustomParam().getHeartbeatMaxLostCount() * startVo.getCustomParam().getHeartbeatTimeInMs()){
logger.warn("当前永锋物流Rfid拉取连接通道心跳启用且心跳超时触发重连连接id:{},连接信息:{}",
startVo.getGatewayBase().getInstanceVo().getRunId(), channelInfo);
//启用了心跳且心跳时间超时
reconnectToRfid(channelInfo, true);
}
}
Thread.sleep(startVo.getSocketParam().getPullInternal());
} catch (Exception e) {
logger.warn(e.getMessage(), e);
}
}
if (rfidClient != null) {
rfidClient.close();
rfidClient = null;
}
logger.info("退出永锋物流Rfid拉取连接线程 {}", channelInfo);
}
private void reconnectToRfid(final String copyChannelInfo, boolean forceConnect) throws InterruptedException {
Thread.sleep(5000);
Thread thread = new Thread(new Runnable() {
@Override
public void run() {
try {
logger.info("永锋物流Rfid触发重连强制:{}....{}:{} {}", forceConnect, rfidClient.getIp(), rfidClient.getPort(),
copyChannelInfo);
if (rfidClient.getChannel() == null || forceConnect) {
rfidClient.reconnect();
}
} catch (Exception e) {
logger.info(e.getMessage(), e);
}
}
});
thread.start();
}
public void forceReconnectToRfid() {
String channelInfo = String.format("channel:%s, active:%s,open:%s,writable:%s", rfidClient.getChannel(),
rfidClient.getChannel() == null ? "" : rfidClient.getChannel().isActive(),
rfidClient.getChannel() == null ? "" : rfidClient.getChannel().isOpen(),
rfidClient.getChannel() == null ? "" : rfidClient.getChannel().isWritable());
try {
Thread.sleep(500);
Thread thread = new Thread(new Runnable() {
@Override
public void run() {
try {
logger.info("永锋物流Rfid触发重连强制:{}....{}:{} {}", true, rfidClient.getIp(), rfidClient.getPort(),
channelInfo);
rfidClient.reconnect();
} catch (Exception e) {
logger.info(e.getMessage(), e);
}
}
});
thread.start();
} catch (Exception e) {
logger.error(e.getMessage(), e);
}
}
private void sendAlarmToPlatform(String detail) {
if (startVo.getServiceProvider() != null && startVo.getGatewayBase() != null) {
AlarmService alarmService = (AlarmService)startVo.getServiceProvider().getByName(ServiceName.Alarm);
if (alarmService != null) {
AlarmDto alarmDto = new AlarmDto();
alarmDto.setAlarmType(AlarmDto.Connect_Fail_Alarm);
alarmDto.setDetail(detail);
alarmDto.setDeviceId(startVo.getDeviceId());
alarmDto.setGatewayId(startVo.getGatewayBase().getInstanceVo().getRunId());
alarmDto.setGatewayName(startVo.getGatewayBase().getInstanceVo().getName());
alarmDto.setMsgKey(null);
alarmDto.setUpper(Boolean.TRUE);
alarmDto.setTime(new Date());
alarmService.raiseAlarm(Arrays.asList(alarmDto));
}
}
}
}

View File

@ -0,0 +1,64 @@
package com.cisdi.data.RFID.gateway;
import com.cisdi.data.common.exception.BusinessException;
import io.netty.buffer.ByteBuf;
import io.netty.channel.ChannelHandlerContext;
import io.netty.handler.codec.ByteToMessageDecoder;
import lombok.extern.slf4j.Slf4j;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.util.Arrays;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
/**
* @Description: 获取完整的报文
* @Creator: Mo
* @Date: 2021/6/2 23:37
*/
@Slf4j
public class RfidFrameDecoder extends ByteToMessageDecoder {
private static final Logger logger = LoggerFactory.getLogger(RfidFrameDecoder.class);
private RfidTaskStartVo startVo;
private final static Integer MIN_LENGTH = 10;
private final byte START_SPLIT = 0x02;
private final byte END_SPLIT = 0x03;
private final Set<Integer> validDataSizeInByte = new HashSet<Integer>(Arrays.asList(10));
public RfidFrameDecoder(RfidTaskStartVo startVo) {
this.startVo = startVo;
}
@Override
protected void decode(ChannelHandlerContext ctx, ByteBuf bufferIn, List<Object> out) throws Exception {
if (bufferIn.readableBytes() < MIN_LENGTH) {
return;
}
String channelInfo = ctx.toString();
// 心跳报文为 02 48 65 61 72 74 42 65 61 03 长度10个字节拥有独立的起始符和结束符不会和数据报文共享起始符和结束符
// 数据体长度固定为 8心跳报文数据内容为 HeartBea
int beginIndex = bufferIn.readerIndex();
for (int i = 0; i + 9 < bufferIn.readableBytes(); i += 10) {
byte curByte = bufferIn.getByte(beginIndex + i);
if(curByte != START_SPLIT){
ctx.close();
throw new BusinessException(channelInfo + "完整报文第一个字节内容不正确,期望: 0x02,实际:" + curByte);
}
byte endByte = bufferIn.getByte(beginIndex + i + 9);
if(endByte != END_SPLIT){
ctx.close();
throw new BusinessException(channelInfo + "完整报文最后一个字节内容不正确,期望: 0x03,实际:" + endByte);
}
out.add(bufferIn.retainedSlice(beginIndex + i, 10));
bufferIn.readerIndex(beginIndex + i + 10);
}
}
}

View File

@ -0,0 +1,58 @@
package com.cisdi.data.RFID.gateway;
import com.alibaba.fastjson.JSON;
import java.io.Serializable;
/**
* 读取到标签或标签离开解析后的内容都一致
*
* @author cup
* @date 2021/03/03
*/
public class RfidItemVo implements Serializable {
private static final long serialVersionUID = -4290553035349526464L;
/**
* rfid 服务器Ip
*/
private String serverIp;
/**
* rfid 服务器端口
*/
private Integer serverPort;
/**
* 编号
*/
private String code;
public String getServerIp() {
return serverIp;
}
public void setServerIp(String serverIp) {
this.serverIp = serverIp;
}
public Integer getServerPort() {
return serverPort;
}
public void setServerPort(Integer serverPort) {
this.serverPort = serverPort;
}
public String getCode() {
return code;
}
public void setCode(String code) {
this.code = code;
}
@Override
public String toString() {
return JSON.toJSONString(this);
}
}

View File

@ -0,0 +1,172 @@
package com.cisdi.data.RFID.gateway;
import com.alibaba.fastjson.JSON;
import com.cisdi.data.common.exception.BusinessException;
import com.cisdi.data.common.utils.Strings;
import com.cisdi.data.sdk.consts.ServiceName;
import com.cisdi.data.sdk.enums.GatewayState;
import com.cisdi.data.sdk.gateway.base.PulledSocketGatewayBase;
import com.cisdi.data.sdk.param.PullSocketParam;
import com.cisdi.data.sdk.procotol.message.SocketReturnMessage;
import com.cisdi.data.sdk.service.RouteService;
import com.cisdi.data.sdk.vo.DeviceVo;
import com.cisdi.data.sdk.vo.ExeResultVo;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.stream.Collectors;
/**
* 物流 rfid 驱动平台客户端 rfidserver多个server使用tcp协议
*
* @author cup
* @date 2021/03/04
*/
public class RfidPullSocketGateway extends PulledSocketGatewayBase {
private static Logger logger = LoggerFactory.getLogger(RfidPullSocketGateway.class);
private String deviceId;
private AtomicBoolean shouldRun = null;
private static final int Min_Pull_Internal = 1; // 允许最小的拉取间隔为1毫秒
private static final int Min_Timeout = 1000; // 允许最小的超时时间间隔为1000毫秒
@Override
public ExeResultVo sendReturnMessage(SocketReturnMessage returnMsg) {
throw new BusinessException("永锋物流Rfid协议不支持下发命令。");
}
@Override
public void start() {
if (state == GatewayState.RUNNING) {
return;
}
try {
startInternal();
state = GatewayState.RUNNING;
logger.info("永锋物流Rfid报警socket拉取网关:{}启动成功", instanceVo.getRunId());
} catch (Exception e) {
logger.error("永锋物流Rfid报警socket拉取网关:{}启动失败", instanceVo.getRunId());
logger.error(e.getLocalizedMessage(), e);
}
}
private void startInternal() {
socketParam = JSON.parseObject(getInstanceVo().getParameter(), PullSocketParam.class);
if (StringUtils.isEmpty(socketParam.getPeerIp()) || socketParam.getPeerPort() == null) {
throw new BusinessException("未正确配置拉取对端ip地址和对端端口。");
}
if (socketParam.getPullInternal() == null) {
throw new BusinessException("未正确配置拉取间隔");
}
if (socketParam.getTimeout() == null) {
throw new BusinessException("未正确配置拉取超时时间");
}
socketParam.setPullInternal(socketParam.getPullInternal() < Min_Pull_Internal ?
Min_Pull_Internal : socketParam.getPullInternal());
socketParam.setTimeout(socketParam.getTimeout() < Min_Timeout ? Min_Timeout : socketParam.getTimeout());
RouteService routeService = (RouteService) serviceProvider.getByName(ServiceName.Route);
List<DeviceVo> deviceVos = routeService.findByRunId(instanceVo.getRunId());
if (deviceVos.size() > 1) {
throw new BusinessException("网关Id:" + instanceVo.getRunId() + "为永锋物流Rfid报警socket拉取网关只允许关联一个设备Id");
}
deviceId = deviceVos.size() > 0 ? deviceVos.get(0).getDeviceId() : null;
if (StringUtils.isEmpty(deviceId)) {
throw new BusinessException("runId=" + getInstanceVo().getRunId() + "未正确配置网关和设备关联");
}
logger.info("永锋物流Rfid报警socket拉取网关:{}读取启动配置参数:{}", getInstanceVo().getRunId(), socketParam);
closePrevState();
shouldRun = new AtomicBoolean(true);
String parameter = socketParam.getOtherParameter();
Set<String> targetServerSet = new HashSet<String>();
targetServerSet.add(String.format("%s:%s", socketParam.getPeerIp(), socketParam.getPeerPort()));
RfidCustomParam customParam = null;
if (parameter != null) {
customParam = JSON.parseObject(parameter, RfidCustomParam.class);
if (customParam != null) {
/**
* RFID服务端参数去重
*/
customParam.setServerList(customParam.getServerList().stream().distinct().collect(Collectors.toList()));
for (String server : customParam.getServerList()) {
targetServerSet.add(server.trim());
}
}
}
int index = 1;
for (String server : targetServerSet) {
// 复制已有参数
PullSocketParam serverParam = JSON.parseObject(JSON.toJSONString(socketParam), PullSocketParam.class);
serverParam.setPeerIp(Strings.split(server, ":")[0]);
serverParam.setPeerPort(Integer.valueOf(Strings.split(server, ":")[1]));
// 启动线程
RfidTaskStartVo startVo = new RfidTaskStartVo();
startVo.setDeviceId(deviceId);
startVo.setGatewayBase(this);
startVo.setServiceProvider(serviceProvider);
startVo.setSocketParam(serverParam);
startVo.setShouldRun(shouldRun);
startVo.setCustomParam(customParam);
RfidClient fireClient = new RfidClient(startVo);
RfidDaemonTask daemonTask = new RfidDaemonTask(fireClient, startVo);
startVo.setRfidDaemonTask(daemonTask);
Thread thread = new Thread(daemonTask, "Fire-Daemon-Task-runid-" + instanceVo.getRunId() + "-s" + index++);
thread.start();
}
state = GatewayState.RUNNING;
}
@Override
public void shutdown() {
if (state == GatewayState.CLOSED) {
return;
}
closePrevState();
logger.info("永锋物流Rfid报警socket拉取网关:{}关闭中", getInstanceVo().getRunId());
state = GatewayState.CLOSED;
logger.info("永锋物流Rfid报警socket拉取网关:{}关闭成功", getInstanceVo().getRunId());
}
private void closePrevState() {
if (shouldRun != null) {
shouldRun.set(false);
shouldRun = null;
}
}
@Override
public Set<String> getActiveDeviceIds() {
Set<String> set = new HashSet<String>();
if (deviceId != null) {
set.add(deviceId);
}
return set;
}
}

View File

@ -0,0 +1,62 @@
package com.cisdi.data.RFID.gateway;
import com.cisdi.data.sdk.gateway.base.PulledSocketGatewayBase;
import com.cisdi.data.sdk.param.PullSocketParam;
import com.cisdi.data.sdk.service.ServiceProvider;
import java.util.concurrent.atomic.AtomicBoolean;
public class RfidTaskStartVo {
private AtomicBoolean shouldRun;
private ServiceProvider serviceProvider;
private String deviceId;
private PulledSocketGatewayBase gatewayBase;
private PullSocketParam socketParam;
private RfidCustomParam customParam;
private RfidDaemonTask rfidDaemonTask;
public AtomicBoolean getShouldRun() {
return shouldRun;
}
public void setShouldRun(AtomicBoolean shouldRun) {
this.shouldRun = shouldRun;
}
public ServiceProvider getServiceProvider() {
return serviceProvider;
}
public void setServiceProvider(ServiceProvider serviceProvider) {
this.serviceProvider = serviceProvider;
}
public String getDeviceId() {
return deviceId;
}
public void setDeviceId(String deviceId) {
this.deviceId = deviceId;
}
public PulledSocketGatewayBase getGatewayBase() {
return gatewayBase;
}
public void setGatewayBase(PulledSocketGatewayBase gatewayBase) {
this.gatewayBase = gatewayBase;
}
public PullSocketParam getSocketParam() {
return socketParam;
}
public void setSocketParam(PullSocketParam socketParam) {
this.socketParam = socketParam;
}
public RfidCustomParam getCustomParam() {
return customParam;
}
public void setCustomParam(RfidCustomParam customParam) {
this.customParam = customParam;
}
public RfidDaemonTask getRfidDaemonTask() {
return rfidDaemonTask;
}
public void setRfidDaemonTask(RfidDaemonTask rfidDaemonTask) {
this.rfidDaemonTask = rfidDaemonTask;
}
}

View File

@ -0,0 +1,87 @@
package com.cisdi.data.RFID.gateway;
import com.cisdi.data.common.exception.BusinessException;
import com.cisdi.data.util.HexUtil;
import io.netty.buffer.ByteBuf;
import io.netty.buffer.Unpooled;
import io.netty.util.CharsetUtil;
import io.netty.util.ReferenceCountUtil;
import java.util.ArrayList;
import java.util.List;
public class RfidVoDecoder {
public static List<RfidItemVo> Decode(ByteBuf in) {
RfidItemVo vo = new RfidItemVo();
List<RfidItemVo> result = new ArrayList<>();
//消息体部分
int length;
if (in == null) {
throw new BusinessException("ByteBuf 入参为null");
} else if (in.readableBytes() == 10) {
length = 8;
}
else {
throw new BusinessException("报文长度不匹配 ,期望10实际" + in.readableBytes());
}
//去掉报文头 结束符
ByteBuf proceedIn = in.retainedSlice(1, length);
result.add(split(proceedIn));
ReferenceCountUtil.release(proceedIn);
return result;
}
/**
* @param in 去掉头尾的报文
* @Description: 拆分报文
* @author: Mo
* @Date: 2021/6/2 10:51
* @return: com.cisdi.data.RFID.gateway.RfidItemVo
*/
public static RfidItemVo split(ByteBuf in) {
RfidItemVo rfidItemVo = new RfidItemVo();
ByteBuf buf = in.readBytes(8);
// 编号
String code = buf.toString(CharsetUtil.UTF_8);
rfidItemVo.setCode(code);
ReferenceCountUtil.release(buf);
return rfidItemVo;
}
public static void main(String[] args) throws Exception {
// 标签读取
// byte[] readBytes1 = HexUtil.hexStringToBytes("001c1952000b000e3000eabcdef01234567890003001000400000501");
// ByteBuf copiedBuffer = Unpooled.copiedBuffer(readBytes1);
// RfidItemVo decoderVo = RfidVoDecoder.Decode(copiedBuffer);
// logger.info("vo1={}", decoderVo);
//
// // 标签离开
// readBytes1 = HexUtil.hexStringToBytes("00161942050c000e3000eabcdef01234567890003001");
// copiedBuffer = Unpooled.copiedBuffer(readBytes1);
// decoderVo = RfidVoDecoder.Decode(copiedBuffer);
// logger.info("vo1={}", decoderVo);
//标签读取
byte[] readBytes1 = HexUtil.hexStringToBytes("02524630313030303103");
ByteBuf copiedBuff = Unpooled.copiedBuffer(readBytes1);
List<RfidItemVo> rfidItemVoList = RfidVoDecoder.Decode(copiedBuff);
rfidItemVoList.forEach(System.out::println);
readBytes1 = HexUtil.hexStringToBytes("0248656172744265617403");
copiedBuff = Unpooled.copiedBuffer(readBytes1);
rfidItemVoList = RfidVoDecoder.Decode(copiedBuff);
rfidItemVoList.forEach(System.out::println);
RfidFrameDecoder decoder = new RfidFrameDecoder(null);
readBytes1 = HexUtil.hexStringToBytes("0248656172744265617403");
copiedBuff = Unpooled.copiedBuffer(readBytes1);
decoder.decode(null, copiedBuff, new ArrayList<Object>());
}
}

View File

@ -0,0 +1,143 @@
package com.cisdi.data.Spectrograph8860;
import com.alibaba.fastjson.JSON;
import com.cisdi.data.Spectrograph8860.impl.SGSessionFactory;
import com.cisdi.data.Spectrograph8860.impl.SGChannelInitializer;
import com.cisdi.data.Spectrograph8860.impl.SGIoSession;
import com.cisdi.data.common.exception.BusinessException;
import com.cisdi.data.sdk.consts.ServiceName;
import com.cisdi.data.sdk.enums.GatewayState;
import com.cisdi.data.sdk.gateway.base.SocketGatewayBase;
import com.cisdi.data.sdk.gateway.netty.IoSession;
import com.cisdi.data.sdk.gateway.netty.SessionFactory;
import com.cisdi.data.sdk.gateway.netty.TcpIoService;
import com.cisdi.data.sdk.gateway.netty.impl.DefaultTcpIoService;
import com.cisdi.data.sdk.param.ListenSocketParam;
import com.cisdi.data.sdk.procotol.message.SocketReturnMessage;
import com.cisdi.data.sdk.service.PlatformService;
import com.cisdi.data.sdk.service.RouteService;
import com.cisdi.data.sdk.vo.DeviceVo;
import com.cisdi.data.sdk.vo.ExeResultVo;
import com.cisdi.data.sdk.vo.SslConfigVo;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
public class SGSocketGateway extends SocketGatewayBase {
private static Logger logger = LoggerFactory.getLogger(SGSocketGateway.class);
TcpIoService ioService = null;
SessionFactory sessionFactory = null;
// 当配置为单个设备模式时此为该设备id
String onlyOneDeviceId = null;
/**
* 下发的时候查配置路由如果配置路由里面有匹配的则走配置路由如果没有匹配的则原路返回
*/
@Override
public ExeResultVo sendReturnMessage(SocketReturnMessage returnMsg) {
throw new BusinessException("光谱仪8860不支持下发服务");
}
@Override
public void start() {
if (state == GatewayState.RUNNING) {
return;
}
logger.info("plc网关:{}读取启动配置参数:{},支持多个设备:{}", instanceVo.getRunId(), instanceVo.getParameter(),
instanceVo.getSuportMultiDevice());
// 不支持多个设备必须强制配置一个设备id
if (instanceVo.getSuportMultiDevice() != null && instanceVo.getSuportMultiDevice() == false) {
RouteService routeService = (RouteService) serviceProvider.getByName(ServiceName.Route);
List<DeviceVo> deviceVos = routeService.findByRunId(instanceVo.getRunId());
if (deviceVos.size() > 1) {
throw new BusinessException("网关Id:" + instanceVo.getRunId() + "为光谱仪8860网关当前配置为只支持单个设备但配置了多个设备。");
}
onlyOneDeviceId = deviceVos.size() > 0 ? deviceVos.get(0).getDeviceId() : null;
if (StringUtils.isEmpty(onlyOneDeviceId)) {
throw new BusinessException("runId=" + getInstanceVo().getRunId() + "未正确配置网关和设备关联");
}
}
DefaultTcpIoService defaultIoService = new DefaultTcpIoService();
SessionFactory factory = new SGSessionFactory(onlyOneDeviceId);
factory.init(serviceProvider, this);
SslConfigVo sslConfigVo = null;
ListenSocketParam socketParam = JSON.parseObject(getInstanceVo().getParameter(), ListenSocketParam.class);
if (socketParam != null && Boolean.TRUE.equals(socketParam.getEnableSsl())) {
PlatformService platformService = (PlatformService) serviceProvider.getByName(ServiceName.Platform);
sslConfigVo = platformService.getSslConfig();
}
SGChannelInitializer channelInitializer =
new SGChannelInitializer(factory, getInstanceVo().getByteOrder(), sslConfigVo);
defaultIoService.init(instanceVo, factory, channelInitializer);
ioService = defaultIoService;
sessionFactory = factory;
boolean open = ioService.open();
if (open == true) {
state = GatewayState.RUNNING;
logger.info("光谱仪8860网关:{}启动成功 参数:{}", instanceVo.getRunId(), getInstanceVo().getParameter());
} else {
logger.info("光谱仪8860网关:{}启动失败 参数:{}", instanceVo.getRunId(), getInstanceVo().getParameter());
}
}
@Override
public void shutdown() {
if (state == GatewayState.CLOSED) {
return;
}
if (sessionFactory != null) {
for (IoSession ioSession : sessionFactory.getSessions()) {
SGIoSession SGIoSession = (SGIoSession) ioSession;
SGIoSession.close();
}
}
boolean close = ioService.close();
if (close == true) {
sessionFactory = null;
state = GatewayState.CLOSED;
logger.info("光谱仪8860网关:{}关闭成功", instanceVo.getRunId());
} else {
logger.info("光谱仪8860网关:{}关闭失败", instanceVo.getRunId());
}
}
@Override
public Set<String> getActiveDeviceIds() {
if (onlyOneDeviceId != null) {
Set<String> set = new HashSet<String>();
set.add(onlyOneDeviceId);
return set;
} else {
return sessionFactory.getActiveDeviceIds();
}
}
}

View File

@ -0,0 +1,73 @@
package com.cisdi.data.Spectrograph8860.impl;
import com.cisdi.data.sdk.enums.ByteOrder;
import com.cisdi.data.sdk.gateway.netty.SessionFactory;
import com.cisdi.data.sdk.gateway.netty.impl.AbstractChannelInitializer;
import com.cisdi.data.sdk.gateway.netty.impl.AbstractIoChannelHandler;
import com.cisdi.data.sdk.gateway.netty.impl.DefaultIoChannelHandler;
import com.cisdi.data.sdk.utils.NettySslUtils;
import com.cisdi.data.sdk.vo.SslConfigVo;
import io.netty.channel.Channel;
import io.netty.channel.ChannelHandler;
import io.netty.channel.socket.SocketChannel;
import io.netty.handler.timeout.IdleStateHandler;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.util.ArrayList;
import java.util.List;
public class SGChannelInitializer<I> extends AbstractChannelInitializer<I> {
private static final Logger logger = LoggerFactory.getLogger(SGChannelInitializer.class);
private SessionFactory factory;
private ByteOrder byteOrder;
private SslConfigVo sslConfigVo;
/**
* 构造通道初始化器对象
*
* @param factory 会话工厂
* @param byteOrder 大小端
* @param sslConfig ssl证书配置如果不启用tls传null
*/
public SGChannelInitializer(SessionFactory factory,
ByteOrder byteOrder,
SslConfigVo sslConfig) {
this.factory = factory;
this.byteOrder = byteOrder;
this.sslConfigVo = sslConfig;
}
@SuppressWarnings("unchecked")
@Override
protected AbstractIoChannelHandler<I> getTailHandler() {
return new DefaultIoChannelHandler(factory);
}
@Override
protected List<ChannelHandler> getHandlers() {
List<ChannelHandler> handlers = new ArrayList<ChannelHandler>();
return handlers;
}
@Override
protected IdleStateHandler getIdleStateHandler() {
return new IdleStateHandler(15, 15, 30);
}
@Override
protected ChannelHandler getSslChannelHandler(Channel socketChannel) {
ChannelHandler sslHandler = null;
try {
if (sslConfigVo != null) {
sslHandler = NettySslUtils.getServerSslHandler((SocketChannel) socketChannel, sslConfigVo);
}
} catch (Exception e) {
logger.warn(e.getLocalizedMessage(), e);
}
return sslHandler;
}
}

View File

@ -0,0 +1,23 @@
package com.cisdi.data.Spectrograph8860.impl;
import com.cisdi.data.sdk.gateway.netty.IoSession;
import com.cisdi.data.sdk.gateway.netty.impl.AbstractSessionFactory;
import java.util.UUID;
public class SGSessionFactory extends AbstractSessionFactory {
private String onlyOneDeviceId;
public SGSessionFactory(String onlyoneDeviceId) {
this.onlyOneDeviceId = onlyoneDeviceId;
}
@Override
public IoSession newSession() {
IoSession session = new SGIoSession(this, onlyOneDeviceId);
session.init(UUID.randomUUID().toString(), provider, socketGateway);
sessionSet.add(session);
return session;
}
}

View File

@ -0,0 +1,14 @@
package com.cisdi.data.Spectrograph8860.test;
import com.cisdi.data.sdk.service.Service;
import com.cisdi.data.sdk.service.ServiceProvider;
public class ServiceProviderTest implements ServiceProvider {
@Override
public Service getByName(String name) {
// TODO Auto-generated method stub
return null;
}
}

View File

@ -0,0 +1,61 @@
package com.cisdi.data.Spectrograph8860.test;
import com.cisdi.data.Spectrograph8860.SGSocketGateway;
import com.cisdi.data.Spectrograph8860.impl.SGSessionFactory;
import com.cisdi.data.Spectrograph8860.impl.SGChannelInitializer;
import com.cisdi.data.sdk.enums.ByteOrder;
import com.cisdi.data.sdk.gateway.netty.SessionFactory;
import com.cisdi.data.sdk.gateway.netty.TcpIoService;
import com.cisdi.data.sdk.gateway.netty.impl.DefaultTcpIoService;
import com.cisdi.data.sdk.vo.GatewayVo;
import io.netty.handler.ssl.OpenSsl;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public class StartPlcTest {
private static Logger logger = LoggerFactory.getLogger(SGSocketGateway.class);
private static TcpIoService ioService = null;
@SuppressWarnings("unused")
private static SessionFactory sessionFactory = null;
public static void main(String[] args) {
boolean available = OpenSsl.isAvailable();
logger.info("openssl available={}", available);
DefaultTcpIoService defaultIoService = new DefaultTcpIoService();
SessionFactory factory = new SGSessionFactory(null);
ServiceProviderTest testServiceProvider = new ServiceProviderTest();
//String passthroughAddress = "192.168.235.1:9098";
factory.init(testServiceProvider, null);
SGChannelInitializer channelInitializer =
new SGChannelInitializer(factory, ByteOrder.BIGENDIAN, null);
GatewayVo instanceVo = new GatewayVo();
instanceVo.setByteOrder(ByteOrder.BIGENDIAN);
instanceVo.setParameter("{\"listenIp\":\"10.76.49.121\",\"listenPort\":5002,\"threadSize\":50,\"timeout\":2000}");
defaultIoService.init(instanceVo, factory, channelInitializer);
ioService = defaultIoService;
sessionFactory = factory;
boolean open = ioService.open();
if (open == true) {
logger.info("plc网关启动成功");
} else {
logger.info("plc网关启动失败");
}
try {
Thread.sleep(10000000);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}

View File

@ -0,0 +1,145 @@
package com.cisdi.data.XRFLEFT;
import com.alibaba.fastjson.JSON;
import com.cisdi.data.XRFLEFT.impl.XRFLeftChannelInitializer;
import com.cisdi.data.XRFLEFT.impl.XRFLeftIoSession;
import com.cisdi.data.XRFLEFT.impl.XRFLeftSessionFactory;
import com.cisdi.data.common.exception.BusinessException;
import com.cisdi.data.sdk.consts.ServiceName;
import com.cisdi.data.sdk.enums.GatewayState;
import com.cisdi.data.sdk.gateway.base.SocketGatewayBase;
import com.cisdi.data.sdk.gateway.netty.IoSession;
import com.cisdi.data.sdk.gateway.netty.SessionFactory;
import com.cisdi.data.sdk.gateway.netty.TcpIoService;
import com.cisdi.data.sdk.gateway.netty.impl.DefaultTcpIoService;
import com.cisdi.data.sdk.param.ListenSocketParam;
import com.cisdi.data.sdk.procotol.message.SocketReturnMessage;
import com.cisdi.data.sdk.service.PlatformService;
import com.cisdi.data.sdk.service.RouteService;
import com.cisdi.data.sdk.vo.DeviceVo;
import com.cisdi.data.sdk.vo.ExeResultVo;
import com.cisdi.data.sdk.vo.SslConfigVo;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
/**
* @description: 左侧荧光仪 10.233.2.132
* @author cuianbing
* @date 2021/7/15 9:27
* @version 1.0
*/
@Slf4j
public class XRFLEFTSocketGateway extends SocketGatewayBase {
TcpIoService ioService = null;
SessionFactory sessionFactory = null;
// 当配置为单个设备模式时此为该设备id
String onlyOneDeviceId = null;
@Override
public ExeResultVo sendReturnMessage(SocketReturnMessage socketReturnMessage) {
throw new BusinessException("X射线荧光光谱仪不支持下发服务");
}
@Override
public void start() {
if (state == GatewayState.RUNNING){
return;
}
log.info("网关:{}读取启动配置参数:{},是否支持支持多个设备:{}", instanceVo.getRunId(), instanceVo.getParameter(),
instanceVo.getSuportMultiDevice());
// 不支持多个设备必须强制配置一个设备id
if (instanceVo.getSuportMultiDevice() != null && instanceVo.getSuportMultiDevice() == false) {
RouteService routeService = (RouteService) serviceProvider.getByName(ServiceName.Route);
List<DeviceVo> deviceVos = routeService.findByRunId(instanceVo.getRunId());
if (deviceVos.size() > 1) {
throw new BusinessException("网关Id:" + instanceVo.getRunId() + "为X射线荧光光谱仪网关当前配置为只支持单个设备但配置了多个设备。");
}
onlyOneDeviceId = deviceVos.size() > 0 ? deviceVos.get(0).getDeviceId() : null;
if (StringUtils.isEmpty(onlyOneDeviceId)) {
throw new BusinessException("runId=" + getInstanceVo().getRunId() + "未正确配置网关和设备关联");
}
}
DefaultTcpIoService defaultIoService = new DefaultTcpIoService();
SessionFactory factory = new XRFLeftSessionFactory(onlyOneDeviceId);
factory.init(serviceProvider, this);
SslConfigVo sslConfigVo = null;
ListenSocketParam socketParam = JSON.parseObject(getInstanceVo().getParameter(), ListenSocketParam.class);
if (socketParam != null && Boolean.TRUE.equals(socketParam.getEnableSsl())) {
PlatformService platformService = (PlatformService) serviceProvider.getByName(ServiceName.Platform);
sslConfigVo = platformService.getSslConfig();
}
XRFLeftChannelInitializer channelInitializer =
new XRFLeftChannelInitializer(factory, getInstanceVo().getByteOrder(), sslConfigVo);
defaultIoService.init(instanceVo, factory, channelInitializer);
ioService = defaultIoService;
sessionFactory = factory;
boolean open = ioService.open();
if (open == true) {
state = GatewayState.RUNNING;
log.info("X射线荧光光谱仪网关:{}启动成功 参数:{}", instanceVo.getRunId(), getInstanceVo().getParameter());
} else {
log.info("X射线荧光光谱仪网关:{}启动失败 参数:{}", instanceVo.getRunId(), getInstanceVo().getParameter());
}
}
@Override
public void shutdown() {
if (state == GatewayState.CLOSED) {
return;
}
if (sessionFactory != null) {
for (IoSession ioSession : sessionFactory.getSessions()) {
XRFLeftIoSession XrfIoSession = (XRFLeftIoSession) ioSession;
XrfIoSession.close();
}
}
boolean close = ioService.close();
if (close == true) {
sessionFactory = null;
state = GatewayState.CLOSED;
log.info("X射线荧光光谱仪网关:{}关闭成功", instanceVo.getRunId());
} else {
log.info("X射线荧光光谱仪网关:{}关闭失败", instanceVo.getRunId());
}
}
@Override
public Set<String> getActiveDeviceIds() {
if (onlyOneDeviceId != null) {
Set<String> set = new HashSet<String>();
set.add(onlyOneDeviceId);
return set;
} else {
return sessionFactory.getActiveDeviceIds();
}
}
}

View File

@ -0,0 +1,75 @@
package com.cisdi.data.XRFLEFT.impl;
import com.cisdi.data.sdk.enums.ByteOrder;
import com.cisdi.data.sdk.gateway.netty.SessionFactory;
import com.cisdi.data.sdk.gateway.netty.impl.AbstractChannelInitializer;
import com.cisdi.data.sdk.gateway.netty.impl.AbstractIoChannelHandler;
import com.cisdi.data.sdk.gateway.netty.impl.DefaultIoChannelHandler;
import com.cisdi.data.sdk.utils.NettySslUtils;
import com.cisdi.data.sdk.vo.SslConfigVo;
import io.netty.channel.Channel;
import io.netty.channel.ChannelHandler;
import io.netty.channel.socket.SocketChannel;
import io.netty.handler.timeout.IdleStateHandler;
import lombok.extern.slf4j.Slf4j;
import java.util.ArrayList;
import java.util.List;
/**
* @author cuianbing
* @version 1.0
* @description: TODO
* @date 2021/7/7 18:57
*/
@Slf4j
public class XRFLeftChannelInitializer<I> extends AbstractChannelInitializer<I> {
private SessionFactory factory;
private ByteOrder byteOrder;
private SslConfigVo sslConfigVo;
/**
* 构造通道初始化器对象
* @param factory 会话工厂
* @param byteOrder 大小端
* @param sslConfig ssl证书配置如果不启用tls传null
*/
public XRFLeftChannelInitializer(SessionFactory factory,
ByteOrder byteOrder,
SslConfigVo sslConfig) {
this.factory = factory;
this.byteOrder = byteOrder;
this.sslConfigVo = sslConfig;
}
@Override
protected AbstractIoChannelHandler<I> getTailHandler() {
return new DefaultIoChannelHandler(factory);
}
@Override
protected List<ChannelHandler> getHandlers() {
List<ChannelHandler> handlers = new ArrayList<ChannelHandler>();
return handlers;
}
@Override
protected IdleStateHandler getIdleStateHandler() {
return new IdleStateHandler(15, 15, 30);
}
@Override
protected ChannelHandler getSslChannelHandler(Channel socketChannel) {
ChannelHandler sslHandler = null;
try {
if(sslConfigVo != null) {
sslHandler = NettySslUtils.getServerSslHandler((SocketChannel)socketChannel, sslConfigVo);
}
} catch (Exception e) {
log.warn(e.getLocalizedMessage(), e);
}
return sslHandler;
}
}

View File

@ -0,0 +1,198 @@
package com.cisdi.data.XRFLEFT.impl;
import com.alibaba.fastjson.JSON;
import com.cisdi.data.common.exception.BusinessException;
import com.cisdi.data.sdk.consts.ServiceName;
import com.cisdi.data.sdk.gateway.message.SocketMessage;
import com.cisdi.data.sdk.gateway.netty.IoSession;
import com.cisdi.data.sdk.gateway.netty.impl.AbstractIoSession;
import com.cisdi.data.sdk.service.PassthroughService;
import com.cisdi.data.sdk.service.SendService;
import io.netty.buffer.ByteBuf;
import io.netty.buffer.ByteBufAllocator;
import lombok.extern.slf4j.Slf4j;
import java.nio.charset.Charset;
import java.nio.charset.StandardCharsets;
import java.util.*;
import java.util.concurrent.atomic.AtomicInteger;
/**
* @description: 荧光光谱仪左侧解码
* @author cuianbing
* @date 2021/7/15 9:19
* @version 1.0
*/
@Slf4j
public class XRFLeftIoSession extends AbstractIoSession implements IoSession {
private XRFLeftSessionFactory factory = null;
private String deviceId = null;
/**
* 如果有值代表所有会话都使用这一个设备id且允许多会话共享此一个设备id不除旧会话
*/
private final String onlyOneDeviceId;
private String gwPrefixCache = null;
private ByteBuf allBuf = ByteBufAllocator.DEFAULT.buffer();
public XRFLeftIoSession(XRFLeftSessionFactory factory, String onlyOneDeviceId) {
super();
this.factory = factory;
this.onlyOneDeviceId = onlyOneDeviceId;
}
@Override
public String[] getDeviceIds() {
String cpDeviceId = deviceId;
String[] result = new String[cpDeviceId == null ? 0 : 1];
if (cpDeviceId != null) {
result[0] = cpDeviceId;
}
return result;
}
@Override
public void onRead(Object message) {
try {
ByteBuf inBuf = (ByteBuf) message;
if (inBuf != null) {
allBuf.writeBytes(inBuf);
}else {
log.info("电文格式为空");
}
}catch (Exception e){
log.error("电文格式错误!");
throw new BusinessException("电文格式错误!");
}
}
@Override
public void onOpen() {
super.onOpen();
log.info("建立连接channel:{}", getChannel());
}
@Override
public void onClose() {
log.info("onClose");
List<Map<String,String>> messages = decode(allBuf);
Map<String, Object> sendMessage =new HashMap<>();
if (serviceProvider != null && socketGateway != null) {
for (Map<String,String> message : messages){
sendMessage.put("data",message);
SendService service = (SendService) serviceProvider.getByName(ServiceName.Send);
SocketMessage socketMessage = socketGateway.buildSocketMessage();
socketMessage.setDeviceId(onlyOneDeviceId);
socketMessage.setData(JSON.toJSONString(sendMessage).getBytes(StandardCharsets.UTF_8));
socketMessage.setMsgKey("default");
service.sendMessage(socketMessage);
if (socketGateway.getInstanceVo().getLogOpen()) {
log.info("类似为:{}:发送消息内容{}", sendMessage.get("data"), sendMessage.toString());
}
}
}
super.onClose();
factory = null;
}
public void close() {
if (getChannel() != null) {
try {
getChannel().close().sync();
} catch (InterruptedException e) {
log.warn(e.getLocalizedMessage(), e);
}
}
}
public void onError(Throwable t) {
// 这里会出现 java.io.IOException: 远程主机强迫关闭了一个现有的连接
log.info("远程主机强迫关闭了一个现有的连接。");
// log.error("session exception:{}", t);
}
public List<Map<String,String>> decode(ByteBuf byteBuf){
List<Map<String,String>> dataList= new ArrayList<>();
AtomicInteger dataFlag = new AtomicInteger();
Map<String,String> data = null;
String msg = byteBuf.toString(Charset.forName("GB2312"));
log.debug("{}",msg);
String[] split = msg.split("\n\r");
for (String s: split){
char tag = s.charAt(0);
if (tag == '3'){
String[] dataArray = s.split("\\s+");
if (dataArray.length > 1){ // 分析错误会出现 `3 (Error) `的数据
assert data != null;
data.put(dataArray[1],dataArray[2]);
}
}else if (tag == '2'){
if (dataFlag.getAndIncrement() > 0){
log.debug("解析的数据为:{}",data);
dataList.add(data);
}
data = new HashMap<>();
//2 高炉渣 323 2021- 7-14 15:41 101
String[] dateArray = s.split("\\s+");
StringBuilder builder = new StringBuilder();
// 时间会出现多余空格的问题 2021- 7-14 15:41 但是10月之后就可以
for (int i = 3 , j = dateArray.length - 1 ; i < j ; i++){
builder.append(dateArray[i]);
}
data.put("分析方法",dateArray[1]);
data.put("样品名称",dateArray[2]);
data.put("分析时间",builder.toString());
}else if(tag == '5'){
dataList.add(data);
log.debug("解析的数据为:{}",data);
}
}
allBuf.clear();
log.info("所有的的数据为:{}",dataList);
return dataList;
}
private void passThrough(ByteBuf passthroughBuf) {
try {
if (serviceProvider != null && socketGateway != null) {
PassthroughService service = (PassthroughService) serviceProvider.getByName(ServiceName.Passthrough);
service.transfer(passthroughBuf, socketGateway.getInstanceVo().getPassthroughAddress());
}
} catch (Exception e) {
log.error("荧光光谱仪协议透传失败:" + e.getLocalizedMessage(), e);
}
}
public String gwPrefix() {
if (gwPrefixCache != null) {
return gwPrefixCache;
}
gwPrefixCache = "";
if (socketGateway != null && socketGateway.getInstanceVo() != null) {
gwPrefixCache = "网关Id:" + socketGateway.getInstanceVo().getRunId() + "连接:" + getChannel() + " ";
} else {
gwPrefixCache = "连接:" + getChannel() + " ";
}
return gwPrefixCache;
}
}

View File

@ -0,0 +1,39 @@
package com.cisdi.data.XRFLEFT.impl;
import com.cisdi.data.sdk.gateway.netty.IoSession;
import com.cisdi.data.sdk.gateway.netty.impl.AbstractSessionFactory;
import lombok.extern.slf4j.Slf4j;
import java.util.UUID;
/**
* @author cuianbing
* @version 1.0
* @description: TODO
* @date 2021/7/7 18:52
*/
@Slf4j
public class XRFLeftSessionFactory extends AbstractSessionFactory {
private String onlyOneDeviceId;
/**
* @description:
* @param: onlyOneDeviceId 设备唯一ID
* @return: void
* @author cuianbing
* @date: 2021/7/7 22:10
*/
public XRFLeftSessionFactory(String onlyOneDeviceId) {
this.onlyOneDeviceId = onlyOneDeviceId;
}
@Override
public IoSession newSession() {
IoSession session = new XRFLeftIoSession(this, onlyOneDeviceId);
session.init(UUID.randomUUID().toString(), provider, socketGateway);
sessionSet.add(session);
return session;
}
}

View File

@ -0,0 +1,21 @@
package com.cisdi.data.XRFLEFT.test;
import com.cisdi.data.sdk.service.Service;
import com.cisdi.data.sdk.service.ServiceProvider;
import lombok.extern.slf4j.Slf4j;
/**
* @author cuianbing
* @version 1.0
* @description: TODO
* @date 2021/7/7 19:17
*/
@Slf4j
public class ServiceProviderTest implements ServiceProvider {
@Override
public Service getByName(String name) {
return null;
}
}

View File

@ -0,0 +1,65 @@
package com.cisdi.data.XRFLEFT.test;
import com.cisdi.data.XRFRIGHT.impl.XRFRightChannelInitializer;
import com.cisdi.data.XRFRIGHT.impl.XRFRightSessionFactory;
import com.cisdi.data.sdk.enums.ByteOrder;
import com.cisdi.data.sdk.gateway.netty.SessionFactory;
import com.cisdi.data.sdk.gateway.netty.TcpIoService;
import com.cisdi.data.sdk.gateway.netty.impl.DefaultTcpIoService;
import com.cisdi.data.sdk.vo.GatewayVo;
import io.netty.handler.ssl.OpenSsl;
import lombok.extern.slf4j.Slf4j;
/**
* @author cuianbing
* @version 1.0
* @description: TODO
* @date 2021/7/7 19:28
*/
@Slf4j
public class StartTest {
private static TcpIoService ioService = null;
private static SessionFactory sessionFactory = null;
public static void main(String[] args) {
boolean available = OpenSsl.isAvailable();
log.info("openssl available={}", available);
DefaultTcpIoService defaultIoService = new DefaultTcpIoService();
SessionFactory factory = new XRFRightSessionFactory(null);
ServiceProviderTest testServiceProvider = new ServiceProviderTest();
factory.init(testServiceProvider, null);
XRFRightChannelInitializer channelInitializer =
new XRFRightChannelInitializer(factory, ByteOrder.BIGENDIAN, null);
GatewayVo instanceVo = new GatewayVo();
instanceVo.setByteOrder(ByteOrder.BIGENDIAN);
instanceVo.setParameter("{\"listenIp\":\"0.0.0.0\",\"listenPort\":8888,\"threadSize\":50,\"timeout\":2000}");
defaultIoService.init(instanceVo, factory, channelInitializer);
ioService = defaultIoService;
sessionFactory = factory;
boolean open = ioService.open();
if (open == true) {
log.info("plc网关启动成功");
} else {
log.info("plc网关启动失败");
}
try {
Thread.sleep(10000000);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}

Some files were not shown because too many files have changed in this diff Show More