Browse Source

同步代码

jwy_category
review512jwy@163.com 2 months ago
commit
28d4d40b0c
  1. 37
      .gitignore
  2. 118
      .mvn/wrapper/MavenWrapperDownloader.java
  3. BIN
      .mvn/wrapper/maven-wrapper.jar
  4. 2
      .mvn/wrapper/maven-wrapper.properties
  5. 11
      Dockerfile
  6. BIN
      Documents/传感器资料/NBI API 资料/NBI SaaSプラットフォーム API説明書-ver 2.1.docx
  7. BIN
      Documents/传感器资料/NBI API 资料/NBI SaaSプラットフォーム API説明書-ver 2.1.pdf
  8. BIN
      Documents/传感器资料/NBI API 资料/NBIInterfaceTest.zip
  9. BIN
      Documents/传感器资料/NBI API 资料/NBI字段匹配表.xlsx
  10. BIN
      Documents/传感器资料/NBI API 资料/NBI数据解析文档.docx
  11. BIN
      Documents/传感器资料/NBI API 资料/NBI数据解析文档.pdf
  12. BIN
      Documents/传感器资料/ZETA传感器/41-干接点检测器-OCZ1ZT.docx
  13. BIN
      Documents/传感器资料/ZETA传感器/57-多路干接点检测器-OC16ZT.docx
  14. BIN
      Documents/传感器资料/ZETA传感器/59-485采集终端-D485ZT.docx
  15. BIN
      Documents/传感器资料/ZETA传感器/BLE gateway/ZETA®LPWAN_BLEZETAGW_产品规格_3.0版.docx
  16. BIN
      Documents/传感器资料/ZETA传感器/JAZE CO2+温湿度.pdf
  17. BIN
      Documents/传感器资料/ZETA传感器/JAZE 超声波距离传感器使用手册v1.1.docx
  18. BIN
      Documents/传感器资料/ZETA传感器/JAZE 超音波距離センサ_JZUS91A1_仕様書_V1.1_20210622.pdf
  19. BIN
      Documents/传感器资料/ZETA传感器/Oviphone健康手环/产品/BG77製品/5G NBIOT体温定位健康手环.docx
  20. BIN
      Documents/传感器资料/ZETA传感器/Oviphone健康手环/产品/BG77製品/B2316 CAT-M & NBIOT Smart Band.docx
  21. BIN
      Documents/传感器资料/ZETA传感器/Oviphone健康手环/产品/BG77製品/B2316 CAT-M, NBIOT体温监测健康定位手环.docx
  22. BIN
      Documents/传感器资料/ZETA传感器/Oviphone健康手环/平台、数据格式/平台,APP和数据对接简介-20210127.docx
  23. BIN
      Documents/传感器资料/ZETA传感器/Oviphone健康手环/平台、数据格式/欧孚通信设备通信协议json1127.docx
  24. BIN
      Documents/传感器资料/ZETA传感器/skytech/SZC100(CO2+温湿度センサー)取扱い説明書_Rev00.pdf
  25. BIN
      Documents/传感器资料/ZETA传感器/skytech/SZT200(高精度傾斜計)取扱い説明書_Rev02.pdf
  26. BIN
      Documents/传感器资料/ZETA传感器/skytech/SZW100_センサーデータフォーマット_r05.pdf
  27. BIN
      Documents/传感器资料/设备匹配表/NESIC租户KTC项目设备列表_20210805.xlsx
  28. 27
      TECHSOR_OFFICIAL.pem
  29. 1
      cmd
  30. 2
      deploy.bat
  31. 310
      mvnw
  32. 182
      mvnw.cmd
  33. 533
      pom.xml
  34. 57
      readme.md
  35. 3
      shell-build.sh
  36. BIN
      src/libs/godzilla-sdk-1.6.0.jar
  37. 11
      src/main/docker/Dockerfile
  38. 136
      src/main/java/com/baidu/fsg/uid/BitsAllocator.java
  39. 45
      src/main/java/com/baidu/fsg/uid/UidGenerator.java
  40. 174
      src/main/java/com/baidu/fsg/uid/buffer/BufferPaddingExecutor.java
  41. 35
      src/main/java/com/baidu/fsg/uid/buffer/BufferedUidProvider.java
  42. 34
      src/main/java/com/baidu/fsg/uid/buffer/RejectedPutBufferHandler.java
  43. 33
      src/main/java/com/baidu/fsg/uid/buffer/RejectedTakeBufferHandler.java
  44. 261
      src/main/java/com/baidu/fsg/uid/buffer/RingBuffer.java
  45. 75
      src/main/java/com/baidu/fsg/uid/exception/UidGenerateException.java
  46. 175
      src/main/java/com/baidu/fsg/uid/impl/CachedUidGenerator.java
  47. 214
      src/main/java/com/baidu/fsg/uid/impl/DefaultUidGenerator.java
  48. 122
      src/main/java/com/baidu/fsg/uid/utils/DateUtils.java
  49. 104
      src/main/java/com/baidu/fsg/uid/utils/DockerUtils.java
  50. 64
      src/main/java/com/baidu/fsg/uid/utils/EnumUtils.java
  51. 165
      src/main/java/com/baidu/fsg/uid/utils/NamingThreadFactory.java
  52. 84
      src/main/java/com/baidu/fsg/uid/utils/NetUtils.java
  53. 52
      src/main/java/com/baidu/fsg/uid/utils/PaddedAtomicLong.java
  54. 27
      src/main/java/com/baidu/fsg/uid/utils/ValuedEnum.java
  55. 83
      src/main/java/com/baidu/fsg/uid/worker/DisposableWorkerIdAssigner.java
  56. 35
      src/main/java/com/baidu/fsg/uid/worker/WorkerIdAssigner.java
  57. 49
      src/main/java/com/baidu/fsg/uid/worker/WorkerNodeType.java
  58. 92
      src/main/java/com/baidu/fsg/uid/worker/entity/WorkerNodeEntity.java
  59. 22
      src/main/java/com/baidu/fsg/uid/worker/service/WorkerNodeEntityService.java
  60. 21
      src/main/java/com/techsor/datacenter/sender/TechsorDataCenterSenderApplication.java
  61. 119
      src/main/java/com/techsor/datacenter/sender/compiler/JsonPathExtractor.java
  62. 71
      src/main/java/com/techsor/datacenter/sender/compiler/MvelCompiler.java
  63. 37
      src/main/java/com/techsor/datacenter/sender/compiler/MvelExecutor.java
  64. 368
      src/main/java/com/techsor/datacenter/sender/compiler/UserFunction.java
  65. 248
      src/main/java/com/techsor/datacenter/sender/components/CommonOpt.java
  66. 57
      src/main/java/com/techsor/datacenter/sender/components/DBMRestfulClient.java
  67. 97
      src/main/java/com/techsor/datacenter/sender/components/DBMWSClient.java
  68. 26
      src/main/java/com/techsor/datacenter/sender/components/GlobalSwitchStatusComponent.java
  69. 134
      src/main/java/com/techsor/datacenter/sender/components/GuavaRedisCache.java
  70. 30
      src/main/java/com/techsor/datacenter/sender/components/MdcLogEnhancerFilter.java
  71. 228
      src/main/java/com/techsor/datacenter/sender/components/SendMail.java
  72. 9
      src/main/java/com/techsor/datacenter/sender/config/AsyncConfig.java
  73. 15
      src/main/java/com/techsor/datacenter/sender/config/DataCenterEnvConfig.java
  74. 141
      src/main/java/com/techsor/datacenter/sender/config/DataSourceAdminConfig.java
  75. 18
      src/main/java/com/techsor/datacenter/sender/config/DataSourceContextHolder.java
  76. 12
      src/main/java/com/techsor/datacenter/sender/config/DynamicRouteDataSource.java
  77. 17
      src/main/java/com/techsor/datacenter/sender/config/GlobalExceptionHandler.java
  78. 167
      src/main/java/com/techsor/datacenter/sender/config/IotCoreConfiguration.java
  79. 16
      src/main/java/com/techsor/datacenter/sender/config/JdbcTemplateConfig.java
  80. 60
      src/main/java/com/techsor/datacenter/sender/config/KinesisAutoConfig.java
  81. 194
      src/main/java/com/techsor/datacenter/sender/config/LettuceRedisConfig.java
  82. 66
      src/main/java/com/techsor/datacenter/sender/config/RestTemplateConfig.java
  83. 80
      src/main/java/com/techsor/datacenter/sender/config/SysMqttConfiguration.java
  84. 32
      src/main/java/com/techsor/datacenter/sender/config/UidConfiguration.java
  85. 52
      src/main/java/com/techsor/datacenter/sender/config/UidProperties.java
  86. 12
      src/main/java/com/techsor/datacenter/sender/constants/CompanyConstants.java
  87. 52
      src/main/java/com/techsor/datacenter/sender/constants/Constants.java
  88. 6
      src/main/java/com/techsor/datacenter/sender/constants/DeviceTypeConstants.java
  89. 19
      src/main/java/com/techsor/datacenter/sender/constants/MsgConstants.java
  90. 9
      src/main/java/com/techsor/datacenter/sender/constants/TypeConstants.java
  91. 42
      src/main/java/com/techsor/datacenter/sender/controllers/HealthController.java
  92. 308
      src/main/java/com/techsor/datacenter/sender/controllers/MainReceiverController.java
  93. 72
      src/main/java/com/techsor/datacenter/sender/dao/BaStatusDao.java
  94. 124
      src/main/java/com/techsor/datacenter/sender/dao/CommonDAO.java
  95. 83
      src/main/java/com/techsor/datacenter/sender/dao/CompanyInfoDao.java
  96. 116
      src/main/java/com/techsor/datacenter/sender/dao/DashboardAlertDao.java
  97. 118
      src/main/java/com/techsor/datacenter/sender/dao/DashboardStatisticsDao.java
  98. 40
      src/main/java/com/techsor/datacenter/sender/dao/DataSrcConfigDao.java
  99. 63
      src/main/java/com/techsor/datacenter/sender/dao/DeviceAlertConfigDao.java
  100. 20
      src/main/java/com/techsor/datacenter/sender/dao/DeviceAlertTemplateBindDao.java

37
.gitignore

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

118
.mvn/wrapper/MavenWrapperDownloader.java

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

BIN
.mvn/wrapper/maven-wrapper.jar

Binary file not shown.

2
.mvn/wrapper/maven-wrapper.properties

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

11
Dockerfile

@ -0,0 +1,11 @@
FROM registry.ap-northeast-1.aliyuncs.com/southwave/jdk17-template:latest
WORKDIR /app
COPY target/data-center-sender.jar app.jar
EXPOSE 8201
# 使用UseCGroupMemoryLimitForHeap
# ENV JAVA_OPTS="-Xms1g -Xmx2g -XX:+UseParallelGC -XX:ParallelGCThreads=2 -XX:MaxGCPauseMillis=200 -XX:GCTimeRatio=19 -XX:NewRatio=3 -XX:+AlwaysPreTouch -XX:+PrintGCDetails -XX:+PrintGCDateStamps -Xloggc:/app/gc.log"
# ENV JAVA_OPTS="-XX:+UnlockExperimentalVMOptions -XX:+UseG1GC -XX:MaxGCPauseMillis=200 -XX:G1NewSizePercent=20 -XX:G1MaxNewSizePercent=60 -XX:InitialHeapSize=2g -Xmx4096m -XX:MetaspaceSize=256m -XX:+PrintGCDetails -XX:+PrintGCDateStamps -Xloggc:/app/gc.log"
# 使用shell方式的ENTRYPOINT来确保环境变量被展开
ENTRYPOINT java $JAVA_OPTS -jar app.jar --spring-profiles=$env

BIN
Documents/传感器资料/NBI API 资料/NBI SaaSプラットフォーム API説明書-ver 2.1.docx

Binary file not shown.

BIN
Documents/传感器资料/NBI API 资料/NBI SaaSプラットフォーム API説明書-ver 2.1.pdf

Binary file not shown.

BIN
Documents/传感器资料/NBI API 资料/NBIInterfaceTest.zip

Binary file not shown.

BIN
Documents/传感器资料/NBI API 资料/NBI字段匹配表.xlsx

Binary file not shown.

BIN
Documents/传感器资料/NBI API 资料/NBI数据解析文档.docx

Binary file not shown.

BIN
Documents/传感器资料/NBI API 资料/NBI数据解析文档.pdf

Binary file not shown.

BIN
Documents/传感器资料/ZETA传感器/41-干接点检测器-OCZ1ZT.docx

Binary file not shown.

BIN
Documents/传感器资料/ZETA传感器/57-多路干接点检测器-OC16ZT.docx

Binary file not shown.

BIN
Documents/传感器资料/ZETA传感器/59-485采集终端-D485ZT.docx

Binary file not shown.

BIN
Documents/传感器资料/ZETA传感器/BLE gateway/ZETA®LPWAN_BLEZETAGW_产品规格_3.0版.docx

Binary file not shown.

BIN
Documents/传感器资料/ZETA传感器/JAZE CO2+温湿度.pdf

Binary file not shown.

BIN
Documents/传感器资料/ZETA传感器/JAZE 超声波距离传感器使用手册v1.1.docx

Binary file not shown.

BIN
Documents/传感器资料/ZETA传感器/JAZE 超音波距離センサ_JZUS91A1_仕様書_V1.1_20210622.pdf

Binary file not shown.

BIN
Documents/传感器资料/ZETA传感器/Oviphone健康手环/产品/BG77製品/5G NBIOT体温定位健康手环.docx

Binary file not shown.

BIN
Documents/传感器资料/ZETA传感器/Oviphone健康手环/产品/BG77製品/B2316 CAT-M & NBIOT Smart Band.docx

Binary file not shown.

BIN
Documents/传感器资料/ZETA传感器/Oviphone健康手环/产品/BG77製品/B2316 CAT-M, NBIOT体温监测健康定位手环.docx

Binary file not shown.

BIN
Documents/传感器资料/ZETA传感器/Oviphone健康手环/平台、数据格式/平台,APP和数据对接简介-20210127.docx

Binary file not shown.

BIN
Documents/传感器资料/ZETA传感器/Oviphone健康手环/平台、数据格式/欧孚通信设备通信协议json1127.docx

Binary file not shown.

BIN
Documents/传感器资料/ZETA传感器/skytech/SZC100(CO2+温湿度センサー)取扱い説明書_Rev00.pdf

Binary file not shown.

BIN
Documents/传感器资料/ZETA传感器/skytech/SZT200(高精度傾斜計)取扱い説明書_Rev02.pdf

Binary file not shown.

BIN
Documents/传感器资料/ZETA传感器/skytech/SZW100_センサーデータフォーマット_r05.pdf

Binary file not shown.

BIN
Documents/传感器资料/设备匹配表/NESIC租户KTC项目设备列表_20210805.xlsx

Binary file not shown.

27
TECHSOR_OFFICIAL.pem

@ -0,0 +1,27 @@
-----BEGIN RSA PRIVATE KEY-----
MIIEpAIBAAKCAQEAoXT+WI0CFw06NjKINFhz5y9xs9CeQYHN0+G24fIePPEBPRhW
Faxg36GuFuYKxk59W+Ey8w5Stz8R1wckbU//uaio/P7QhNbl+OpVIKbU93SVW8x6
VH8roTSf+uYh6k6qO5ejAjqiicuEj8dZ8fQWyYSB4X/mLrXg5k5dxKyjhv5nM8RO
vvFHy/uvcdFOAeBbYrq9pHOkSP3BLU+wjutBDmxEdM9YLJk9qOM9bulxr1+QMXNY
4pjpWDlqfM1BpZZDhKzvUqLVjO+QwQ2E8mUgoK2PVY1umC5X8Jlcfy83A77+pKzl
ZKYpLgfLHj7rV5I12uoBx4mvLO1jw6XrNlIb9QIDAQABAoIBAGe+pDxEBwbG4hO3
LpvsBjWT38y6DSZsgNRX4cqXZ+Siu7gFLjNo+ypXWmSuVlgMUTK7pqBVIMNMjGsN
1NNEpz4l6Mf/9/6Tk1v5Ps/nQ0rqJ5q/7g7jVCaWiQGP5FUJTQtTqVOiV5SRKFG2
t83nmMjOEyLRqxdymNuDmW7pu33ebtDZxwm+QeN3nz6TwAbV7Geas5NC1UJLR0+C
nLQh0M9QELv7fKUPiznr6wE9CxB+1fx9es6HJxYK6Q4W+4mjd8CVXXMPDiQhTVEt
jnibk3UfxBQB7fkYP8PUukGq+Z4BgCszoAW0J8gFwiC8YMuzzQw3k83vPCiZZ+JQ
u0hgUPUCgYEA1lQi4mhKNtYMfbVtKEURajvUy5pZw4rzIyo+6XFjE25c3Q/nt3ot
d+vgh6dNCfRll95CB2RKOUoelj3nDeX+aM+QEwwQghLAtAdcRcIhG3DfIYBOJmiw
ugjbk5AW1bc38eQsjtRD7aZMyJjjr2bI7D2D5/MrjqdMZ6sxYdFRmpMCgYEAwNlB
h/Da5kY/z9qcXSnysr78ffU5BLGcxN2At+aXYGKyoR2YQqSME0y1jC9h0w+a7nAx
jCtkz+ozhBkP7o0vRZ8eGbP/65CbPrsY8P9Kpvk7dr2IRMTUjMFihhptGQFrLP3a
g+T2T+gQWS0v5HqiSot6znHZL+jND9elwx8nnFcCgYEAuemhmOL9/TMPArwtQ5El
2hCsNTBeTNBqt0Yd7ED+wAwrYVY6mVzRtARXb1Qf71KgDWwtulu0Rp2Uip6Hnfaz
CBeD0gHVD/9USNVZpOkP7s2pv1WcdJS7N6QXU5jZNekIDjruq7ZUdgCa+iYk2jE+
eC2kDb9RORzFmedVnpQDRSECgYBH26xTXyfxzhNQ/ABvpoXMnOWweYN5gEUOBgtE
eyPEwoIVDtYBXxbiyh6L0cv9vT7Zwex0cmbqIjZ37m7FUM5gft3UbgHaYNO4GDc+
9aF3fj7uC8mO9ljM6fIwTgCA5MpuxVh69QHi3HHbCL9jv15hsH9eFYX8GB7w3EXj
4uP7mQKBgQCFG7l/s1VDsLn9VNpkoUBjZMMdrLCyCWVrTEdeYtZ5LIx3etZxgbah
/rvryIDgc/j7riQgEDnqYk19Ee/HVxK1duJO6d/ywDcSlnNMaChrS8khsMrbK6yI
geqH+9jaaPUVacfeVe0MCIGLxnMiUucIUIyp3VV2OuJ2xx68xqw1wA==
-----END RSA PRIVATE KEY-----

1
cmd

@ -0,0 +1 @@
docker run -d --name test-sender -e redisTimeout=30000 -e redisMaxActive=7000 -e iotcorePort=8883 -e secretkey=Plkid7RDnHc1gGbp2yAv/Scc+ukI0q8vzBuyEBN2 -e businessQueryPushInfoUrl=https://iothub-web-stg.ttkdatatechbuild.com/api/targetConfig/config/v1/queryAlertForwardConfigByAlarmTmplIds -e alarmEmailResultUrl=https://iothub-web-stg.ttkdatatechbuild.com/api/common/logEmailSentResult -e dynamicJdbcUrl=jdbc:mysql://rm-bp11k2zm2fr7864428o.mysql.rds.aliyuncs.com/%s -e defaultRedisCacheTTL=5000 -e JAVA_OPTS="-XX:+UseZGC -Xms1g -Xmx2g -XX:MetaspaceSize=256m -Xlog:gc*:file=/app/gc.log:time,level,tags" -e iotcoreClientId=tkbuild-demo -e jdbcUsername=zhc -e redisShutdownTimeout=30000 -e roidAuthorization="Bearer eyJ0eXAiOiJKV1QiLCJhbGciOiJSUzI1NiJ9..." -e apihost=https://api-sec.test-public-api.kanri-roid.app -e messageProtocol=kinesis -e redisLockExpire=500 -e logLevel=DEBUG -e awsaccesskey=AKIA5OFH5OOZHM3U3KX4 -e dataCenterSenderTargetUrl=http://43.163.243.201:8030/nesic/deviceId/ -e queryPushInfoUrl=https://iothub-web-stg.ttkdatatechbuild.com/api/targetConfig/config/v2/queryAlertForwardConfigByDeviceId -e redisMinIdle=0 -e iotcoreEndpoint=iotcore-mqtts-stg.ttkdatatechbuild.com -e redisMaxIdle=7000 -e redisHost=r-uf63x4g5p6ir5xao87pd.redis.rds.aliyuncs.com -e jdbcPassword=Youqu48bnb1 -e roid2Url="/api/public/v1/targets/{targetId}/monitoring-status" -e env=dev -e mqttNormalTopic=kinesis-to-lambda-stg -e redisPassword=B2BGn4gK4htgkEwP -e redisDatabase=0 -e redisMaxWait=10000 -e jdbcUrl=jdbc:mysql://rm-bp11k2zm2fr7864428o.mysql.rds.aliyuncs.com/data_center_aeon_admin -e roidAlarmCancelUrl="/api/public/v1/problem-reports/return-to-normal" -e redisPort=6379 -e roidAlarmUrl="/api/public/v1/problem-reports/alarm" -e roid2Authorization="Bearer eyJ0eXAiOiJKV1QiLCJhbGciOiJSUzI1NiJ9..." -e roidBaStatusUrl="/api/public/v1/targets/{targetId}/running-status" 923770123186.dkr.ecr.ap-northeast-1.amazonaws.com/tokyo-build-sender

2
deploy.bat

@ -0,0 +1,2 @@
scp -i ./TECHSOR_OFFICIAL.pem ./target/TECHSOR_dataCenter_sender-0.0.1-SNAPSHOT.jar root@8.209.255.206:~
ssh -i ./TECHSOR_OFFICIAL.pem root@8.209.255.206

310
mvnw

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

182
mvnw.cmd

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

533
pom.xml

@ -0,0 +1,533 @@
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>3.2.12</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<groupId>com.techsor</groupId>
<artifactId>TECHSOR_dataCenter_sender</artifactId>
<version>0.0.1-SNAPSHOT</version>
<name>TECHSOR_dataCenter_sender</name>
<description>Demo project for Spring Boot</description>
<properties>
<java.version>17</java.version>
<aws.ecr.registry>381659385655.dkr.ecr.ap-northeast-1.amazonaws.com</aws.ecr.registry>
<aws.ecr.registryTest>923770123186.dkr.ecr.ap-northeast-1.amazonaws.com</aws.ecr.registryTest>
<aws.ecr.repository>tokyo-build-sender</aws.ecr.repository>
</properties>
<dependencyManagement>
<dependencies>
<dependency>
<groupId>software.amazon.awssdk</groupId>
<artifactId>bom</artifactId>
<version>2.20.113</version>
<type>pom</type>
<scope>import</scope>
</dependency>
<dependency>
<groupId>software.amazon.awssdk</groupId>
<artifactId>services</artifactId>
<version>2.20.113</version>
</dependency>
<dependency>
<groupId>software.amazon.kinesis</groupId>
<artifactId>amazon-kinesis-client-pom</artifactId>
<version>3.1.0</version>
</dependency>
<dependency>
<groupId>io.netty</groupId>
<artifactId>netty-common</artifactId>
<version>4.2.2.Final</version>
</dependency>
<dependency>
<groupId>io.netty</groupId>
<artifactId>netty-buffer</artifactId>
<version>4.2.2.Final</version>
</dependency>
<dependency>
<groupId>io.netty</groupId>
<artifactId>netty-resolver</artifactId>
<version>4.2.2.Final</version>
</dependency>
<dependency>
<groupId>io.netty</groupId>
<artifactId>netty-transport</artifactId>
<version>4.2.2.Final</version>
</dependency>
<dependency>
<groupId>io.netty</groupId>
<artifactId>netty-transport-native-unix-common</artifactId>
<version>4.2.2.Final</version>
</dependency>
<dependency>
<groupId>io.netty</groupId>
<artifactId>netty-codec-base</artifactId>
<version>4.2.2.Final</version>
</dependency>
</dependencies>
</dependencyManagement>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
<exclusions>
<exclusion>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-logging</artifactId>
</exclusion>
<exclusion>
<groupId>org.apache.tomcat.embed</groupId>
<artifactId>tomcat-embed-core</artifactId>
</exclusion>
</exclusions>
</dependency>
<!-- https://mvnrepository.com/artifact/org.apache.tomcat.embed/tomcat-embed-core -->
<dependency>
<groupId>org.apache.tomcat.embed</groupId>
<artifactId>tomcat-embed-core</artifactId>
<version>10.1.42</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-redis</artifactId>
<version>2.5.4</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-integration</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.integration</groupId>
<artifactId>spring-integration-redis</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-actuator</artifactId>
</dependency>
<dependency>
<groupId>com.lmax</groupId>
<artifactId>disruptor</artifactId>
<version>3.3.6</version>
</dependency>
<dependency>
<groupId>com.mysql</groupId>
<artifactId>mysql-connector-j</artifactId>
<version>9.3.0</version>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<optional>true</optional>
</dependency>
<!-- https://mvnrepository.com/artifact/com.google.code.gson/gson -->
<dependency>
<groupId>com.google.code.gson</groupId>
<artifactId>gson</artifactId>
<version>2.13.1</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-jdbc</artifactId>
</dependency>
<!-- JSON等格式的转义和反转义 -->
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-text</artifactId>
<version>1.13.1</version>
</dependency>
<!--<dependency>
<groupId>net.sf.json-lib</groupId>
<artifactId>json-lib</artifactId>
<version>2.4</version>
<classifier>jdk15</classifier>
</dependency>-->
<!-- https://mvnrepository.com/artifact/com.alibaba.fastjson2/fastjson2 -->
<dependency>
<groupId>com.alibaba.fastjson2</groupId>
<artifactId>fastjson2</artifactId>
<version>2.0.57</version>
</dependency>
<!-- DBM Godzilla-->
<dependency>
<groupId>godzilla</groupId>
<artifactId>godzilla</artifactId>
<version>1.6.0</version>
<scope>system</scope>
<systemPath>${project.basedir}/src/libs/godzilla-sdk-1.6.0.jar</systemPath>
</dependency>
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-api</artifactId>
<version>2.0.17</version>
</dependency>
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>jul-to-slf4j</artifactId>
<version>1.7.7</version>
</dependency>
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>jcl-over-slf4j</artifactId>
<version>1.7.7</version>
</dependency>
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>log4j-over-slf4j</artifactId>
<version>1.7.7</version>
</dependency>
<!-- https://mvnrepository.com/artifact/ch.qos.logback/logback-classic -->
<dependency>
<groupId>ch.qos.logback</groupId>
<artifactId>logback-classic</artifactId>
<version>1.5.18</version>
<scope>compile</scope>
</dependency>
<dependency>
<groupId>ch.qos.logback</groupId>
<artifactId>logback-core</artifactId>
<version>1.5.18</version>
<scope>compile</scope>
</dependency>
<dependency>
<groupId>org.java-websocket</groupId>
<artifactId>Java-WebSocket</artifactId>
<version>1.5.0</version>
</dependency>
<!-- https://mvnrepository.com/artifact/com.squareup.okhttp3/okhttp -->
<dependency>
<groupId>com.squareup.okhttp3</groupId>
<artifactId>okhttp</artifactId>
<version>4.12.0</version>
</dependency>
<!-- https://mvnrepository.com/artifact/org.apache.commons/commons-pool2 -->
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-pool2</artifactId>
<version>2.11.1</version>
</dependency>
<dependency>
<groupId>org.mockito</groupId>
<artifactId>mockito-core</artifactId>
<version>4.11.0</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>cn.hutool</groupId>
<artifactId>hutool-all</artifactId>
<version>5.8.38</version>
</dependency>
<!-- https://mvnrepository.com/artifact/com.jayway.jsonpath/json-path -->
<dependency>
<groupId>com.jayway.jsonpath</groupId>
<artifactId>json-path</artifactId>
<version>2.9.0</version>
</dependency>
<!-- https://mvnrepository.com/artifact/com.amazonaws/aws-java-sdk-dynamodb -->
<dependency>
<groupId>com.amazonaws</groupId>
<artifactId>aws-java-sdk-dynamodb</artifactId>
<version>1.12.701</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-jpa</artifactId>
</dependency>
<dependency>
<groupId>org.mvel</groupId>
<artifactId>mvel2</artifactId>
<version>2.4.12.Final</version>
</dependency>
<dependency>
<groupId>org.junit.vintage</groupId>
<artifactId>junit-vintage-engine</artifactId>
<version>5.8.2</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>net.bytebuddy</groupId>
<artifactId>byte-buddy</artifactId>
<version>1.8.16</version>
</dependency>
<dependency>
<groupId>net.bytebuddy</groupId>
<artifactId>byte-buddy-agent</artifactId>
<version>1.8.16</version>
<scope>test</scope>
</dependency>
<!-- https://mvnrepository.com/artifact/com.google.guava/guava -->
<dependency>
<groupId>com.google.guava</groupId>
<artifactId>guava</artifactId>
<version>33.4.8-jre</version>
</dependency>
<dependency>
<groupId>org.eclipse.paho</groupId>
<artifactId>org.eclipse.paho.client.mqttv3</artifactId>
<version>1.2.5</version>
</dependency>
<!-- https://mvnrepository.com/artifact/org.bouncycastle/bcprov-jdk18on -->
<dependency>
<groupId>org.bouncycastle</groupId>
<artifactId>bcprov-jdk18on</artifactId>
<version>1.81</version>
</dependency>
<dependency>
<groupId>commons-io</groupId>
<artifactId>commons-io</artifactId>
<version>2.19.0</version>
</dependency>
<!-- &lt;!&ndash; https://mvnrepository.com/artifact/software.amazon.awssdk/dynamodb &ndash;&gt;-->
<!-- <dependency>-->
<!-- <groupId>software.amazon.awssdk</groupId>-->
<!-- <artifactId>dynamodb</artifactId>-->
<!-- <version>2.25.31</version>-->
<!-- </dependency>-->
<!-- https://mvnrepository.com/artifact/javax.mail/mail -->
<dependency>
<groupId>javax.mail</groupId>
<artifactId>mail</artifactId>
<version>1.4.7</version>
</dependency>
<!-- https://mvnrepository.com/artifact/com.amazonaws/amazon-kinesis-producer -->
<dependency>
<groupId>com.amazonaws</groupId>
<artifactId>amazon-kinesis-producer</artifactId>
<version>0.15.10</version>
<exclusions>
<exclusion>
<groupId>org.apache.kafka</groupId>
<artifactId>kafka-clients</artifactId>
</exclusion>
</exclusions>
</dependency>
<!-- https://mvnrepository.com/artifact/org.apache.kafka/kafka-clients -->
<dependency>
<groupId>org.apache.kafka</groupId>
<artifactId>kafka-clients</artifactId>
<version>4.0.0</version>
</dependency>
<dependency>
<groupId>software.amazon.awssdk</groupId>
<artifactId>kinesis</artifactId>
</dependency>
<!-- https://mvnrepository.com/artifact/software.amazon.kinesis/amazon-kinesis-client -->
<!-- https://mvnrepository.com/artifact/software.amazon.kinesis/amazon-kinesis-client -->
<dependency>
<groupId>software.amazon.kinesis</groupId>
<artifactId>amazon-kinesis-client</artifactId>
<version>3.0.3</version>
</dependency>
<dependency>
<groupId>com.amazonaws</groupId>
<artifactId>aws-java-sdk-kinesis</artifactId>
<version>1.12.681</version> <!-- 请检查最新版本 -->
</dependency>
<!-- https://mvnrepository.com/artifact/com.amazonaws/aws-java-sdk-core -->
<dependency>
<groupId>com.amazonaws</groupId>
<artifactId>aws-java-sdk-core</artifactId>
<version>1.12.681</version>
</dependency>
<!-- https://mvnrepository.com/artifact/org.yaml/snakeyaml -->
<dependency>
<groupId>org.yaml</groupId>
<artifactId>snakeyaml</artifactId>
<version>2.4</version>
</dependency>
<!-- https://mvnrepository.com/artifact/org.json/json -->
<dependency>
<groupId>org.json</groupId>
<artifactId>json</artifactId>
<version>20250517</version>
</dependency>
<!-- https://mvnrepository.com/artifact/net.bytebuddy/byte-buddy -->
<dependency>
<groupId>net.bytebuddy</groupId>
<artifactId>byte-buddy</artifactId>
<version>1.17.5</version>
</dependency>
<!-- log4j -->
<dependency>
<groupId>org.apache.logging.log4j</groupId>
<artifactId>log4j-core</artifactId>
<version>2.24.3</version>
</dependency>
<dependency>
<groupId>org.apache.logging.log4j</groupId>
<artifactId>log4j-api</artifactId>
<version>2.24.3</version>
</dependency>
<!-- https://mvnrepository.com/artifact/net.minidev/json-smart -->
<dependency>
<groupId>net.minidev</groupId>
<artifactId>json-smart</artifactId>
<version>2.5.2</version>
</dependency>
<!-- https://mvnrepository.com/artifact/com.google.protobuf/protobuf-java -->
<dependency>
<groupId>com.google.protobuf</groupId>
<artifactId>protobuf-java</artifactId>
<version>4.31.1</version>
</dependency>
<!-- https://mvnrepository.com/artifact/org.apache.commons/commons-compress -->
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-compress</artifactId>
<version>1.27.1</version>
</dependency>
<!-- https://mvnrepository.com/artifact/com.squareup.wire/wire-compiler -->
<dependency>
<groupId>com.squareup.wire</groupId>
<artifactId>wire-compiler</artifactId>
<version>5.2.1</version>
<scope>runtime</scope>
</dependency>
<!-- https://mvnrepository.com/artifact/com.squareup.wire/wire-schema -->
<dependency>
<groupId>com.squareup.wire</groupId>
<artifactId>wire-schema</artifactId>
<version>5.2.1</version>
</dependency>
<!-- https://mvnrepository.com/artifact/org.apache.avro/avro -->
<dependency>
<groupId>org.apache.avro</groupId>
<artifactId>avro</artifactId>
<version>1.12.0</version>
</dependency>
<!-- https://mvnrepository.com/artifact/io.netty/netty-handler -->
<dependency>
<groupId>io.netty</groupId>
<artifactId>netty-handler</artifactId>
<version>4.2.2.Final</version>
</dependency>
<!-- https://mvnrepository.com/artifact/org.springframework/spring-context -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>6.1.21</version>
</dependency>
<!-- https://mvnrepository.com/artifact/org.springframework/spring-context-support -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context-support</artifactId>
<version>6.1.21</version>
</dependency>
<!-- https://mvnrepository.com/artifact/com.github.seratch/jslack -->
<dependency>
<groupId>com.github.seratch</groupId>
<artifactId>jslack</artifactId>
<version>3.4.2</version>
</dependency>
</dependencies>
<build>
<finalName>data-center-sender</finalName>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
<!-- https://mvnrepository.com/artifact/pl.project13.maven/git-commit-id-plugin -->
<plugin>
<groupId>pl.project13.maven</groupId>
<artifactId>git-commit-id-plugin</artifactId>
<version>4.9.10</version>
<executions>
<execution>
<goals>
<goal>revision</goal>
</goals>
</execution>
</executions>
<configuration>
<verbose>true</verbose>
<dateFormat>yyyy-MM-dd'T'HH:mm:ssZ</dateFormat>
<generateGitPropertiesFile>true</generateGitPropertiesFile>
<generateGitPropertiesFilename>${project.build.outputDirectory}/git.properties</generateGitPropertiesFilename>
</configuration>
</plugin>
<!--&lt;!&ndash; 正式环境 &ndash;&gt;-->
<!-- <plugin>-->
<!-- <groupId>io.fabric8</groupId>-->
<!-- <artifactId>docker-maven-plugin</artifactId>-->
<!-- <version>0.38.1</version>-->
<!-- <configuration>-->
<!-- <authConfig>-->
<!-- <username>AKIAVRXFMB43TOELSROK</username>-->
<!-- <password>GYxb5qzuYeEuXLj9/kW9FJB05c2oAu7Cw7j82pLS</password>-->
<!-- </authConfig>-->
<!-- <images>-->
<!-- <image>-->
<!-- <name>${aws.ecr.registry}/${aws.ecr.repository}:latest</name>-->
<!-- <registry>${aws.ecr.registry}</registry>-->
<!-- <build>-->
<!-- <dockerFile>${project.basedir}/Dockerfile</dockerFile>-->
<!-- </build>-->
<!-- </image>-->
<!-- </images>-->
<!-- </configuration>-->
<!-- </plugin>-->
<!-- 测试环境 -->
<plugin>
<groupId>io.fabric8</groupId>
<artifactId>docker-maven-plugin</artifactId>
<version>0.38.1</version>
<configuration>
<authConfig>
<username>AKIA5OFH5OOZPCXZIRUQ</username>
<password>TMIN27+OxamT1FmBQSVKfUIWpOVldhxQx2Stxwix</password>
</authConfig>
<images>
<image>
<name>${aws.ecr.registryTest}/${aws.ecr.repository}:latest</name>
<registry>${aws.ecr.registry}</registry>
<build>
<dockerFile>${project.basedir}/Dockerfile</dockerFile>
</build>
</image>
</images>
</configuration>
</plugin>
</plugins>
</build>
</project>

57
readme.md

@ -0,0 +1,57 @@
# Techsor数据转发系统接收部分
# Version V0.2.1
# DBM
mqtt订阅已经完成
# OviPhone
测试接口:
http://IP:8200/api/v1/oviphone/raw
功能:接收数据并存储进restful_history.
# RoadMap
+ 代码优化
+ 功能实现
+ 测试代码
### docker 环境配置
#### 环境启动问题
aws上应该可以设置环境变量 `env`
`env`=dev
或者
`env`=prd
#### 接收服务器
## ????
```properties
spring.datasource.url=${jdbcUrl} //jdbcUrl
spring.datasource.username=${jdbcUsername} //jdbcUsername
spring.datasource.password=${jdbcPassword} //jdbcPassword
spring.datasource.driver-class-name=com.mysql.jdbc.Driver
spring.datasource.hikari.driver-class-name=com.mysql.jdbc.Driver
spring.datasource.hikari.schema=data_center
spring.redis.host=${redisHost}
spring.redis.password=${redisPassword}
spring.redis.port=${redisPort}
spring.redis.database=${redisDatabase}
spring.redis.timeout=${redisTimeout}
spring.redis.lettuce.pool.max-active=${redisMaxActive}
spring.redis.lettuce.pool.min-idle=${redisMinIdle}
spring.redis.lettuce.pool.max-idle=${redisMaxIdle}
spring.redis.lettuce.pool.max-wait=${redisMaxWait}
spring.redis.lettuce.shutdown-timeout=${redisShutdownTimeout}
data.center.sender.url=${dataCenterSenderTargetUrl}
```

3
shell-build.sh

@ -0,0 +1,3 @@
git pull
mvn clean
mvn package -DskipTests=true docker:build

BIN
src/libs/godzilla-sdk-1.6.0.jar

Binary file not shown.

11
src/main/docker/Dockerfile

@ -0,0 +1,11 @@
FROM openjdk:8u131-jdk
WORKDIR /app
COPY data-center-sender.jar app.jar
EXPOSE 8201
# 使用UseCGroupMemoryLimitForHeap
ENV JAVA_OPTS="-Xms2g -Xmx2g -XX:+UseParallelGC -XX:ParallelGCThreads=2 -XX:MaxGCPauseMillis=200 -XX:GCTimeRatio=19 -XX:NewRatio=3 -XX:+AlwaysPreTouch -XX:+PrintGCDetails -XX:+PrintGCDateStamps -Xloggc:/app/gc.log"
# 使用shell方式的ENTRYPOINT来确保环境变量被展开
ENTRYPOINT java $JAVA_OPTS -jar app.jar --spring-profiles=$env

136
src/main/java/com/baidu/fsg/uid/BitsAllocator.java

@ -0,0 +1,136 @@
/*
* Copyright (c) 2017 Baidu, Inc. All Rights Reserve.
*
* 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
*
* http://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.
*/
package com.baidu.fsg.uid;
import org.apache.commons.lang3.builder.ToStringBuilder;
import org.apache.commons.lang3.builder.ToStringStyle;
import org.springframework.util.Assert;
/**
* Allocate 64 bits for the UID(long)<br>
* sign (fixed 1bit) -> deltaSecond -> workerId -> sequence(within the same second)
*
* @author yutianbao
*/
public class BitsAllocator {
/**
* Total 64 bits
*/
public static final int TOTAL_BITS = 1 << 6;
/**
* Bits for [sign-> second-> workId-> sequence]
*/
private int signBits = 1;
private final int timestampBits;
private final int workerIdBits;
private final int sequenceBits;
/**
* Max value for workId & sequence
*/
private final long maxDeltaSeconds;
private final long maxWorkerId;
private final long maxSequence;
/**
* Shift for timestamp & workerId
*/
private final int timestampShift;
private final int workerIdShift;
/**
* Constructor with timestampBits, workerIdBits, sequenceBits<br>
* The highest bit used for sign, so <code>63</code> bits for timestampBits, workerIdBits, sequenceBits
*/
public BitsAllocator(int timestampBits, int workerIdBits, int sequenceBits) {
// make sure allocated 64 bits
int allocateTotalBits = signBits + timestampBits + workerIdBits + sequenceBits;
Assert.isTrue(allocateTotalBits == TOTAL_BITS, "allocate not enough 64 bits");
// initialize bits
this.timestampBits = timestampBits;
this.workerIdBits = workerIdBits;
this.sequenceBits = sequenceBits;
// initialize max value
this.maxDeltaSeconds = ~(-1L << timestampBits);
this.maxWorkerId = ~(-1L << workerIdBits);
this.maxSequence = ~(-1L << sequenceBits);
// initialize shift
this.timestampShift = workerIdBits + sequenceBits;
this.workerIdShift = sequenceBits;
}
/**
* Allocate bits for UID according to delta seconds & workerId & sequence<br>
* <b>Note that: </b>The highest bit will always be 0 for sign
*
* @param deltaSeconds
* @param workerId
* @param sequence
* @return
*/
public long allocate(long deltaSeconds, long workerId, long sequence) {
return (deltaSeconds << timestampShift) | (workerId << workerIdShift) | sequence;
}
/**
* Getters
*/
public int getSignBits() {
return signBits;
}
public int getTimestampBits() {
return timestampBits;
}
public int getWorkerIdBits() {
return workerIdBits;
}
public int getSequenceBits() {
return sequenceBits;
}
public long getMaxDeltaSeconds() {
return maxDeltaSeconds;
}
public long getMaxWorkerId() {
return maxWorkerId;
}
public long getMaxSequence() {
return maxSequence;
}
public int getTimestampShift() {
return timestampShift;
}
public int getWorkerIdShift() {
return workerIdShift;
}
@Override
public String toString() {
return ToStringBuilder.reflectionToString(this, ToStringStyle.SHORT_PREFIX_STYLE);
}
}

45
src/main/java/com/baidu/fsg/uid/UidGenerator.java

@ -0,0 +1,45 @@
/*
* Copyright (c) 2017 Baidu, Inc. All Rights Reserve.
*
* 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
*
* http://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.
*/
package com.baidu.fsg.uid;
import com.baidu.fsg.uid.exception.UidGenerateException;
/**
* Represents a unique id generator.
*
* @author yutianbao
*/
public interface UidGenerator {
/**
* Get a unique ID
*
* @return UID
* @throws UidGenerateException
*/
long getUID() throws UidGenerateException;
/**
* Parse the UID into elements which are used to generate the UID. <br>
* Such as timestamp & workerId & sequence...
*
* @param uid
* @return Parsed info
*/
String parseUID(long uid);
}

174
src/main/java/com/baidu/fsg/uid/buffer/BufferPaddingExecutor.java

@ -0,0 +1,174 @@
/*
* Copyright (c) 2017 Baidu, Inc. All Rights Reserve.
*
* 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
*
* http://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.
*/
package com.baidu.fsg.uid.buffer;
import com.baidu.fsg.uid.utils.NamingThreadFactory;
import com.baidu.fsg.uid.utils.PaddedAtomicLong;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.util.Assert;
import java.util.List;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicBoolean;
/**
* Represents an executor for padding {@link RingBuffer}<br>
* There are two kinds of executors: one for scheduled padding, the other for padding immediately.
*
* @author yutianbao
*/
public class BufferPaddingExecutor {
private static final Logger LOGGER = LoggerFactory.getLogger(RingBuffer.class);
/** Constants */
private static final String WORKER_NAME = "RingBuffer-Padding-Worker";
private static final String SCHEDULE_NAME = "RingBuffer-Padding-Schedule";
private static final long DEFAULT_SCHEDULE_INTERVAL = 5 * 60L; // 5 minutes
/** Whether buffer padding is running */
private final AtomicBoolean running;
/** We can borrow UIDs from the future, here store the last second we have consumed */
private final PaddedAtomicLong lastSecond;
/** RingBuffer & BufferUidProvider */
private final RingBuffer ringBuffer;
private final BufferedUidProvider uidProvider;
/** Padding immediately by the thread pool */
private final ExecutorService bufferPadExecutors;
/** Padding schedule thread */
private final ScheduledExecutorService bufferPadSchedule;
/** Schedule interval Unit as seconds */
private long scheduleInterval = DEFAULT_SCHEDULE_INTERVAL;
/**
* Constructor with {@link RingBuffer} and {@link BufferedUidProvider}, default use schedule
*
* @param ringBuffer {@link RingBuffer}
* @param uidProvider {@link BufferedUidProvider}
*/
public BufferPaddingExecutor(RingBuffer ringBuffer, BufferedUidProvider uidProvider) {
this(ringBuffer, uidProvider, true);
}
/**
* Constructor with {@link RingBuffer}, {@link BufferedUidProvider}, and whether use schedule padding
*
* @param ringBuffer {@link RingBuffer}
* @param uidProvider {@link BufferedUidProvider}
* @param usingSchedule
*/
public BufferPaddingExecutor(RingBuffer ringBuffer, BufferedUidProvider uidProvider, boolean usingSchedule) {
this.running = new AtomicBoolean(false);
this.lastSecond = new PaddedAtomicLong(TimeUnit.MILLISECONDS.toSeconds(System.currentTimeMillis()));
this.ringBuffer = ringBuffer;
this.uidProvider = uidProvider;
// initialize thread pool
int cores = Runtime.getRuntime().availableProcessors();
bufferPadExecutors = Executors.newFixedThreadPool(cores * 2, new NamingThreadFactory(WORKER_NAME));
// initialize schedule thread
if (usingSchedule) {
bufferPadSchedule = Executors.newSingleThreadScheduledExecutor(new NamingThreadFactory(SCHEDULE_NAME));
} else {
bufferPadSchedule = null;
}
}
/**
* Start executors such as schedule
*/
public void start() {
if (bufferPadSchedule != null) {
bufferPadSchedule.scheduleWithFixedDelay(() -> paddingBuffer(), scheduleInterval, scheduleInterval, TimeUnit.SECONDS);
}
}
/**
* Shutdown executors
*/
public void shutdown() {
if (!bufferPadExecutors.isShutdown()) {
bufferPadExecutors.shutdownNow();
}
if (bufferPadSchedule != null && !bufferPadSchedule.isShutdown()) {
bufferPadSchedule.shutdownNow();
}
}
/**
* Whether is padding
*
* @return
*/
public boolean isRunning() {
return running.get();
}
/**
* Padding buffer in the thread pool
*/
public void asyncPadding() {
bufferPadExecutors.submit(this::paddingBuffer);
}
/**
* Padding buffer fill the slots until to catch the cursor
*/
public void paddingBuffer() {
LOGGER.info("Ready to padding buffer lastSecond:{}. {}", lastSecond.get(), ringBuffer);
// is still running
if (!running.compareAndSet(false, true)) {
LOGGER.info("Padding buffer is still running. {}", ringBuffer);
return;
}
// fill the rest slots until to catch the cursor
boolean isFullRingBuffer = false;
while (!isFullRingBuffer) {
List<Long> uidList = uidProvider.provide(lastSecond.incrementAndGet());
for (Long uid : uidList) {
isFullRingBuffer = !ringBuffer.put(uid);
if (isFullRingBuffer) {
break;
}
}
}
// not running now
running.compareAndSet(true, false);
LOGGER.info("End to padding buffer lastSecond:{}. {}", lastSecond.get(), ringBuffer);
}
/**
* Setters
*/
public void setScheduleInterval(long scheduleInterval) {
Assert.isTrue(scheduleInterval > 0, "Schedule interval must positive!");
this.scheduleInterval = scheduleInterval;
}
}

35
src/main/java/com/baidu/fsg/uid/buffer/BufferedUidProvider.java

@ -0,0 +1,35 @@
/*
* Copyright (c) 2017 Baidu, Inc. All Rights Reserve.
*
* 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
*
* http://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.
*/
package com.baidu.fsg.uid.buffer;
import java.util.List;
/**
* Buffered UID provider(Lambda supported), which provides UID in the same one second
*
* @author yutianbao
*/
@FunctionalInterface
public interface BufferedUidProvider {
/**
* Provides UID in one second
*
* @param momentInSecond
* @return
*/
List<Long> provide(long momentInSecond);
}

34
src/main/java/com/baidu/fsg/uid/buffer/RejectedPutBufferHandler.java

@ -0,0 +1,34 @@
/*
* Copyright (c) 2017 Baidu, Inc. All Rights Reserve.
*
* 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
*
* http://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.
*/
package com.baidu.fsg.uid.buffer;
/**
* If tail catches the cursor it means that the ring buffer is full, any more buffer put request will be rejected.
* Specify the policy to handle the reject. This is a Lambda supported interface
*
* @author yutianbao
*/
@FunctionalInterface
public interface RejectedPutBufferHandler {
/**
* Reject put buffer request
*
* @param ringBuffer
* @param uid
*/
void rejectPutBuffer(RingBuffer ringBuffer, long uid);
}

33
src/main/java/com/baidu/fsg/uid/buffer/RejectedTakeBufferHandler.java

@ -0,0 +1,33 @@
/*
* Copyright (c) 2017 Baidu, Inc. All Rights Reserve.
*
* 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
*
* http://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.
*/
package com.baidu.fsg.uid.buffer;
/**
* If cursor catches the tail it means that the ring buffer is empty, any more buffer take request will be rejected.
* Specify the policy to handle the reject. This is a Lambda supported interface
*
* @author yutianbao
*/
@FunctionalInterface
public interface RejectedTakeBufferHandler {
/**
* Reject take buffer request
*
* @param ringBuffer
*/
void rejectTakeBuffer(RingBuffer ringBuffer);
}

261
src/main/java/com/baidu/fsg/uid/buffer/RingBuffer.java

@ -0,0 +1,261 @@
/*
* Copyright (c) 2017 Baidu, Inc. All Rights Reserve.
*
* 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
*
* http://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.
*/
package com.baidu.fsg.uid.buffer;
import com.baidu.fsg.uid.utils.PaddedAtomicLong;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.util.Assert;
import java.util.concurrent.atomic.AtomicLong;
/**
* Represents a ring buffer based on array.<br>
* Using array could improve read element performance due to the CUP cache line. To prevent
* the side effect of False Sharing, {@link PaddedAtomicLong} is using on 'tail' and 'cursor'<p>
*
* A ring buffer is consisted of:
* <li><b>slots:</b> each element of the array is a slot, which is be set with a UID
* <li><b>flags:</b> flag array corresponding the same index with the slots, indicates whether can take or put slot
* <li><b>tail:</b> a sequence of the max slot position to produce
* <li><b>cursor:</b> a sequence of the min slot position to consume
*
* @author yutianbao
*/
public class RingBuffer {
private static final Logger LOGGER = LoggerFactory.getLogger(RingBuffer.class);
/** Constants */
private static final int START_POINT = -1;
private static final long CAN_PUT_FLAG = 0L;
private static final long CAN_TAKE_FLAG = 1L;
public static final int DEFAULT_PADDING_PERCENT = 50;
/** The size of RingBuffer's slots, each slot hold a UID */
private final int bufferSize;
private final long indexMask;
private final long[] slots;
private final PaddedAtomicLong[] flags;
/** Tail: last position sequence to produce */
private final AtomicLong tail = new PaddedAtomicLong(START_POINT);
/** Cursor: current position sequence to consume */
private final AtomicLong cursor = new PaddedAtomicLong(START_POINT);
/** Threshold for trigger padding buffer*/
private final int paddingThreshold;
/** Reject put/take buffer handle policy */
private RejectedPutBufferHandler rejectedPutHandler = this::discardPutBuffer;
private RejectedTakeBufferHandler rejectedTakeHandler = this::exceptionRejectedTakeBuffer;
/** Executor of padding buffer */
private BufferPaddingExecutor bufferPaddingExecutor;
/**
* Constructor with buffer size, paddingFactor default as {@value #DEFAULT_PADDING_PERCENT}
*
* @param bufferSize must be positive & a power of 2
*/
public RingBuffer(int bufferSize) {
this(bufferSize, DEFAULT_PADDING_PERCENT);
}
/**
* Constructor with buffer size & padding factor
*
* @param bufferSize must be positive & a power of 2
* @param paddingFactor percent in (0 - 100). When the count of rest available UIDs reach the threshold, it will trigger padding buffer<br>
* Sample: paddingFactor=20, bufferSize=1000 -> threshold=1000 * 20 /100,
* padding buffer will be triggered when tail-cursor<threshold
*/
public RingBuffer(int bufferSize, int paddingFactor) {
// check buffer size is positive & a power of 2; padding factor in (0, 100)
Assert.isTrue(bufferSize > 0L, "RingBuffer size must be positive");
Assert.isTrue(Integer.bitCount(bufferSize) == 1, "RingBuffer size must be a power of 2");
Assert.isTrue(paddingFactor > 0 && paddingFactor < 100, "RingBuffer size must be positive");
this.bufferSize = bufferSize;
this.indexMask = bufferSize - 1;
this.slots = new long[bufferSize];
this.flags = initFlags(bufferSize);
this.paddingThreshold = bufferSize * paddingFactor / 100;
}
/**
* Put an UID in the ring & tail moved<br>
* We use 'synchronized' to guarantee the UID fill in slot & publish new tail sequence as atomic operations<br>
*
* <b>Note that: </b> It is recommended to put UID in a serialize way, cause we once batch generate a series UIDs and put
* the one by one into the buffer, so it is unnecessary put in multi-threads
*
* @param uid
* @return false means that the buffer is full, apply {@link RejectedPutBufferHandler}
*/
public synchronized boolean put(long uid) {
long currentTail = tail.get();
long currentCursor = cursor.get();
// tail catches the cursor, means that you can't put any cause of RingBuffer is full
long distance = currentTail - (currentCursor == START_POINT ? 0 : currentCursor);
if (distance == bufferSize - 1) {
rejectedPutHandler.rejectPutBuffer(this, uid);
return false;
}
// 1. pre-check whether the flag is CAN_PUT_FLAG
int nextTailIndex = calSlotIndex(currentTail + 1);
if (flags[nextTailIndex].get() != CAN_PUT_FLAG) {
rejectedPutHandler.rejectPutBuffer(this, uid);
return false;
}
// 2. put UID in the next slot
// 3. update next slot' flag to CAN_TAKE_FLAG
// 4. publish tail with sequence increase by one
slots[nextTailIndex] = uid;
flags[nextTailIndex].set(CAN_TAKE_FLAG);
tail.incrementAndGet();
// The atomicity of operations above, guarantees by 'synchronized'. In another word,
// the take operation can't consume the UID we just put, until the tail is published(tail.incrementAndGet())
return true;
}
/**
* Take an UID of the ring at the next cursor, this is a lock free operation by using atomic cursor<p>
*
* Before getting the UID, we also check whether reach the padding threshold,
* the padding buffer operation will be triggered in another thread<br>
* If there is no more available UID to be taken, the specified {@link RejectedTakeBufferHandler} will be applied<br>
*
* @return UID
* @throws IllegalStateException if the cursor moved back
*/
public long take() {
// spin get next available cursor
long currentCursor = cursor.get();
long nextCursor = cursor.updateAndGet(old -> old == tail.get() ? old : old + 1);
// check for safety consideration, it never occurs
Assert.isTrue(nextCursor >= currentCursor, "Curosr can't move back");
// trigger padding in an async-mode if reach the threshold
long currentTail = tail.get();
if (currentTail - nextCursor < paddingThreshold) {
LOGGER.info("Reach the padding threshold:{}. tail:{}, cursor:{}, rest:{}", paddingThreshold, currentTail,
nextCursor, currentTail - nextCursor);
bufferPaddingExecutor.asyncPadding();
}
// cursor catch the tail, means that there is no more available UID to take
if (nextCursor == currentCursor) {
rejectedTakeHandler.rejectTakeBuffer(this);
}
// 1. check next slot flag is CAN_TAKE_FLAG
int nextCursorIndex = calSlotIndex(nextCursor);
Assert.isTrue(flags[nextCursorIndex].get() == CAN_TAKE_FLAG, "Curosr not in can take status");
// 2. get UID from next slot
// 3. set next slot flag as CAN_PUT_FLAG.
long uid = slots[nextCursorIndex];
flags[nextCursorIndex].set(CAN_PUT_FLAG);
// Note that: Step 2,3 can not swap. If we set flag before get value of slot, the producer may overwrite the
// slot with a new UID, and this may cause the consumer take the UID twice after walk a round the ring
return uid;
}
/**
* Calculate slot index with the slot sequence (sequence % bufferSize)
*/
protected int calSlotIndex(long sequence) {
return (int) (sequence & indexMask);
}
/**
* Discard policy for {@link RejectedPutBufferHandler}, we just do logging
*/
protected void discardPutBuffer(RingBuffer ringBuffer, long uid) {
LOGGER.warn("Rejected putting buffer for uid:{}. {}", uid, ringBuffer);
}
/**
* Policy for {@link RejectedTakeBufferHandler}, throws {@link RuntimeException} after logging
*/
protected void exceptionRejectedTakeBuffer(RingBuffer ringBuffer) {
LOGGER.warn("Rejected take buffer. {}", ringBuffer);
throw new RuntimeException("Rejected take buffer. " + ringBuffer);
}
/**
* Initialize flags as CAN_PUT_FLAG
*/
private PaddedAtomicLong[] initFlags(int bufferSize) {
PaddedAtomicLong[] flags = new PaddedAtomicLong[bufferSize];
for (int i = 0; i < bufferSize; i++) {
flags[i] = new PaddedAtomicLong(CAN_PUT_FLAG);
}
return flags;
}
/**
* Getters
*/
public long getTail() {
return tail.get();
}
public long getCursor() {
return cursor.get();
}
public int getBufferSize() {
return bufferSize;
}
/**
* Setters
*/
public void setBufferPaddingExecutor(BufferPaddingExecutor bufferPaddingExecutor) {
this.bufferPaddingExecutor = bufferPaddingExecutor;
}
public void setRejectedPutHandler(RejectedPutBufferHandler rejectedPutHandler) {
this.rejectedPutHandler = rejectedPutHandler;
}
public void setRejectedTakeHandler(RejectedTakeBufferHandler rejectedTakeHandler) {
this.rejectedTakeHandler = rejectedTakeHandler;
}
@Override
public String toString() {
StringBuilder builder = new StringBuilder();
builder.append("RingBuffer [bufferSize=").append(bufferSize)
.append(", tail=").append(tail)
.append(", cursor=").append(cursor)
.append(", paddingThreshold=").append(paddingThreshold).append("]");
return builder.toString();
}
}

75
src/main/java/com/baidu/fsg/uid/exception/UidGenerateException.java

@ -0,0 +1,75 @@
/*
* Copyright (c) 2017 Baidu, Inc. All Rights Reserve.
*
* 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
*
* http://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.
*/
package com.baidu.fsg.uid.exception;
/**
* UidGenerateException
*
* @author yutianbao
*/
public class UidGenerateException extends RuntimeException {
/**
* Serial Version UID
*/
private static final long serialVersionUID = -27048199131316992L;
/**
* Default constructor
*/
public UidGenerateException() {
super();
}
/**
* Constructor with message & cause
*
* @param message
* @param cause
*/
public UidGenerateException(String message, Throwable cause) {
super(message, cause);
}
/**
* Constructor with message
*
* @param message
*/
public UidGenerateException(String message) {
super(message);
}
/**
* Constructor with message format
*
* @param msgFormat
* @param args
*/
public UidGenerateException(String msgFormat, Object... args) {
super(String.format(msgFormat, args));
}
/**
* Constructor with cause
*
* @param cause
*/
public UidGenerateException(Throwable cause) {
super(cause);
}
}

175
src/main/java/com/baidu/fsg/uid/impl/CachedUidGenerator.java

@ -0,0 +1,175 @@
/*
* Copyright (c) 2017 Baidu, Inc. All Rights Reserve.
*
* 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
*
* http://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.
*/
package com.baidu.fsg.uid.impl;
import com.baidu.fsg.uid.buffer.BufferPaddingExecutor;
import com.baidu.fsg.uid.buffer.RejectedPutBufferHandler;
import com.baidu.fsg.uid.buffer.RejectedTakeBufferHandler;
import com.baidu.fsg.uid.buffer.RingBuffer;
import com.baidu.fsg.uid.exception.UidGenerateException;
import com.baidu.fsg.uid.UidGenerator;
import com.baidu.fsg.uid.BitsAllocator;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.DisposableBean;
import org.springframework.util.Assert;
import java.util.ArrayList;
import java.util.List;
/**
* Represents a cached implementation of {@link UidGenerator} extends
* from {@link DefaultUidGenerator}, based on a lock free {@link RingBuffer}<p>
*
* The spring properties you can specified as below:<br>
* <li><b>boostPower:</b> RingBuffer size boost for a power of 2, Sample: boostPower is 3, it means the buffer size
* will be <code>({@link BitsAllocator#getMaxSequence()} + 1) &lt;&lt;
* {@link #boostPower}</code>, Default as {@value #DEFAULT_BOOST_POWER}
* <li><b>paddingFactor:</b> Represents a percent value of (0 - 100). When the count of rest available UIDs reach the
* threshold, it will trigger padding buffer. Default as{@link RingBuffer#DEFAULT_PADDING_PERCENT}
* Sample: paddingFactor=20, bufferSize=1000 -> threshold=1000 * 20 /100, padding buffer will be triggered when tail-cursor<threshold
* <li><b>scheduleInterval:</b> Padding buffer in a schedule, specify padding buffer interval, Unit as second
* <li><b>rejectedPutBufferHandler:</b> Policy for rejected put buffer. Default as discard put request, just do logging
* <li><b>rejectedTakeBufferHandler:</b> Policy for rejected take buffer. Default as throwing up an exception
*
* @author yutianbao
*/
public class CachedUidGenerator extends DefaultUidGenerator implements DisposableBean {
private static final Logger LOGGER = LoggerFactory.getLogger(CachedUidGenerator.class);
private static final int DEFAULT_BOOST_POWER = 3;
/** Spring properties */
private int boostPower = DEFAULT_BOOST_POWER;
private int paddingFactor = RingBuffer.DEFAULT_PADDING_PERCENT;
private Long scheduleInterval;
private RejectedPutBufferHandler rejectedPutBufferHandler;
private RejectedTakeBufferHandler rejectedTakeBufferHandler;
/** RingBuffer */
private RingBuffer ringBuffer;
private BufferPaddingExecutor bufferPaddingExecutor;
@Override
public void afterPropertiesSet() throws Exception {
// initialize workerId & bitsAllocator
super.afterPropertiesSet();
// initialize RingBuffer & RingBufferPaddingExecutor
this.initRingBuffer();
LOGGER.info("Initialized RingBuffer successfully.");
}
@Override
public long getUID() {
try {
System.out.println("我是cache的uid");
return ringBuffer.take();
} catch (Exception e) {
LOGGER.error("Generate unique id exception. ", e);
throw new UidGenerateException(e);
}
}
@Override
public String parseUID(long uid) {
return super.parseUID(uid);
}
@Override
public void destroy() throws Exception {
bufferPaddingExecutor.shutdown();
}
/**
* Get the UIDs in the same specified second under the max sequence
*
* @param currentSecond
* @return UID list, size of {@link BitsAllocator#getMaxSequence()} + 1
*/
protected List<Long> nextIdsForOneSecond(long currentSecond) {
// Initialize result list size of (max sequence + 1)
int listSize = (int) bitsAllocator.getMaxSequence() + 1;
List<Long> uidList = new ArrayList<>(listSize);
// Allocate the first sequence of the second, the others can be calculated with the offset
long firstSeqUid = bitsAllocator.allocate(currentSecond - epochSeconds, workerId, 0L);
for (int offset = 0; offset < listSize; offset++) {
uidList.add(firstSeqUid + offset);
}
return uidList;
}
/**
* Initialize RingBuffer & RingBufferPaddingExecutor
*/
private void initRingBuffer() {
// initialize RingBuffer
int bufferSize = ((int) bitsAllocator.getMaxSequence() + 1) << boostPower;
this.ringBuffer = new RingBuffer(bufferSize, paddingFactor);
LOGGER.info("Initialized ring buffer size:{}, paddingFactor:{}", bufferSize, paddingFactor);
// initialize RingBufferPaddingExecutor
boolean usingSchedule = (scheduleInterval != null);
this.bufferPaddingExecutor = new BufferPaddingExecutor(ringBuffer, this::nextIdsForOneSecond, usingSchedule);
if (usingSchedule) {
bufferPaddingExecutor.setScheduleInterval(scheduleInterval);
}
LOGGER.info("Initialized BufferPaddingExecutor. Using schdule:{}, interval:{}", usingSchedule, scheduleInterval);
// set rejected put/take handle policy
this.ringBuffer.setBufferPaddingExecutor(bufferPaddingExecutor);
if (rejectedPutBufferHandler != null) {
this.ringBuffer.setRejectedPutHandler(rejectedPutBufferHandler);
}
if (rejectedTakeBufferHandler != null) {
this.ringBuffer.setRejectedTakeHandler(rejectedTakeBufferHandler);
}
// fill in all slots of the RingBuffer
bufferPaddingExecutor.paddingBuffer();
// start buffer padding threads
bufferPaddingExecutor.start();
}
/**
* Setters for spring property
*/
public void setBoostPower(int boostPower) {
Assert.isTrue(boostPower > 0, "Boost power must be positive!");
this.boostPower = boostPower;
}
public void setRejectedPutBufferHandler(RejectedPutBufferHandler rejectedPutBufferHandler) {
Assert.notNull(rejectedPutBufferHandler, "RejectedPutBufferHandler can't be null!");
this.rejectedPutBufferHandler = rejectedPutBufferHandler;
}
public void setRejectedTakeBufferHandler(RejectedTakeBufferHandler rejectedTakeBufferHandler) {
Assert.notNull(rejectedTakeBufferHandler, "RejectedTakeBufferHandler can't be null!");
this.rejectedTakeBufferHandler = rejectedTakeBufferHandler;
}
public void setScheduleInterval(long scheduleInterval) {
Assert.isTrue(scheduleInterval > 0, "Schedule interval must positive!");
this.scheduleInterval = scheduleInterval;
}
}

214
src/main/java/com/baidu/fsg/uid/impl/DefaultUidGenerator.java

@ -0,0 +1,214 @@
/*
* Copyright (c) 2017 Baidu, Inc. All Rights Reserve.
*
* 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
*
* http://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.
*/
package com.baidu.fsg.uid.impl;
import com.baidu.fsg.uid.exception.UidGenerateException;
import com.baidu.fsg.uid.UidGenerator;
import com.baidu.fsg.uid.BitsAllocator;
import com.baidu.fsg.uid.utils.DateUtils;
import com.baidu.fsg.uid.worker.WorkerIdAssigner;
import com.techsor.datacenter.sender.config.UidProperties;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import java.util.Date;
import java.util.concurrent.TimeUnit;
/**
* Represents an implementation of {@link UidGenerator}
*
* The unique id has 64bits (long), default allocated as blow:<br>
* <li>sign: The highest bit is 0
* <li>delta seconds: The next 28 bits, represents delta seconds since a customer epoch(2016-05-20 00:00:00.000).
* Supports about 8.7 years until to 2024-11-20 21:24:16
* <li>worker id: The next 22 bits, represents the worker's id which assigns based on database, max id is about 420W
* <li>sequence: The next 13 bits, represents a sequence within the same second, max for 8192/s<br><br>
*
* The {@link DefaultUidGenerator#parseUID(long)} is a tool method to parse the bits
*
* <pre>{@code
* +------+----------------------+----------------+-----------+
* | sign | delta seconds | worker node id | sequence |
* +------+----------------------+----------------+-----------+
* 1bit 28bits 22bits 13bits
* }</pre>
*
* You can also specified the bits by Spring property setting.
* <li>timeBits: default as 28
* <li>workerBits: default as 22
* <li>seqBits: default as 13
* <li>epochStr: Epoch date string format 'yyyy-MM-dd'. Default as '2016-05-20'<p>
*
* <b>Note that:</b> The total bits must be 64 -1
*
* @author yutianbao
*/
@Component
public class DefaultUidGenerator implements UidGenerator, InitializingBean {
private static final Logger LOGGER = LoggerFactory.getLogger(DefaultUidGenerator.class);
@Autowired
UidProperties uidProperties;
/** Bits allocate */
/**
* timeBits = 31 68年
* workerBits = 17 每天重启5次可用70年
* seqBits = 15 每秒32768个并发
*/
/** Customer epoch, unit as second. For example 2016-05-20 (ms: 1463673600000)*/
/**
* 默认时间更改为2020-10-28毫秒值1603814400000
*/
protected String epochStr = "2023-11-01";
protected long epochSeconds = TimeUnit.MILLISECONDS.toSeconds(1698768000000L);
/** Stable fields after spring bean initializing */
protected BitsAllocator bitsAllocator;
protected long workerId;
/** Volatile fields caused by nextId() */
protected long sequence = 0L;
protected long lastSecond = -1L;
/** Spring property */
@Autowired
protected WorkerIdAssigner workerIdAssigner;
@Override
public void afterPropertiesSet() throws Exception {
// initialize bits allocator
bitsAllocator = new BitsAllocator(uidProperties.getTimeBits(), uidProperties.getWorkerBits(), uidProperties.getSeqBits());
// initialize worker id
workerId = workerIdAssigner.assignWorkerId();
if (workerId > bitsAllocator.getMaxWorkerId()) {
throw new RuntimeException("Worker id " + workerId + " exceeds the max " + bitsAllocator.getMaxWorkerId());
}
LOGGER.info("Initialized bits(1, {}, {}, {}) for workerID:{}", uidProperties.getTimeBits(), uidProperties.getWorkerBits(), uidProperties.getSeqBits(), workerId);
}
@Override
public long getUID() throws UidGenerateException {
try {
return nextId();
} catch (Exception e) {
LOGGER.error("Generate unique id exception. ", e);
throw new UidGenerateException(e);
}
}
@Override
public String parseUID(long uid) {
long totalBits = BitsAllocator.TOTAL_BITS;
long signBits = bitsAllocator.getSignBits();
long timestampBits = bitsAllocator.getTimestampBits();
long workerIdBits = bitsAllocator.getWorkerIdBits();
long sequenceBits = bitsAllocator.getSequenceBits();
// parse UID
long sequence = (uid << (totalBits - sequenceBits)) >>> (totalBits - sequenceBits);
long workerId = (uid << (timestampBits + signBits)) >>> (totalBits - workerIdBits);
long deltaSeconds = uid >>> (workerIdBits + sequenceBits);
Date thatTime = new Date(TimeUnit.SECONDS.toMillis(epochSeconds + deltaSeconds));
String thatTimeStr = DateUtils.formatByDateTimePattern(thatTime);
// format as string
return String.format("{\"UID\":\"%d\",\"timestamp\":\"%s\",\"workerId\":\"%d\",\"sequence\":\"%d\"}",
uid, thatTimeStr, workerId, sequence);
}
/**
* Get UID
*
* @return UID
* @throws UidGenerateException in the case: Clock moved backwards; Exceeds the max timestamp
*/
protected synchronized long nextId() {
long currentSecond = getCurrentSecond();
// Clock moved backwards, refuse to generate uid
if (currentSecond < lastSecond) {
long refusedSeconds = lastSecond - currentSecond;
throw new UidGenerateException("Clock moved backwards. Refusing for %d seconds", refusedSeconds);
}
// At the same second, increase sequence
if (currentSecond == lastSecond) {
sequence = (sequence + 1) & bitsAllocator.getMaxSequence();
// Exceed the max sequence, we wait the next second to generate uid
if (sequence == 0) {
currentSecond = getNextSecond(lastSecond);
}
// At the different second, sequence restart from zero
} else {
sequence = 0L;
}
lastSecond = currentSecond;
// Allocate bits for UID
return bitsAllocator.allocate(currentSecond - epochSeconds, workerId, sequence);
}
/**
* Get next millisecond
*/
private long getNextSecond(long lastTimestamp) {
long timestamp = getCurrentSecond();
while (timestamp <= lastTimestamp) {
timestamp = getCurrentSecond();
}
return timestamp;
}
/**
* Get current second
*/
private long getCurrentSecond() {
long currentSecond = TimeUnit.MILLISECONDS.toSeconds(System.currentTimeMillis());
if (currentSecond - epochSeconds > bitsAllocator.getMaxDeltaSeconds()) {
throw new UidGenerateException("Timestamp bits is exhausted. Refusing UID generate. Now: " + currentSecond);
}
return currentSecond;
}
/**
* Setters for spring property
*/
public void setWorkerIdAssigner(WorkerIdAssigner workerIdAssigner) {
this.workerIdAssigner = workerIdAssigner;
}
public void setEpochStr(String epochStr) {
if (StringUtils.isNotBlank(epochStr)) {
this.epochStr = epochStr;
this.epochSeconds = TimeUnit.MILLISECONDS.toSeconds(DateUtils.parseByDayPattern(epochStr).getTime());
}
}
}

122
src/main/java/com/baidu/fsg/uid/utils/DateUtils.java

@ -0,0 +1,122 @@
/*
* Copyright (c) 2017 Baidu, Inc. All Rights Reserve.
*
* 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
*
* http://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.
*/
package com.baidu.fsg.uid.utils;
import org.apache.commons.lang3.time.DateFormatUtils;
import java.text.ParseException;
import java.util.Calendar;
import java.util.Date;
/**
* DateUtils provides date formatting, parsing
*
* @author yutianbao
*/
public abstract class DateUtils extends org.apache.commons.lang3.time.DateUtils {
/**
* Patterns
*/
public static final String DAY_PATTERN = "yyyy-MM-dd";
public static final String DATETIME_PATTERN = "yyyy-MM-dd HH:mm:ss";
public static final String DATETIME_MS_PATTERN = "yyyy-MM-dd HH:mm:ss.SSS";
public static final Date DEFAULT_DATE = DateUtils.parseByDayPattern("1970-01-01");
/**
* Parse date by 'yyyy-MM-dd' pattern
*
* @param str
* @return
*/
public static Date parseByDayPattern(String str) {
return parseDate(str, DAY_PATTERN);
}
/**
* Parse date by 'yyyy-MM-dd HH:mm:ss' pattern
*
* @param str
* @return
*/
public static Date parseByDateTimePattern(String str) {
return parseDate(str, DATETIME_PATTERN);
}
/**
* Parse date without Checked exception
*
* @param str
* @param pattern
* @return
* @throws RuntimeException when ParseException occurred
*/
public static Date parseDate(String str, String pattern) {
try {
return parseDate(str, new String[]{pattern});
} catch (ParseException e) {
throw new RuntimeException(e);
}
}
/**
* Format date into string
*
* @param date
* @param pattern
* @return
*/
public static String formatDate(Date date, String pattern) {
return DateFormatUtils.format(date, pattern);
}
/**
* Format date by 'yyyy-MM-dd' pattern
*
* @param date
* @return
*/
public static String formatByDayPattern(Date date) {
if (date != null) {
return DateFormatUtils.format(date, DAY_PATTERN);
} else {
return null;
}
}
/**
* Format date by 'yyyy-MM-dd HH:mm:ss' pattern
*
* @param date
* @return
*/
public static String formatByDateTimePattern(Date date) {
return DateFormatUtils.format(date, DATETIME_PATTERN);
}
/**
* Get current day using format date by 'yyyy-MM-dd HH:mm:ss' pattern
*
* @return
* @author yebo
*/
public static String getCurrentDayByDayPattern() {
Calendar cal = Calendar.getInstance();
return formatByDayPattern(cal.getTime());
}
}

104
src/main/java/com/baidu/fsg/uid/utils/DockerUtils.java

@ -0,0 +1,104 @@
/*
* Copyright (c) 2017 Baidu, Inc. All Rights Reserve.
*
* 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
*
* http://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.
*/
package com.baidu.fsg.uid.utils;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
* DockerUtils
*
* @author yutianbao
*/
public abstract class DockerUtils {
private static final Logger LOGGER = LoggerFactory.getLogger(DockerUtils.class);
/** Environment param keys */
private static final String ENV_KEY_HOST = "JPAAS_HOST";
private static final String ENV_KEY_PORT = "JPAAS_HTTP_PORT";
private static final String ENV_KEY_PORT_ORIGINAL = "JPAAS_HOST_PORT_8080";
/** Docker host & port */
private static String DOCKER_HOST = "";
private static String DOCKER_PORT = "";
/** Whether is docker */
private static boolean IS_DOCKER;
static {
retrieveFromEnv();
}
/**
* Retrieve docker host
*
* @return empty string if not a docker
*/
public static String getDockerHost() {
return DOCKER_HOST;
}
/**
* Retrieve docker port
*
* @return empty string if not a docker
*/
public static String getDockerPort() {
return DOCKER_PORT;
}
/**
* Whether a docker
*
* @return
*/
public static boolean isDocker() {
return IS_DOCKER;
}
/**
* Retrieve host & port from environment
*/
private static void retrieveFromEnv() {
// retrieve host & port from environment
DOCKER_HOST = System.getenv(ENV_KEY_HOST);
DOCKER_PORT = System.getenv(ENV_KEY_PORT);
// not found from 'JPAAS_HTTP_PORT', then try to find from 'JPAAS_HOST_PORT_8080'
if (StringUtils.isBlank(DOCKER_PORT)) {
DOCKER_PORT = System.getenv(ENV_KEY_PORT_ORIGINAL);
}
boolean hasEnvHost = StringUtils.isNotBlank(DOCKER_HOST);
boolean hasEnvPort = StringUtils.isNotBlank(DOCKER_PORT);
// docker can find both host & port from environment
if (hasEnvHost && hasEnvPort) {
IS_DOCKER = true;
// found nothing means not a docker, maybe an actual machine
} else if (!hasEnvHost && !hasEnvPort) {
IS_DOCKER = false;
} else {
LOGGER.error("Missing host or port from env for Docker. host:{}, port:{}", DOCKER_HOST, DOCKER_PORT);
throw new RuntimeException(
"Missing host or port from env for Docker. host:" + DOCKER_HOST + ", port:" + DOCKER_PORT);
}
}
}

64
src/main/java/com/baidu/fsg/uid/utils/EnumUtils.java

@ -0,0 +1,64 @@
/*
* Copyright (c) 2017 Baidu, Inc. All Rights Reserve.
*
* 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
*
* http://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.
*/
package com.baidu.fsg.uid.utils;
import org.springframework.util.Assert;
/**
* EnumUtils provides the operations for {@link ValuedEnum} such as Parse, value of...
*
* @author yutianbao
*/
public abstract class EnumUtils {
/**
* Parse the bounded value into ValuedEnum
*
* @param clz
* @param value
* @return
*/
public static <T extends ValuedEnum<V>, V> T parse(Class<T> clz, V value) {
Assert.notNull(clz, "clz can not be null");
if (value == null) {
return null;
}
for (T t : clz.getEnumConstants()) {
if (value.equals(t.value())) {
return t;
}
}
return null;
}
/**
* Null-safe valueOf function
*
* @param <T>
* @param enumType
* @param name
* @return
*/
public static <T extends Enum<T>> T valueOf(Class<T> enumType, String name) {
if (name == null) {
return null;
}
return Enum.valueOf(enumType, name);
}
}

165
src/main/java/com/baidu/fsg/uid/utils/NamingThreadFactory.java

@ -0,0 +1,165 @@
/*
* Copyright (c) 2017 Baidu, Inc. All Rights Reserve.
*
* 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
*
* http://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.
*/
package com.baidu.fsg.uid.utils;
import org.apache.commons.lang3.ClassUtils;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.lang.Thread.UncaughtExceptionHandler;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ThreadFactory;
import java.util.concurrent.atomic.AtomicLong;
/**
* Named thread in ThreadFactory. If there is no specified name for thread, it
* will auto detect using the invoker classname instead.
*
* @author yutianbao
*/
public class NamingThreadFactory implements ThreadFactory {
private static final Logger LOGGER = LoggerFactory.getLogger(NamingThreadFactory.class);
/**
* Thread name pre
*/
private String name;
/**
* Is daemon thread
*/
private boolean daemon;
/**
* UncaughtExceptionHandler
*/
private UncaughtExceptionHandler uncaughtExceptionHandler;
/**
* Sequences for multi thread name prefix
*/
private final ConcurrentHashMap<String, AtomicLong> sequences;
/**
* Constructors
*/
public NamingThreadFactory() {
this(null, false, null);
}
public NamingThreadFactory(String name) {
this(name, false, null);
}
public NamingThreadFactory(String name, boolean daemon) {
this(name, daemon, null);
}
public NamingThreadFactory(String name, boolean daemon, UncaughtExceptionHandler handler) {
this.name = name;
this.daemon = daemon;
this.uncaughtExceptionHandler = handler;
this.sequences = new ConcurrentHashMap<String, AtomicLong>();
}
@Override
public Thread newThread(Runnable r) {
Thread thread = new Thread(r);
thread.setDaemon(this.daemon);
// If there is no specified name for thread, it will auto detect using the invoker classname instead.
// Notice that auto detect may cause some performance overhead
String prefix = this.name;
if (StringUtils.isBlank(prefix)) {
prefix = getInvoker(2);
}
thread.setName(prefix + "-" + getSequence(prefix));
// no specified uncaughtExceptionHandler, just do logging.
if (this.uncaughtExceptionHandler != null) {
thread.setUncaughtExceptionHandler(this.uncaughtExceptionHandler);
} else {
thread.setUncaughtExceptionHandler(new UncaughtExceptionHandler() {
@Override
public void uncaughtException(Thread t, Throwable e) {
LOGGER.error("unhandled exception in thread: " + t.getId() + ":" + t.getName(), e);
}
});
}
return thread;
}
/**
* Get the method invoker's class name
*
* @param depth
* @return
*/
private String getInvoker(int depth) {
Exception e = new Exception();
StackTraceElement[] stes = e.getStackTrace();
if (stes.length > depth) {
return ClassUtils.getShortClassName(stes[depth].getClassName());
}
return getClass().getSimpleName();
}
/**
* Get sequence for different naming prefix
*
* @param invoker
* @return
*/
private long getSequence(String invoker) {
AtomicLong r = this.sequences.get(invoker);
if (r == null) {
r = new AtomicLong(0);
AtomicLong previous = this.sequences.putIfAbsent(invoker, r);
if (previous != null) {
r = previous;
}
}
return r.incrementAndGet();
}
/**
* Getters & Setters
*/
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public boolean isDaemon() {
return daemon;
}
public void setDaemon(boolean daemon) {
this.daemon = daemon;
}
public UncaughtExceptionHandler getUncaughtExceptionHandler() {
return uncaughtExceptionHandler;
}
public void setUncaughtExceptionHandler(UncaughtExceptionHandler handler) {
this.uncaughtExceptionHandler = handler;
}
}

84
src/main/java/com/baidu/fsg/uid/utils/NetUtils.java

@ -0,0 +1,84 @@
/*
* Copyright (c) 2017 Baidu, Inc. All Rights Reserve.
*
* 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
*
* http://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.
*/
package com.baidu.fsg.uid.utils;
import java.net.InetAddress;
import java.net.NetworkInterface;
import java.net.SocketException;
import java.util.Enumeration;
/**
* NetUtils
*
* @author yutianbao
*/
public abstract class NetUtils {
/**
* Pre-loaded local address
*/
public static InetAddress localAddress;
static {
try {
localAddress = getLocalInetAddress();
} catch (SocketException e) {
throw new RuntimeException("fail to get local ip.");
}
}
/**
* Retrieve the first validated local ip address(the Public and LAN ip addresses are validated).
*
* @return the local address
* @throws SocketException the socket exception
*/
public static InetAddress getLocalInetAddress() throws SocketException {
// enumerates all network interfaces
Enumeration<NetworkInterface> enu = NetworkInterface.getNetworkInterfaces();
while (enu.hasMoreElements()) {
NetworkInterface ni = enu.nextElement();
if (ni.isLoopback()) {
continue;
}
Enumeration<InetAddress> addressEnumeration = ni.getInetAddresses();
while (addressEnumeration.hasMoreElements()) {
InetAddress address = addressEnumeration.nextElement();
// ignores all invalidated addresses
if (address.isLinkLocalAddress() || address.isLoopbackAddress() || address.isAnyLocalAddress()) {
continue;
}
return address;
}
}
throw new RuntimeException("No validated local address!");
}
/**
* Retrieve local address
*
* @return the string local address
*/
public static String getLocalAddress() {
return localAddress.getHostAddress();
}
}

52
src/main/java/com/baidu/fsg/uid/utils/PaddedAtomicLong.java

@ -0,0 +1,52 @@
/*
* Copyright (c) 2017 Baidu, Inc. All Rights Reserve.
*
* 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
*
* http://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.
*/
package com.baidu.fsg.uid.utils;
import java.util.concurrent.atomic.AtomicLong;
/**
* Represents a padded {@link AtomicLong} to prevent the FalseSharing problem<p>
*
* The CPU cache line commonly be 64 bytes, here is a sample of cache line after padding:<br>
* 64 bytes = 8 bytes (object reference) + 6 * 8 bytes (padded long) + 8 bytes (a long value)
*
* @author yutianbao
*/
public class PaddedAtomicLong extends AtomicLong {
private static final long serialVersionUID = -3415778863941386253L;
/** Padded 6 long (48 bytes) */
public volatile long p1, p2, p3, p4, p5, p6 = 7L;
/**
* Constructors from {@link AtomicLong}
*/
public PaddedAtomicLong() {
super();
}
public PaddedAtomicLong(long initialValue) {
super(initialValue);
}
/**
* To prevent GC optimizations for cleaning unused padded references
*/
public long sumPaddingToPreventOptimization() {
return p1 + p2 + p3 + p4 + p5 + p6;
}
}

27
src/main/java/com/baidu/fsg/uid/utils/ValuedEnum.java

@ -0,0 +1,27 @@
/*
* Copyright (c) 2017 Baidu, Inc. All Rights Reserve.
*
* 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
*
* http://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.
*/
package com.baidu.fsg.uid.utils;
/**
* {@code ValuedEnum} defines an enumeration which is bounded to a value, you
* may implements this interface when you defines such kind of enumeration, that
* you can use {@link EnumUtils} to simplify parse and valueOf operation.
*
* @author yutianbao
*/
public interface ValuedEnum<T> {
T value();
}

83
src/main/java/com/baidu/fsg/uid/worker/DisposableWorkerIdAssigner.java

@ -0,0 +1,83 @@
/*
* Copyright (c) 2017 Baidu, Inc. All Rights Reserve.
*
* 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
*
* http://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.
*/
package com.baidu.fsg.uid.worker;
import com.baidu.fsg.uid.worker.service.WorkerNodeEntityService;
import com.baidu.fsg.uid.utils.DockerUtils;
import com.baidu.fsg.uid.utils.NetUtils;
import org.apache.commons.lang3.RandomUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.transaction.annotation.Transactional;
import jakarta.annotation.Resource;
import java.time.LocalDate;
import java.time.LocalDateTime;
import com.baidu.fsg.uid.worker.entity.WorkerNodeEntity;
/**
* Represents an implementation of {@link WorkerIdAssigner},
* the worker id will be discarded after assigned to the UidGenerator
*
* @author yutianbao
*/
public class DisposableWorkerIdAssigner implements WorkerIdAssigner {
private static final Logger LOGGER = LoggerFactory.getLogger(DisposableWorkerIdAssigner.class);
@Resource
private WorkerNodeEntityService workerNodeEntityService;
/**
* Assign worker id base on database.<p>
* If there is host name & port in the environment, we considered that the node runs in Docker container<br>
* Otherwise, the node runs on an actual machine.
*
* @return assigned worker id
*/
@Override
@Transactional
public long assignWorkerId() {
// build worker node entity
WorkerNodeEntity workerNodeEntity = buildWorkerNode();
// add worker node for new (ignore the same IP + PORT)
Long id = workerNodeEntityService.save(workerNodeEntity);
LOGGER.info("Add worker node:" + workerNodeEntity);
return id;
}
/**
* Build worker node entity by IP and PORT
*/
private WorkerNodeEntity buildWorkerNode() {
WorkerNodeEntity workerNodeEntity = new WorkerNodeEntity();
if (DockerUtils.isDocker()) {
workerNodeEntity.setType(WorkerNodeType.CONTAINER.value());
workerNodeEntity.setHostName(DockerUtils.getDockerHost());
workerNodeEntity.setPort(DockerUtils.getDockerPort());
} else {
workerNodeEntity.setType(WorkerNodeType.ACTUAL.value());
workerNodeEntity.setHostName(NetUtils.getLocalAddress());
workerNodeEntity.setPort(System.currentTimeMillis() + "-" + RandomUtils.nextInt(0,100000));
}
workerNodeEntity.setLaunchDate(LocalDate.now());
workerNodeEntity.setCreated(LocalDateTime.now());
workerNodeEntity.setModified(LocalDateTime.now());
return workerNodeEntity;
}
}

35
src/main/java/com/baidu/fsg/uid/worker/WorkerIdAssigner.java

@ -0,0 +1,35 @@
/*
* Copyright (c) 2017 Baidu, Inc. All Rights Reserve.
*
* 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
*
* http://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.
*/
package com.baidu.fsg.uid.worker;
import com.baidu.fsg.uid.impl.DefaultUidGenerator;
/**
* Represents a worker id assigner for {@link DefaultUidGenerator}
*
* @author yutianbao
*/
public interface WorkerIdAssigner {
/**
* Assign worker id for {@link DefaultUidGenerator}
*
* @return assigned worker id
*/
long assignWorkerId();
}

49
src/main/java/com/baidu/fsg/uid/worker/WorkerNodeType.java

@ -0,0 +1,49 @@
/*
* Copyright (c) 2017 Baidu, Inc. All Rights Reserve.
*
* 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
*
* http://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.
*/
package com.baidu.fsg.uid.worker;
import com.baidu.fsg.uid.utils.ValuedEnum;
/**
* WorkerNodeType
* <li>CONTAINER: Such as Docker
* <li>ACTUAL: Actual machine
*
* @author yutianbao
*/
public enum WorkerNodeType implements ValuedEnum<Integer> {
CONTAINER(1), ACTUAL(2);
/**
* Lock type
*/
private final Integer type;
/**
* Constructor with field of type
*/
private WorkerNodeType(Integer type) {
this.type = type;
}
@Override
public Integer value() {
return type;
}
}

92
src/main/java/com/baidu/fsg/uid/worker/entity/WorkerNodeEntity.java

@ -0,0 +1,92 @@
package com.baidu.fsg.uid.worker.entity;
import java.time.LocalDate;
import java.time.LocalDateTime;
/**
* @author jason
* @since 2020-10-26
*/
public class WorkerNodeEntity {
private static final long serialVersionUID = 1L;
private Long id;
private String hostName;
private String port;
private Integer type;
private LocalDate launchDate;
private LocalDateTime modified;
private LocalDateTime created;
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
public String getHostName() {
return hostName;
}
public void setHostName(String hostName) {
this.hostName = hostName;
}
public String getPort() {
return port;
}
public void setPort(String port) {
this.port = port;
}
public Integer getType() {
return type;
}
public void setType(Integer type) {
this.type = type;
}
public LocalDate getLaunchDate() {
return launchDate;
}
public void setLaunchDate(LocalDate launchDate) {
this.launchDate = launchDate;
}
public LocalDateTime getModified() {
return modified;
}
public void setModified(LocalDateTime modified) {
this.modified = modified;
}
public LocalDateTime getCreated() {
return created;
}
public void setCreated(LocalDateTime created) {
this.created = created;
}
}

22
src/main/java/com/baidu/fsg/uid/worker/service/WorkerNodeEntityService.java

@ -0,0 +1,22 @@
package com.baidu.fsg.uid.worker.service;
import com.baidu.fsg.uid.worker.entity.WorkerNodeEntity;
/**
* <p>
* 数据库操作解耦 接口
* </p>
*
* @author jason
* @since 2021-10-1
*/
public interface WorkerNodeEntityService {
/**
* 保存实体
*
* @param workerNodeEntity
*/
Long save(WorkerNodeEntity workerNodeEntity);
}

21
src/main/java/com/techsor/datacenter/sender/TechsorDataCenterSenderApplication.java

@ -0,0 +1,21 @@
package com.techsor.datacenter.sender;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cache.annotation.EnableCaching;
import org.springframework.scheduling.annotation.EnableScheduling;
@EnableScheduling
@SpringBootApplication
@EnableCaching
public class TechsorDataCenterSenderApplication {
private static final Logger logger = LoggerFactory.getLogger(TechsorDataCenterSenderApplication.class);
public static void main(String[] args) {
SpringApplication.run(TechsorDataCenterSenderApplication.class, args);
logger.info("TechsorDataCenterSenderApplication started successfully!");
}
}

119
src/main/java/com/techsor/datacenter/sender/compiler/JsonPathExtractor.java

@ -0,0 +1,119 @@
package com.techsor.datacenter.sender.compiler;
import java.lang.reflect.Method;
import java.util.*;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
/**
* JsonPath提取器类用于将包含算术运算函数和JsonPath的中缀表达式转换为逆波兰表示法RPN
* <p>
* 这个类使用正则表达式来分割输入的字符串表达式并基于算法将其转换为RPN队列以便后续的评估和处理
* 支持的功能包括基本的算术运算+-*/和自定义函数
*/
public class JsonPathExtractor {
private static final Set<String> FUNCTIONS = new HashSet<>();
static {
Method[] declaredMethods = UserFunction.class.getDeclaredMethods();
for (Method declaredMethod : declaredMethods) {
FUNCTIONS.add(declaredMethod.getName());
}
}
private boolean containsArithmeticOperator(String s) {
return s.contains("+") || s.contains("-") || s.contains("*") || s.contains("/");
}
private boolean containsFunction(String s) {
return FUNCTIONS.contains(s);
}
/**
* 将中缀表达式转换为逆波兰表示法RPN
* <p>
* 使用Shunting-yard算法来处理中缀表达式并将其转换为后缀表示法以便于表达式的评估
*
* @param infix 中缀表达式字符串
* @return 转换后的RPN表达式队列
*/
public static Queue<String> infixToRPN(String infix) {
Stack<String> operators = new Stack<>();
Queue<String> output = new LinkedList<>();
// 使用正则表达式来分割字符串,这样可以同时处理数字、运算符、括号、JsonPath和函数
Pattern pattern = Pattern.compile("\\$\\..+?(?=\\+|\\-|\\*|\\/|\\)|$)|\\d+|[-+*/()]|" + String.join("|", FUNCTIONS));
Matcher matcher = pattern.matcher(infix);
while (matcher.find()) {
String token = matcher.group();
if (isNumber(token)) {
output.add(token);
} else if (isJsonPath(token)) {
output.add(token);
} else if (FUNCTIONS.contains(token)) {
operators.push(token);
} else if ("(".equals(token)) {
operators.push(token);
} else if (")".equals(token)) {
while (!operators.isEmpty() && !operators.peek().equals("(")) {
output.add(operators.pop());
}
operators.pop(); // Pop "("
if (!operators.isEmpty() && FUNCTIONS.contains(operators.peek())) {
output.add(operators.pop()); // Pop function
}
} else { // Handle operators
while (!operators.isEmpty() && isHigherPrecedence(operators.peek(), token)) {
output.add(operators.pop());
}
operators.push(token);
}
}
while (!operators.isEmpty()) {
output.add(operators.pop());
}
return output;
}
/**
* 比较两个运算符的优先级
*
* @param op1 第一个运算符
* @param op2 第二个运算符
* @return 如果第一个运算符的优先级高于或等于第二个运算符则返回true否则返回false
*/
private static boolean isHigherPrecedence(String op1, String op2) {
if ("+".equals(op1) || "-".equals(op1)) {
return ("*".equals(op2) || "/".equals(op2));
}
return false;
}
/**
* 检查给定的字符串是否是JsonPath
*
* @param s 待检查的字符串
* @return 如果字符串是JsonPath则返回true否则返回false
*/
private static boolean isJsonPath(String s) {
return s.startsWith("$.");
}
/**
* 检查给定的字符串是否可以解析为数字
*
* @param s 待检查的字符串
* @return 如果字符串可以解析为数字则返回true否则返回false
*/
private static boolean isNumber(String s) {
try {
Double.parseDouble(s);
return true;
} catch (NumberFormatException e) {
return false;
}
}
}

71
src/main/java/com/techsor/datacenter/sender/compiler/MvelCompiler.java

@ -0,0 +1,71 @@
package com.techsor.datacenter.sender.compiler;
import org.apache.commons.lang3.StringUtils;
import org.mvel2.MVEL;
import org.mvel2.ParserContext;
import java.io.Serializable;
import java.lang.reflect.Method;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;
/**
* MVEL编译器类用于编译包含自定义函数的MVEL表达式
* <p>
* 该类实现了单例模式确保整个应用中只有一个MVEL编译器实例
* 它预先加载了UserFunction类中定义的所有方法到MVEL解析上下文中以便在表达式中使用这些自定义函数
*/
public class MvelCompiler {
private static final MvelCompiler instance = new MvelCompiler();
private static ParserContext context;
/**
* 私有构造函数初始化MVEL编译器实例
* <p>
* 在构造函数中创建一个ParserContext对象并将UserFunction类中定义的所有方法加载到这个上下文中
*/
private MvelCompiler() {
context = new ParserContext();
// 将UserFunction类中的所有方法加载到context中
Method[] declaredMethods = UserFunction.class.getDeclaredMethods();
for (Method declaredMethod : declaredMethods) {
context.addImport(declaredMethod.getName(), declaredMethod);
}
}
/**
* 获取MvelCompiler类的唯一实例
*
* @return MvelCompiler的单例对象
*/
public static MvelCompiler getInstance() {
return instance;
}
/**
* 获取MVEL编译器的解析上下文
*
* @return MVEL解析上下文
*/
public static ParserContext getContext() {
return context;
}
/**
* 编译给定的MVEL表达式
* <p>
* 如果表达式非空则使用预先配置的解析上下文来编译表达式并返回一个可序列化的编译表达式对象
*
* @param expression 待编译的MVEL表达式字符串
* @return 编译后的可序列化表达式对象如果输入表达式为空则返回null
*/
public Serializable compile(String expression) {
if (StringUtils.isNotEmpty(expression)) {
return MVEL.compileExpression(expression, context);
}
return null;
}
}

37
src/main/java/com/techsor/datacenter/sender/compiler/MvelExecutor.java

@ -0,0 +1,37 @@
package com.techsor.datacenter.sender.compiler;
import lombok.extern.slf4j.Slf4j;
import org.mvel2.MVEL;
import java.util.Map;
/**
* MVEL表达式执行器类用于执行MVEL表达式
* <p>
* 该类提供了一个静态方法来执行给定的MVEL表达式并允许传入参数映射来定义表达式中使用的变量
*/
@Slf4j
public class MvelExecutor {
/**
* 执行给定的MVEL表达式并返回执行结果
* <p>
* 该方法使用 {@link MvelCompiler} 提供的解析上下文来编译表达式然后使用提供的参数映射执行编译后的表达式
* 如果执行过程中发生异常将记录错误日志
*
* @param mvel 表达式字符串
* @param params 表达式中使用的变量的参数映射
* @return 表达式执行的结果如果执行失败返回null
*/
public static Object eval(String mvel, Map<String, Object> params) {
Object result = null;
try {
result = MVEL.executeExpression(MVEL.compileExpression(mvel, MvelCompiler.getContext()), params);
} catch (Exception e) {
log.error("解析失败mvel ========>{}",mvel,e);
}
return String.valueOf(result);
}
}

368
src/main/java/com/techsor/datacenter/sender/compiler/UserFunction.java

@ -0,0 +1,368 @@
package com.techsor.datacenter.sender.compiler;
import com.techsor.datacenter.sender.service.*;
import com.techsor.datacenter.sender.utils.SpringUtils;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
/**
* 提供静态方法处理数据字符串的工具类
*/
@Slf4j
public class UserFunction {
/**
* 使用 OCRInnerService 处理 OCR 数据字符串并返回处理后的数据
*
* @param data 要处理的 OCR 数据字符串
* @return 处理后的 OCR 数据字符串若发生错误则返回原始数据字符串
*/
public static String getOCRDataString(String data){
OCRInnerService ocrInnerService=SpringUtils.getBean("ocrInnerService", OCRInnerService.class);
try {
return ocrInnerService.start(data);
} catch (Exception e) {
log.error("getOCRDataString error",e);
}
return data;
}
/**
* 使用 NBIInnerService 处理 NBI 数据字符串并返回处理后的数据
*
* @param data 要处理的 NBI 数据字符串
* @return 处理后的 NBI 数据字符串若发生错误则返回空字符串
*/
public static String getNBIDataString(String data){
NBIInnerService deltaInnerService=SpringUtils.getBean("nbiInnerService", NBIInnerService.class);
try {
return deltaInnerService.start(data);
} catch (Exception e) {
log.error("getNBIDataString error",e);
}
return "";
}
public static String getDeltaDataString(String data){
StringBuffer stringBuffer=new StringBuffer();
stringBuffer.append("[");
stringBuffer.append(data);
stringBuffer.append("]");
DeltaInnerService deltaInnerService=SpringUtils.getBean("deltaInnerService", DeltaInnerService.class);
try {
return deltaInnerService.start(stringBuffer.toString());
} catch (Exception e) {
log.error("getDeltaDataString error",e);
}
return "";
}
/**
* 使用 KingIOServerService 处理 KingIO 数据字符串并返回处理后的数据
*
* @param data 要处理的 KingIO 数据字符串
* @return 处理后的 KingIO 数据字符串若发生错误则返回空字符串
*/
public static String getKingIODataString(String data){
KingIOServerService kingIOServerService=SpringUtils.getBean("kingIOServerService", KingIOServerService.class);
try {
return kingIOServerService.start(data);
} catch (Exception e) {
log.error("getKingIODataString error",e);
}
return "";
}
/**
* 使用 St150Service 处理 st150 数据字符串并返回处理后的数据
*
* @param data 要处理的 KingIO 数据字符串
* @return 处理后的 KingIO 数据字符串若发生错误则返回空字符串
*/
public static String getSt150DataString(String data){
St150Service st150Service=SpringUtils.getBean("St150Service", St150Service.class);
try {
return st150Service.start(data);
} catch (Exception e) {
log.error("getSt150DataString error",e);
}
return "";
}
/**
* 使用 NittanService 处理 Nittan 数据字符串并返回处理后的数据
*
* @param data 要处理的 Nittan 数据字符串
* @return 处理后的 Nittan 数据字符串若发生错误则返回空字符串
*/
public static String getNittanDataString(String data){
NittanService nittanInnerServiceInstance=SpringUtils.getBean("nittanService", NittanService.class);
try {
return nittanInnerServiceInstance.start(data);
} catch (Exception e) {
log.error("getNittanDataString error",e);
}
return "";
}
public static String getZetaDataString(String data){
ZETAInnerService ZETAInnerServiceInstance=SpringUtils.getBean("ZETAInnerService",ZETAInnerService.class);
return ZETAInnerServiceInstance.start(data);
}
public static String subString(String data, String start, String end) {
int s = Integer.parseInt(start);
int e = Integer.parseInt(end);
return StringUtils.substring(data, s, e);
}
/***
* 函数从左边开始字符串匹配
* **/
public static boolean startWith(String data, String start) {
return StringUtils.startsWith(data, start);
}
/**
*
* 判断字符串是否以end为结尾
* **/
public static boolean endWith(String data, String end) {
return StringUtils.endsWith(data, end);
}
/**
* 判断字符串是否包含containsStr
* **/
public static boolean contains(String data, String containsStr) {
return StringUtils.contains(data, containsStr);
}
/**
* data转换为16进制
* **/
public static String toHex(String data) {
return Integer.toHexString(Integer.parseInt(data));
}
/**
*
* */
public static String toOctal(String data) {
return Integer.toOctalString(Integer.parseInt(data));
}
public static String toBinary(String data) {
return Integer.toBinaryString(Integer.parseInt(data));
}
public static String toDecimal(String data) {
return Integer.toString(Integer.parseInt(data));
}
public static String toHex(String data, String length) {
int len = Integer.parseInt(length);
String tmp = Integer.toHexString(Integer.parseInt(data));
return StringUtils.leftPad(tmp, len, "0");
}
public static String toOctal(String data, String length) {
int len = Integer.parseInt(length);
String tmp = Integer.toOctalString(Integer.parseInt(data));
return StringUtils.leftPad(tmp, len, "0");
}
/**
* 二进制转为十进制
*
* **/
public static Integer binaryToDecimal(String data) {
return Integer.parseInt(data, 2);
}
/**
*
*十六进制转为十进制
* **/
public static Integer hexToDecimal(String data) {
return Integer.parseInt(data, 16);
}
/**
* 第N位为
* @param data 数据字段 random
* @param n N位 80
* @param value (1,2,3,4) 只要其中一个满足就返回true
* @return
*/
public static boolean nthBitEq(String data, String n, String value) {
int m = Integer.parseInt(n);
String tmp = data.substring(m-1, m);
String[] aars = value.split(",");
boolean rs = false;
for (String arr : aars) {
rs = rs || tmp.equals(arr.trim());
}
return rs;
}
/**
* 第N位不为
* @param data 数据字段 random
* @param n N位 80
* @param value (1,2,3,4) 只要其中一个满足就返回false
* @return
*/
public static boolean nthBitNq(String data, String n, String value) {
return !nthBitEq(data,n,value);
}
/**
* 第N位介于 [5,8] >=5 and <=8
* @param data 数据字段 random
* @param n N位 80
* @param sv 开始值 5
* @param ev 结束值 8
* @return
*/
public static boolean nthBitBt(String data, String n, String sv, String ev) {
int m = Integer.parseInt(n);
int tmp = Integer.valueOf(data.substring(m-1, m));
return tmp >= Integer.valueOf(sv) && tmp <= Integer.valueOf(ev);
}
/**
* 倒数第N位为
* @param data 数据字段 random
* @param n 倒数第N位
* @param value (1,2,3,4) 只要其中一个满足就返回true
* @return
*/
public static boolean enBitEq(String data, String n, String value) {
int m = data.length() - Integer.parseInt(n) + 1;
String tmp = data.substring(m-1, m);
String[] airs = value.split(",");
boolean rs = false;
for (String arr : airs) {
rs = rs || tmp.equals(arr.trim());
}
return rs;
}
/**
* 倒数第N位不为
* @param data 数据字段 random
* @param n 倒数第N位
* @param value (1,2,3,4) 只要其中一个满足就返回false
* @return
*/
public static boolean enBitNq(String data, String n, String value) {
return !enBitEq(data,n,value);
}
/**
* 倒数第N位介于 [5,8] >=5 and <=8
* @param data 数据字段 random
* @param n N位 80
* @param sv 开始值 5
* @param ev 结束值 8
* @return
*/
public static boolean enBitBt(String data, String n, String sv, String ev) {
int m = data.length() - Integer.parseInt(n) + 1;
int tmp = Integer.valueOf(data.substring(m-1, m));
return tmp >= Integer.valueOf(sv) && tmp <= Integer.valueOf(ev);
}
/**
* 尾号为
* @param data 数据字段 mid
* @param value (1,2,3,4) 只要其中一个满足就返回true
* @return
*/
public static boolean tailEq(String data, String value) {
String[] airs = value.split(",");
boolean rs = false;
for (String arr : airs) {
rs = rs || data.endsWith(arr.trim());
}
return rs;
}
/**
* 尾号不为
* @param data 数据
* @param value (1,2,3,4) 只要其中一个满足就返回false
* @return
*/
public static boolean tailNq(String data, String value) {
return !tailEq(data, value);
}
/**
* 尾号介于 [5,8] >=5 and <=8
* @param data 数据字段 mid
* @param sv 开始值 5
* @param ev 结束值 8
* @return
*/
public static boolean tailBt(String data, String sv, String ev) {
int tmp = Integer.valueOf(data.substring(data.length()-1, data.length()));
return tmp >= Integer.valueOf(sv) && tmp <= Integer.valueOf(ev);
}
/**
* 包含
* @param data 数据字段 channel
* @param value (F,D,E) 包含其中之一就返回true
* @return
*/
public static boolean defContains(String data, String value) {
String[] arcs = value.split(",");
boolean rs = false;
for (String arr : arcs) {
rs = rs || data.contains(arr.trim());
}
return rs;
}
/**
* 不包含
* @param data 数据字段 channel
* @param value (F,D,E) 包含其中之一就返回false
* @return
*/
public static boolean defNotContains(String data, String value) {
return !defContains(data, value);
}
/**
* 布尔值为真
* @param data 数据字段
*/
public static boolean isTrue(String data) {
return Boolean.parseBoolean(data);
}
/**
* 布尔值为假
* @param data 数据字段
*/
public static boolean isFalse(String data) {
return !Boolean.parseBoolean(data);
}
public static Integer getBooleanIntValue(String data){
if(Boolean.parseBoolean(data)){
return 1;
}
return 0;
}
}

248
src/main/java/com/techsor/datacenter/sender/components/CommonOpt.java

@ -0,0 +1,248 @@
package com.techsor.datacenter.sender.components;
import com.alibaba.fastjson2.JSONArray;
import com.alibaba.fastjson2.JSONObject;
import com.techsor.datacenter.sender.constants.Constants;
import com.techsor.datacenter.sender.dao.CompanyInfoDao;
import com.techsor.datacenter.sender.dao.DeviceDao;
import com.techsor.datacenter.sender.dto.RedisAlarmDTO;
import com.techsor.datacenter.sender.entitiy.DeviceEntity;
import com.techsor.datacenter.sender.entitiy.company.CompanyEntity;
import com.techsor.datacenter.sender.utils.HttpUtil;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.data.redis.connection.lettuce.LettuceConnectionFactory;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Component;
import org.springframework.util.StringUtils;
import jakarta.annotation.Resource;
import java.util.*;
@Component
public class CommonOpt {
private static final Logger log= LoggerFactory.getLogger(CommonOpt.class);
private static final String ALERT_CANCEL_INFO = Constants.ALERT_CANCEL_INFO;
private static final String ALERT_INFO = Constants.ALERT_INFO;
@Resource
private RedisTemplate redisTemplate;
@Resource
private CompanyInfoDao companyInfoDao;
@Resource
DeviceDao deviceDao;
@Resource
private Constants constants;
/**
* Retrieve the company ID associated with the device ID from Redis.
*
* @param deviceId The unique identifier of the device.
* @return The associated company ID, or null if no matching company ID is found.
*/
public String getTopCompanyId(String deviceId){
LettuceConnectionFactory connectionFactory = (LettuceConnectionFactory) redisTemplate.getConnectionFactory();
// log.error("Not Error, For Debug,[redisTemplate] Current Redis Database: " + connectionFactory.getDatabase());
// log.error("Not Error, For Debug,[deviceId]: " + deviceId);
String companyId = (String) redisTemplate.opsForHash().get("deviceCompanyMapping", deviceId);
if (companyId==null){
//Try from mysql
companyId = getCompanyIdFromAllDB(deviceId);
if (companyId.equals("")){
log.error("Can't find topCompanyId for deviceId: "+deviceId+", Please notice if this device is not login on platform.");
return null;
}else{
//Update redis cache
redisTemplate.opsForHash().put("deviceCompanyMapping", deviceId, companyId);
}
}
try{
companyId = companyInfoDao.getTopCompanyId(companyId)+"";
}catch (Exception e){
log.error("Get top companyId Error:",e.getMessage(),e.fillInStackTrace());
}
log.info("GetTopCompanyId:"+companyId);
return companyId;
}
public String getCompanyIdFromAllDB(String deviceId){
String companyId = "";
List<CompanyEntity> companyEntityList = companyInfoDao.getCompanyList();
for (CompanyEntity companyItem : companyEntityList){
String tempCompanyId = "";
log.info("[getCompanyIdFromAllDB] companyId:"+companyItem.getId().toString());
if (companyItem.getParentId()==-1 || companyItem.getParentId()==1){
tempCompanyId = companyItem.getId().toString();
}else{
log.info("[getCompanyIdFromAllDB] Not level 1 company. skip.");
continue;
}
//只处理一级企业
log.info("[getCompanyIdFromAllDB] deviceId:"+deviceId+" comanyId:"+tempCompanyId);
List<DeviceEntity> deviceList = deviceDao.getDeviceInfoByDeviceIdWithDB(deviceId,tempCompanyId);
if (deviceList.size()<=0){
log.info("[getCompanyIdFromAllDB] deviceList size is 0");
continue;
}else{
log.info("[getCompanyIdFromAllDB] companyId get! Value:"+tempCompanyId);
companyId=tempCompanyId;
break;
}
}
log.info("GetCompanyId:"+companyId);
return companyId;
}
public void handleTargetUrl(JSONObject respObject, Map<String, Object> keys) {
if (keys.containsKey("needTransfer") && "true".equalsIgnoreCase(keys.get("needTransfer").toString())) {
String targetData = JSONObject.toJSONString(keys.get("rawData"));
List<String> targetUrlList = new ArrayList<>();
JSONArray dataArr = respObject.getJSONObject("data").getJSONArray("dataList");
if (200 == respObject.getIntValue("code") && null != dataArr) {
for (Object data : dataArr) {
String targetForwardParamsStr = JSONObject.parseObject(data.toString()).getString("targetForwardParams");
if (!StringUtils.isEmpty(targetForwardParamsStr)) {
JSONObject tfpObject = JSONObject.parseObject(targetForwardParamsStr);
targetUrlList.add(tfpObject.getString("url"));
}
}
}
if (null != targetUrlList && !targetUrlList.isEmpty()) {
for (String targetUrl : targetUrlList) {
if (!StringUtils.isEmpty(targetUrl)) {
String pushResp = HttpUtil.doPost(targetUrl, targetData, null);
System.out.println("push alarm result:" + pushResp);
}
}
} else {
System.out.println("alarm push url is null.........");
}
}
}
public String getEmailSubject(String alarmType, int type, Map<String, Object> keys,
JSONObject alertForwardConfig) {
String buildingName = "";
if (keys.containsKey("buildingInfo") && null != keys.get("buildingInfo")) {
JSONObject obj = JSONObject.parseObject(JSONObject.toJSONString(keys.get("buildingInfo")));
buildingName = obj.getString("name");
}
String floorName = "";
if (keys.containsKey("floorInfo") && null != keys.get("floorInfo")) {
JSONObject obj = JSONObject.parseObject(JSONObject.toJSONString(keys.get("floorInfo")));
floorName = obj.getString("name");
}
String spaceName = "";
if (keys.containsKey("spaceInfo") && null != keys.get("spaceInfo")) {
JSONObject obj = JSONObject.parseObject(JSONObject.toJSONString(keys.get("spaceInfo")));
spaceName = obj.getString("name");
}
if (1 == type) {
return String.format(ALERT_INFO, buildingName, floorName, spaceName, alarmType);
} else if (2 == type) {
return String.format(ALERT_CANCEL_INFO, buildingName, floorName, spaceName, alarmType);
}
return "";
}
public void switchAlarmSendMail(int type, String emails, String parseAlertContent, String subject, String deviceId) {
String defaultMemo = "";
if (2 == type) {
defaultMemo = "設備が正常に戻りました";
}
String sendHtml = getMemo(parseAlertContent, defaultMemo);
List<String> emailList = Arrays.asList(emails.contains(",") ? StringUtils.split(emails, ",") : new String[]{emails});
List<String> sendList = new ArrayList(emailList);
//收件人
String receiver = sendList.get(0);
//抄送人
sendList.remove(receiver);
String cc = StringUtils.collectionToDelimitedString(sendList, ",");
String errorMsg = "";
try {
SendMail sendMail = new SendMail();
sendMail.sendMail(subject, sendHtml, receiver, cc);
} catch (Exception e) {
System.out.println("mail sent error:" + e.getMessage());
errorMsg = e.getMessage();
}
//统计邮件成功/失败数量
JSONObject postJsonObject = new JSONObject();
postJsonObject.put("errorMsg", errorMsg);
postJsonObject.put("deviceId", deviceId);
if (StringUtils.isEmpty(errorMsg)) {
postJsonObject.put("status", "Succeeded");
} else {
postJsonObject.put("status", "Failed");
}
String resp = HttpUtil.doPost(constants.EMAIL_RESULT_URL, postJsonObject.toString() , null);
System.out.println("log email result: " + resp);
}
public static String getMemo(String parseAlertContent, String defaultMemo) {
return StringUtils.isEmpty(parseAlertContent) ? defaultMemo : parseAlertContent;
}
public void roid(String parseAlertContent, String emailSubject, Map<String, Object> keys, int type,
RedisAlarmDTO redisAlarmDTO) {
HashMap<String, Object> headerMap = new HashMap<>();
headerMap.put("Content-Type", "application/json;charset=UTF-8");
headerMap.put("access-control-allow-credentials", "True");
headerMap.put("X-Requested-With", "XMLHttpRequest");
headerMap.put("Authorization", constants.ROID_AUTHORIZATION);
headerMap.put("Accept", "application/json, text/plain, /");
if (1 == type) {
JSONObject jsonObject = new JSONObject();
jsonObject.put("problem_report_category_id", Long.valueOf(keys.get("problemReportCategoryId").toString()));
jsonObject.put("target_id", Long.valueOf(keys.get("targetId").toString()));
jsonObject.put("memo", CommonOpt.getMemo(parseAlertContent, "").replace("<br/>", " "));
if(keys.containsKey("buildingId")) {
jsonObject.put("building_id", Long.valueOf(keys.get("buildingId").toString()));
}
// if(keys.containsKey("buildingCode")) {
// jsonObject.put("building_code", keys.get("buildingCode").getS());
// }
String resp = HttpUtil.doPost(constants.ROID_ALARM_URL, jsonObject.toString(), headerMap);
System.out.println("roid alarm api resp : " + resp);
//redis设置状态和id
if (!StringUtils.isEmpty(resp)) {
JSONObject roidRespObject = JSONObject.parseObject(resp);
if (roidRespObject.containsKey("id")) {
redisAlarmDTO.setProblemReportId(roidRespObject.getLongValue("id"));
}
}
} else if (2 == type) {
if (null != redisAlarmDTO && null != redisAlarmDTO.getProblemReportId()) {
JSONObject jsonObject = new JSONObject();
jsonObject.put("problem_report_id", redisAlarmDTO.getProblemReportId());
jsonObject.put("memo", CommonOpt.getMemo(parseAlertContent, emailSubject).replace("<br/>", " "));
String resp = HttpUtil.doPost(constants.ROID_ALARM_CANCEL_URL, jsonObject.toString(), headerMap);
System.out.println("roid cancel alarm api resp : " + resp);
}
}
}
}

57
src/main/java/com/techsor/datacenter/sender/components/DBMRestfulClient.java

@ -0,0 +1,57 @@
package com.techsor.datacenter.sender.components;
import com.techsor.datacenter.sender.config.DataCenterEnvConfig;
import com.techsor.datacenter.sender.entitiy.DBMResponse;
import cn.hutool.http.HttpRequest;
import cn.hutool.json.JSONUtil;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.http.HttpEntity;
import org.springframework.http.HttpHeaders;
import org.springframework.http.MediaType;
import org.springframework.stereotype.Component;
import org.springframework.web.client.RestTemplate;
import jakarta.annotation.Resource;
import java.util.Locale;
@Component
public class DBMRestfulClient {
private static final Logger logger = LoggerFactory.getLogger(DBMRestfulClient.class);
@Resource
private DataCenterEnvConfig dataCenterEnvConfig;
@Resource
private RestTemplate restTemplate;
//post传递json参数
public DBMResponse postJson(String sessionId, String params) {
logger.debug("sessionId: " +sessionId);
params = params.toLowerCase(Locale.ROOT);
//请求参数JOSN类型
HttpHeaders headers = new HttpHeaders();
MediaType type = MediaType.parseMediaType("application/json; charset=UTF-8");
headers.setContentType(type);
// HttpEntity<String> formEntity = new HttpEntity<String>(params, headers);
logger.debug("Post URL: {},{}" ,dataCenterEnvConfig.getJgUrl(),sessionId);
logger.debug("Post msg: {}" ,params);
//转发数据到DBM的正式代码,测试期间注释掉
String responseJson = HttpRequest.post(dataCenterEnvConfig.getJgUrl() + sessionId)
.body(params)
.execute()
.body();
// 将JSON字符串转换为DBMResponse对象
DBMResponse response = JSONUtil.parseObj(responseJson).toBean(DBMResponse.class);
logger.debug("Response Code:{}",response.getCode());
logger.debug("Response msg:{}",response.getMsg());
return response;
}
}

97
src/main/java/com/techsor/datacenter/sender/components/DBMWSClient.java

@ -0,0 +1,97 @@
package com.techsor.datacenter.sender.components;
import com.jurassic.godzilla.sdk.ws.GodzillaWSClientBuilder;
import com.techsor.datacenter.sender.dao.NittanDAO;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.net.URI;
import java.net.URISyntaxException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;
/**
* @Author: hao.dai
* @Project: websocket
* @Date: 2021/5/10 14:47
* @Description:
* @Godzilla.tech
*/
public class DBMWSClient {
private final static Logger logger = LoggerFactory.getLogger(DBMWSClient.class);
public static ScheduledExecutorService executorService;
public static List<Map<String,GodzillaWSClientBuilder>> godzillaWSClientBuilderList = new ArrayList<>();
public static void main(String[] args) throws URISyntaxException, InterruptedException {
GodzillaWSClientBuilder godzillaWSClientBuilder = GodzillaWSClientBuilder.create()
.deviceId("RBTEST0001")
.autoReconnect(true)
.sendHBIntervalTime(1000)
.reconnectIntervalTime(1000)
.godzillaWSDataHandler(message -> {
System.out.println("接收到的消息:" + message);
})
.build(new URI("wss://agent-slb-1.godzilla.tech/"));
godzillaWSClientBuilder.connectBlocking();
ScheduledExecutorService executorService = Executors.newSingleThreadScheduledExecutor();
//10s一次
executorService.scheduleWithFixedDelay(() -> {
godzillaWSClientBuilder.send("{\n" +
" \"temperature\": 25,\n" +
" \"city\": \"Tokyo\"\n" +
"}");
}, 100L, 10000, TimeUnit.MILLISECONDS);
Thread.sleep(90000000);
}
public static void initWS() throws URISyntaxException, InterruptedException {
NittanDAO nittanDAO = new NittanDAO();
List<Map<String, Object>> wsClientList = nittanDAO.getJGWSClient();
for (int i=0;i<wsClientList.size();i++){
GodzillaWSClientBuilder godzillaWSClientBuilder = GodzillaWSClientBuilder.create()
.deviceId((String) wsClientList.get(i).get("client_id"))
.autoReconnect(true)
.sendHBIntervalTime((Integer) wsClientList.get(i).get("heartbeat"))
.reconnectIntervalTime((Integer) wsClientList.get(i).get("reconnect_interval"))
.godzillaWSDataHandler(message -> {
System.out.println("接收到的消息:" + message);
})
.build(new URI("wss://agent-slb-1.godzilla.tech/"));
godzillaWSClientBuilder.connectBlocking();
executorService = Executors.newSingleThreadScheduledExecutor();
//将client_id与客户端实例绑定返回
Map<String,GodzillaWSClientBuilder> item = new HashMap<>();
item.put((String) wsClientList.get(i).get("client_id"),godzillaWSClientBuilder);
godzillaWSClientBuilderList.add(item);
}
}
public static void sendMessage(String clientId,String content) {
if(DBMWSClient.godzillaWSClientBuilderList!=null && DBMWSClient.godzillaWSClientBuilderList.size()>0){
for (Map<String, GodzillaWSClientBuilder> item:DBMWSClient.godzillaWSClientBuilderList
) {
if (item.get(clientId)!=null){
logger.debug("Use client:"+clientId);
item.get(clientId).send(content);
}
}
}
}
public static void sendMessage(String content) {
if(DBMWSClient.godzillaWSClientBuilderList!=null && DBMWSClient.godzillaWSClientBuilderList.size()>0){
logger.debug("Use default client:"+"NEC00003");
DBMWSClient.godzillaWSClientBuilderList.get(0).get("NEC00003").send(content);
logger.debug("Send message: "+content);
}
}
}

26
src/main/java/com/techsor/datacenter/sender/components/GlobalSwitchStatusComponent.java

@ -0,0 +1,26 @@
package com.techsor.datacenter.sender.components;
import org.springframework.stereotype.Component;
import jakarta.annotation.PostConstruct;
import java.util.concurrent.atomic.AtomicBoolean;
@Component
public class GlobalSwitchStatusComponent {
private AtomicBoolean switchStatus;
@PostConstruct
public void init(){
this.switchStatus=new AtomicBoolean(false);
}
public void updateSwitchStatus(boolean switchStatus){
this.switchStatus=new AtomicBoolean(switchStatus);
}
public boolean getSwitchStatus(){
return this.switchStatus.get();
}
}

134
src/main/java/com/techsor/datacenter/sender/components/GuavaRedisCache.java

@ -0,0 +1,134 @@
package com.techsor.datacenter.sender.components;
import com.alibaba.fastjson2.JSON;
import com.google.common.cache.CacheBuilder;
import com.google.common.cache.CacheLoader;
import com.google.common.cache.LoadingCache;
import lombok.extern.slf4j.Slf4j;
import org.slf4j.MDC;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Component;
import jakarta.annotation.PostConstruct;
import java.time.Duration;
import java.time.LocalDate;
import java.time.ZoneId;
import java.time.ZonedDateTime;
import java.time.format.DateTimeFormatter;
import java.util.UUID;
import java.util.concurrent.TimeUnit;
@Slf4j
@Component
public class GuavaRedisCache {
private final LoadingCache<String, Integer> cache;
private final RedisTemplate<String, Object> redisTemplate;
private final GlobalSwitchStatusComponent globalSwitchStatusComponent;
@Autowired
public GuavaRedisCache(RedisTemplate<String, Object> redisTemplate, GlobalSwitchStatusComponent globalSwitchStatusComponent) {
this.redisTemplate = redisTemplate;
this.globalSwitchStatusComponent = globalSwitchStatusComponent;
this.cache = CacheBuilder.newBuilder()
.maximumSize(2000)
.expireAfterWrite(7, TimeUnit.MINUTES)
.concurrencyLevel(1000)
.build(new CacheLoader<>() {
@Override
public Integer load(String key) throws Exception {
return 0;
}
});
}
public void incrementDailyDeviceIdCount(String deviceId) {
// if (this.globalSwitchStatusComponent.getSwitchStatus()) {
String key = getKeyForToday();
cache.put(key + ":" + deviceId, cache.getUnchecked(key + ":" + deviceId) + 1);
// }
}
public void incrementDailyAlertCancelCount(String deviceId) {
// if (this.globalSwitchStatusComponent.getSwitchStatus()) {
String key = getSenderAlertCancelKeyForToday();
cache.put(key + ":" + deviceId, cache.getUnchecked(key + ":" + deviceId) + 1);
// }
}
public void incrementDailyBuildingCount(String deviceId) {
// if (this.globalSwitchStatusComponent.getSwitchStatus()) {
String key = getSenderBuildingKeyForToday();
cache.put(key + ":" + deviceId, cache.getUnchecked(key + ":" + deviceId) + 1);
// }
}
public void incrementDailyDispatchCount(String deviceId) {
// if (this.globalSwitchStatusComponent.getSwitchStatus()) {
String key = getSenderDispatchKeyForToday();
cache.put(key + ":" + deviceId, cache.getUnchecked(key + ":" + deviceId) + 1);
// }
}
public void incrementDailyAlertCount(String deviceId) {
// if (this.globalSwitchStatusComponent.getSwitchStatus()) {
String key = getSenderAlertKeyForToday();
cache.put(key + ":" + deviceId, cache.getUnchecked(key + ":" + deviceId) + 1);
// }
}
private String getKeyForToday() {
LocalDate today = LocalDate.now();
ZoneId japanZone = ZoneId.of("Asia/Tokyo");
ZonedDateTime nowInJapan = ZonedDateTime.now(japanZone);
DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd");
LocalDate yesterdayInJapan = nowInJapan.toLocalDate();
return "sender:device:counts:" + formatter.format(yesterdayInJapan);
}
private String getSenderDeviceKeyForToday() {
LocalDate today = LocalDate.now();
return "sender:device:counts:" + today.format(DateTimeFormatter.ISO_LOCAL_DATE);
}
private String getSenderBuildingKeyForToday() {
LocalDate today = LocalDate.now();
return "sender:building:counts:" + today.format(DateTimeFormatter.ISO_LOCAL_DATE);
}
private String getSenderDispatchKeyForToday() {
LocalDate today = LocalDate.now();
return "sender:dispatch:counts:" + today.format(DateTimeFormatter.ISO_LOCAL_DATE);
}
private String getSenderAlertKeyForToday() {
LocalDate today = LocalDate.now();
return "sender:alert:counts:" + today.format(DateTimeFormatter.ISO_LOCAL_DATE);
}
private String getSenderAlertCancelKeyForToday() {
LocalDate today = LocalDate.now();
return "sender:alert_cancel:counts:" + today.format(DateTimeFormatter.ISO_LOCAL_DATE);
}
public void syncToRedis() {
String requestId = UUID.randomUUID().toString();
MDC.put("requestId", requestId);
log.info("Syncing cache to Redis=============================>");
log.info("Current Cache Size Data {}", cache.size());
log.info("Current Cache Value :{}", JSON.toJSON(cache.asMap()));
cache.asMap().forEach((key, value) -> {
String[] parts = key.split(":");
String redisKey = parts[0] + ":" + parts[1] + ":" + parts[2] + ":" + parts[3];
String deviceId = parts[4];
redisTemplate.opsForHash().increment(redisKey, deviceId, value);
redisTemplate.expire(redisKey, Duration.ofDays(2)); // 设置键2天后过期
});
log.info("Syncing cache to Redis done");
this.cache.invalidateAll();
MDC.clear();
}
}

30
src/main/java/com/techsor/datacenter/sender/components/MdcLogEnhancerFilter.java

@ -0,0 +1,30 @@
package com.techsor.datacenter.sender.components;
import org.springframework.stereotype.Component;
import org.springframework.web.filter.OncePerRequestFilter;
import jakarta.servlet.FilterChain;
import jakarta.servlet.ServletException;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.util.UUID;
import org.slf4j.MDC;
@Component
public class MdcLogEnhancerFilter extends OncePerRequestFilter {
@Override
protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) throws ServletException, IOException {
String requestId = request.getHeader("X-Request-ID");
if (requestId == null || requestId.isEmpty()) {
requestId = UUID.randomUUID().toString();
}
MDC.put("requestId", requestId);
try {
filterChain.doFilter(request, response);
} finally {
MDC.clear();
}
}
}

228
src/main/java/com/techsor/datacenter/sender/components/SendMail.java

@ -0,0 +1,228 @@
package com.techsor.datacenter.sender.components;
import com.alibaba.fastjson2.JSON;
import com.google.gson.Gson;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Component;
import org.springframework.util.StringUtils;
import javax.mail.*;
import javax.mail.internet.InternetAddress;
import javax.mail.internet.MimeMessage;
import javax.mail.internet.MimeUtility;
import javax.net.ssl.SSLSocketFactory;
import java.io.UnsupportedEncodingException;
import java.util.Date;
import java.util.Properties;
/****
* 发送邮件调用邮箱API接口
*
* **/
@Component
public class SendMail {
private static Logger logger = LoggerFactory.getLogger(SendMail.class);
/**
* Message对象将存储我们实际发送的电子邮件信息
* Message对象被作为一个MimeMessage对象来创建并且需要知道应当选择哪一个JavaMail session
*/
private MimeMessage message;
/**
* Session类代表JavaMail中的一个邮件会话
* 每一个基于JavaMail的应用程序至少有一个Session可以有任意多的Session
*
* JavaMail需要Properties来创建一个session对象 寻找"mail.smtp.host" 属性值就是发送邮件的主机
* 寻找"mail.smtp.auth" 身份验证目前免费邮件服务器都需要这一项
*/
private Session session;
/***
* 邮件是既可以被发送也可以被受到JavaMail使用了两个不同的类来完成这两个功能Transport Store Transport
* 是用来发送信息的而Store用来收信对于我们只需要用到Transport对象
*/
private Transport transport;
private String mailHost = "email-smtp.ap-northeast-1.amazonaws.com";
private int mailPort = 465;
private String sender_username = "AKIAVRXFMB43Z4Q6WGZN";
private String sender_password = "BL2KvrpRMDLPmyTqm2yqN9xGi5dQOAMwL/vX4aIrVm6X";
private String email_sendername = "datacenter-info";
private boolean mailSsl = true;
private boolean password_encrypted = false;
private String mail_from="alert@ttkdatatechbuild.com";
/**
*
* @param subject
* @param sendHtml
* @param receiveUser
*/
public void sendMail(String subject, String sendHtml, String receiveUser, String cc){
if(this.mailSsl) {
logger.debug("begin to send mail ssl {},{}",subject,receiveUser);
sendMailSsl(subject, sendHtml, receiveUser, cc);
}else {
logger.debug("begin to send mail doSendHtmlEmail25 {},{}",subject,receiveUser);
doSendHtmlEmail25(subject, sendHtml, receiveUser, cc);
}
}
/**
* 发送邮件
*
* @param subject
* 邮件主题
* @param sendHtml
* 邮件内容
* @param receiveUser
* 收件人地址
* @param cc
*/
public void doSendHtmlEmail25(String subject, String sendHtml, String receiveUser, String cc) {
try {
// 发件人
// InternetAddress from = new InternetAddress(sender_username);
// 下面这个是设置发送人的Nick name
InternetAddress from = new InternetAddress(
MimeUtility.encodeWord(email_sendername) + " <" + mail_from + ">");
message.setFrom(from);
// 收件人
InternetAddress to = new InternetAddress(receiveUser);
message.setRecipient(Message.RecipientType.TO, to);// 还可以有CC、BCC
// InternetAddress cto = new InternetAddress(mail_from);
// message.setRecipient(Message.RecipientType.CC, cto);
if (!StringUtils.isEmpty(cc)) {
message.setRecipients(Message.RecipientType.CC, InternetAddress.parse(cc));
}
// 邮件主题
message.setSubject(subject);
String content = sendHtml.toString();
// 邮件内容,也可以使纯文本"text/plain"
message.setContent(content, "text/html;charset=UTF-8");
// 保存邮件
message.saveChanges();
transport = session.getTransport("smtp");
// smtp验证,就是你用来发邮件的邮箱用户名密码
transport.connect(mailHost, mailPort,sender_username, sender_password);
// 发送
transport.sendMessage(message, message.getAllRecipients());
// System.out.println("send success!");
logger.info("send success");
} catch (Exception e) {
logger.error("[SendMail Error] doSendHtmlEmail25出错", e);
} finally {
if (transport != null) {
try {
transport.close();
} catch (MessagingException e) {
logger.error("[SendMail Error] doSendHtmlEmail25 transport出错", e);
}
}
}
}
public void sendMailSsl(String subject, String sendHtml, String receiveUser, String cc){
try {
final String SSL_FACTORY = SSLSocketFactory.getDefault().getClass().getName();
final Properties p = System.getProperties() ;
p.setProperty("mail.smtp.host", mailHost);
p.setProperty("mail.smtp.auth", "true");
p.setProperty("mail.smtp.ssl.protocols", "TLSv1.2");
p.setProperty("mail.smtp.user", sender_username);
p.setProperty("mail.smtp.pass", sender_password);
p.setProperty("mail.smtp.socketFactory.class", SSL_FACTORY);
p.setProperty("mail.smtp.socketFactory.fallback", "false");
//邮箱发送服务器端口,这里设置为465端口
p.setProperty("mail.smtp.port", mailPort+"");
p.setProperty("mail.smtp.socketFactory.port",mailPort+"");
// 根据邮件会话属性和密码验证器构造一个发送邮件的session
Session session = Session.getInstance(p, new Authenticator(){
protected PasswordAuthentication getPasswordAuthentication() {
return new PasswordAuthentication(p.getProperty("mail.smtp.user"),p.getProperty("mail.smtp.pass"));
}
});
session.setDebug(true);
Message message = new MimeMessage(session);
//消息发送的主题
message.setSubject(subject);
//接受消息的人
message.setReplyTo(InternetAddress.parse(mail_from));
//消息的发送者
InternetAddress from = new InternetAddress(
MimeUtility.encodeWord(email_sendername) + " <" + mail_from + ">");
message.setFrom(from);
// message.setFrom(new InternetAddress(p.getProperty("mail.smtp.user"),sender_username));
// 创建邮件的接收者地址,并设置到邮件消息中
// String[] split = receiveUser.split(",");
// InternetAddress []tos = new InternetAddress[split.length];
// for (int i = 0; i < split.length; i++) {
// tos[i]=new InternetAddress(split[i]);
// }
// 设置抄送人
// if (cc != null && cc.length() > 0) {
// message.setRecipients(Message.RecipientType.CC, InternetAddress.parse(cc));
// }
//message.setRecipients(Message.RecipientType.TO, tos);
InternetAddress to = new InternetAddress(receiveUser);
message.setRecipient(Message.RecipientType.TO, to);// 还可以有CC、BCC
// InternetAddress cto = new InternetAddress(mail_from);
// message.setRecipient(Message.RecipientType.CC, cto);
if (!StringUtils.isEmpty(cc)) {
message.setRecipients(Message.RecipientType.CC, InternetAddress.parse(cc));
}
// 消息发送的时间
message.setSentDate(new Date());
String content = sendHtml.toString();
// 邮件内容,也可以使纯文本"text/plain"
message.setContent(content, "text/html;charset=UTF-8");
// Multipart mainPart = new MimeMultipart();
// // 创建一个包含HTML内容的MimeBodyPart
// BodyPart html = new MimeBodyPart();
// // 设置HTML内容
// html.setContent(sendHtml+ email_urlinfo, "text/html; charset=utf-8");
// mainPart.addBodyPart(html);
// // 将MiniMultipart对象设置为邮件内容
// message.setContent(mainPart);
// // 设置附件
//// if (fileList != null && fileList.length > 0) {
//// for (int i = 0; i < fileList.length; i++) {
//// html = new MimeBodyPart();
//// FileDataSource fds = new FileDataSource(fileList[i]);
//// html.setDataHandler(new DataHandler(fds));
//// html.setFileName(MimeUtility.encodeText(fds.getName(), "UTF-8", "B"));
//// mainPart.addBodyPart(html);
//// }
//// }
// message.setContent(mainPart);
message.saveChanges();
Transport.send(message);
logger.info("send success");
} catch (MessagingException e) {
logger.error("[SendMail Error] sendMail--error:"+e.getMessage(),e);
e.printStackTrace();
} catch (UnsupportedEncodingException e) {
logger.error("[SendMail Error] sendMail--error:"+e.getMessage(),e);
e.printStackTrace();
}
}
}

9
src/main/java/com/techsor/datacenter/sender/config/AsyncConfig.java

@ -0,0 +1,9 @@
package com.techsor.datacenter.sender.config;
import org.springframework.context.annotation.Configuration;
import org.springframework.scheduling.annotation.EnableAsync;
@Configuration
@EnableAsync
public class AsyncConfig {
}

15
src/main/java/com/techsor/datacenter/sender/config/DataCenterEnvConfig.java

@ -0,0 +1,15 @@
package com.techsor.datacenter.sender.config;
import lombok.Data;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Configuration;
@Data
@Configuration
public class DataCenterEnvConfig {
@Value("${data.center.sender.url:#{'http://localhost:8033/nesic/deviceId/'}}")
private String jgUrl;
}

141
src/main/java/com/techsor/datacenter/sender/config/DataSourceAdminConfig.java

@ -0,0 +1,141 @@
package com.techsor.datacenter.sender.config;
import com.zaxxer.hikari.HikariDataSource;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.jdbc.DataSourceBuilder;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Primary;
import org.springframework.jdbc.core.JdbcTemplate;
import javax.sql.DataSource;
import java.util.HashMap;
import java.util.Map;
@Configuration
public class DataSourceAdminConfig {
@Value("${spring.datasource.admin.name}")
private String name;
@Value("${spring.datasource.admin.url}")
private String url;
@Value("${spring.datasource.admin.username}")
private String username;
@Value("${spring.datasource.admin.password}")
private String password;
@Value("${spring.datasource.admin.driverClassName}")
private String driverClassName;
@Value("${spring.datasource.admin.hikari.schema}")
private String schema;
@Value("${spring.datasource.admin.hikari.minimum-idle}")
private Integer mininumIdle;
@Value("${spring.datasource.admin.hikari.maximum-pool-size}")
private Integer maximuPoolSize;
@Value("${spring.datasource.admin.hikari.connection-timeout}")
private Integer connectionTimeout;
@Value("${dynamic.jdbc.url}")
private String dynamicJdbcUrl;
/**
* 获取admin数据源
*
* */
@Primary
@Bean
public DataSource adminDatasource() {
HikariDataSource adminDatasource = DataSourceBuilder.create()
.url(url)
.username(username)
.password(password).driverClassName(driverClassName)
.type(HikariDataSource.class)
.build();
adminDatasource.setSchema(schema);
adminDatasource.setMinimumIdle(mininumIdle);
adminDatasource.setMaximumPoolSize(maximuPoolSize);
adminDatasource.setConnectionTimeout(connectionTimeout);
return adminDatasource;
}
// @Bean
// public DataSource thirdDatasource() {
// String dbUrl=String.format(dynamicJdbcUrl,"data_center_third");
// HikariDataSource adminDatasource = DataSourceBuilder.create()
// .url(dbUrl)
// .username(username)
// .password(password).driverClassName(driverClassName)
// .type(HikariDataSource.class)
// .build();
// adminDatasource.setSchema("data_center_third");
// adminDatasource.setMinimumIdle(mininumIdle);
// adminDatasource.setMaximumPoolSize(maximuPoolSize);
// adminDatasource.setConnectionTimeout(connectionTimeout);
// return adminDatasource;
// }
/**
* 构造jdbcTemplate用于获取动态数据源
* **/
@Bean
public JdbcTemplate adminJdbcTemplate(@Qualifier("adminDatasource") DataSource adminDatasource) {
return new JdbcTemplate(adminDatasource);
}
@Bean
public DataSource dynamicDataSource(JdbcTemplate adminJdbcTemplate,@Qualifier("adminDatasource") DataSource adminDatasource
// ,@Qualifier("thirdDatasource") DataSource thirdDatasource
) {
DynamicRouteDataSource dynamicDataSource = new DynamicRouteDataSource();
Map<Object, Object> targetDataSources = new HashMap<>();
String sql="\t\tSELECT\n" +
"\t\t\tbcom.id,\n" +
"\t\t\tbcom.company_name companyName\n" +
"\t\tFROM\n" +
"\t\t\tdata_center_aeon_admin.basic_company bcom\n" +
"\t\tWHERE bcom.flag != 1";
adminJdbcTemplate.query(sql,rs->{
HikariDataSource dataSource1 = new HikariDataSource();
String dbName="data_center_aeon_"+rs.getInt("id");
String dbUrl=String.format(dynamicJdbcUrl,dbName);
dataSource1.setJdbcUrl(dbUrl);
dataSource1.setUsername(username);
dataSource1.setPassword(password);
dataSource1.setDriverClassName(driverClassName);
dataSource1.setSchema(dbName);
dataSource1.setMinimumIdle(mininumIdle);
dataSource1.setMaximumPoolSize(maximuPoolSize);
dataSource1.setConnectionTimeout(connectionTimeout);
targetDataSources.put("dataSourceForCompany_"+rs.getInt("id"), dataSource1);
});
// targetDataSources.put("dataSourceForCompany_0", thirdDatasource);
dynamicDataSource.setTargetDataSources(targetDataSources);
dynamicDataSource.setDefaultTargetDataSource(adminDatasource); // 设置默认数据源
return dynamicDataSource;
}
@Bean
public JdbcTemplate jdbcTemplate(@Qualifier("dynamicDataSource") DataSource dynamicDataSource) {
return new JdbcTemplate(dynamicDataSource);
}
}

18
src/main/java/com/techsor/datacenter/sender/config/DataSourceContextHolder.java

@ -0,0 +1,18 @@
package com.techsor.datacenter.sender.config;
public class DataSourceContextHolder {
private static final ThreadLocal<String> contextHolder = new ThreadLocal<>();
public static void setCurrentDataSourceKey(String dataSourceKey) {
contextHolder.set(dataSourceKey);
}
public static String getCurrentDataSourceKey() {
return contextHolder.get();
}
public static void clearCurrentDataSourceKey() {
contextHolder.remove();
}
}

12
src/main/java/com/techsor/datacenter/sender/config/DynamicRouteDataSource.java

@ -0,0 +1,12 @@
package com.techsor.datacenter.sender.config;
import org.springframework.jdbc.datasource.lookup.AbstractRoutingDataSource;
public class DynamicRouteDataSource extends AbstractRoutingDataSource {
@Override
protected Object determineCurrentLookupKey() {
return DataSourceContextHolder.getCurrentDataSourceKey();
}
}

17
src/main/java/com/techsor/datacenter/sender/config/GlobalExceptionHandler.java

@ -0,0 +1,17 @@
package com.techsor.datacenter.sender.config;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.bind.annotation.ExceptionHandler;
@ControllerAdvice
public class GlobalExceptionHandler {
@ExceptionHandler(Exception.class)
public ResponseEntity<String> handleException(Exception e) {
return new ResponseEntity<>(e.getMessage(), HttpStatus.OK);
}
}

167
src/main/java/com/techsor/datacenter/sender/config/IotCoreConfiguration.java

@ -0,0 +1,167 @@
package com.techsor.datacenter.sender.config;
import org.apache.commons.lang3.StringUtils;
import org.bouncycastle.jce.provider.BouncyCastleProvider;
import org.eclipse.paho.client.mqttv3.*;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.io.ClassPathResource;
import lombok.extern.slf4j.Slf4j;
import javax.net.ssl.KeyManagerFactory;
import javax.net.ssl.SSLContext;
import javax.net.ssl.TrustManagerFactory;
import java.io.BufferedInputStream;
import java.io.BufferedReader;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.net.URI;
import java.net.URL;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.security.KeyFactory;
import java.security.KeyStore;
import java.security.PrivateKey;
import java.security.Security;
import java.security.cert.CertificateFactory;
import java.security.cert.X509Certificate;
import java.security.spec.PKCS8EncodedKeySpec;
import java.util.Base64;
import java.util.stream.Collectors;
@Configuration
public class IotCoreConfiguration {
private Logger logger = LoggerFactory.getLogger(IotCoreConfiguration.class);
@Value("${iotcore.endpoint}")
private String iotcoreEndpoint;
@Value("${iotcore.port}")
private Integer iotcorePort ;
@Value("${iotcore.clientId}")
private String iotcoreClientId;
@Value("${iotcore.env}")
private String iotcoreEnv;
@Bean
public MqttClient mqttClient() throws Exception {
String brokerUrl = "ssl://" + iotcoreEndpoint + ":" + iotcorePort;
String clientId = iotcoreClientId+ "-" + System.currentTimeMillis();
// String caCertFile = "C:\\Users\\jwy\\Desktop\\TMP\\iotcore\\root-CA.crt";
// String clientCertFile = "C:\\Users\\jwy\\Desktop\\TMP\\iotcore\\tkbuild-thing.cert.pem";
// String privateKeyFile = "C:\\Users\\jwy\\Desktop\\TMP\\iotcore\\tkbuild-thing.private.key";
MqttClient client = null;
try {
logger.info("iotcoreEndpoint:{}", iotcoreEndpoint);
logger.info("iotcorePort:{}", iotcorePort);
logger.info("iotcoreClientId:{}", clientId);
// 加载 BouncyCastle 提供器
Security.addProvider(new BouncyCastleProvider());
// 创建 KeyStore 并加载 CA 证书
CertificateFactory cf = CertificateFactory.getInstance("X.509");
KeyStore keyStore = KeyStore.getInstance(KeyStore.getDefaultType());
keyStore.load(null, null);
// 加载 CA 证书
logger.info("load iotcore.ca.crt......");
InputStream caCertStream = IotCoreConfiguration.class.getResourceAsStream("/ssl/" + iotcoreEnv +"/iotcore.root.pem");
X509Certificate caCert = (X509Certificate) cf.generateCertificate(caCertStream);
keyStore.setCertificateEntry("ca-cert", caCert);
// 加载客户端证书
logger.info("load iotcore.cert.pem......");
InputStream clientCertStream = IotCoreConfiguration.class.getResourceAsStream("/ssl/" + iotcoreEnv +"/iotcore.cert.pem");
X509Certificate clientCert = (X509Certificate) cf.generateCertificate(clientCertStream);
keyStore.setCertificateEntry("client-cert", clientCert);
// 加载私钥
logger.info("load iotcore.private.key......");
PrivateKey privateKey = loadPrivateKey("/ssl/" + iotcoreEnv +"/iotcore.private.key");
keyStore.setKeyEntry("client-key", privateKey, "".toCharArray(), new java.security.cert.Certificate[]{clientCert});
// 设置 KeyManager 和 TrustManager
KeyManagerFactory kmf = KeyManagerFactory.getInstance(KeyManagerFactory.getDefaultAlgorithm());
kmf.init(keyStore, "".toCharArray());
TrustManagerFactory tmf = TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm());
tmf.init(keyStore);
SSLContext sslContext = SSLContext.getInstance("TLSv1.2");
sslContext.init(kmf.getKeyManagers(), tmf.getTrustManagers(), null);
// 创建 MQTT 客户端
MqttConnectOptions options = new MqttConnectOptions();
options.setSocketFactory(sslContext.getSocketFactory());
options.setCleanSession(false);
options.setAutomaticReconnect(true);
options.setKeepAliveInterval(30);
client = new MqttClient(brokerUrl, clientId);
// 设置回调函数
client.setCallback(new MqttCallback() {
@Override
public void connectionLost(Throwable cause) {
logger.error("Connection lost: " + cause.getMessage());
// 自动重连功能会由 MqttClient 自动处理
}
@Override
public void messageArrived(String topic, MqttMessage message) throws Exception {
}
@Override
public void deliveryComplete(IMqttDeliveryToken token) {
logger.info("IotCoreConfiguration Delivery complete: " + token.getMessageId());
}
});
client.connect(options);
logger.info("Connected to AWS IoT Core......");
} catch (Exception e) {
logger.error("Connect to AWS IoT Core error", e);
}
if(null == client) {
logger.error("client is null............");
}
return client;
}
private PrivateKey loadPrivateKey(String filePath) throws Exception {
InputStream inputStream = IotCoreConfiguration.class.getResourceAsStream(filePath);
BufferedReader reader = new BufferedReader(new InputStreamReader(inputStream));
// 过滤掉以 "-----" 开头的行,并合并成单一字符串
String key = reader.lines()
.filter(line -> !line.startsWith("-----"))
.collect(Collectors.joining());
byte[] keyBytes = Base64.getDecoder().decode(key);
PKCS8EncodedKeySpec spec = new PKCS8EncodedKeySpec(keyBytes);
KeyFactory keyFactory = KeyFactory.getInstance("RSA");
return keyFactory.generatePrivate(spec);
}
}

16
src/main/java/com/techsor/datacenter/sender/config/JdbcTemplateConfig.java

@ -0,0 +1,16 @@
//package com.techsor.datacenter.sender.config;
//
//import org.springframework.context.annotation.Bean;
//import org.springframework.context.annotation.Configuration;
//import org.springframework.jdbc.core.JdbcTemplate;
//
//import javax.sql.DataSource;
//
//@Configuration
//public class JdbcTemplateConfig {
//
// @Bean
// public JdbcTemplate jdbcTemplate(DataSource dataSource){
// return new JdbcTemplate(dataSource);
// }
//}

60
src/main/java/com/techsor/datacenter/sender/config/KinesisAutoConfig.java

@ -0,0 +1,60 @@
package com.techsor.datacenter.sender.config;
import com.amazonaws.ClientConfiguration;
import com.amazonaws.auth.AWSCredentials;
import com.amazonaws.auth.AWSCredentialsProvider;
import com.amazonaws.auth.AWSStaticCredentialsProvider;
import com.amazonaws.auth.BasicAWSCredentials;
import com.amazonaws.regions.Regions;
import com.amazonaws.services.kinesis.AmazonKinesis;
import com.amazonaws.services.kinesis.AmazonKinesisClientBuilder;
import com.amazonaws.services.kinesis.producer.KinesisProducer;
import com.amazonaws.services.kinesis.producer.KinesisProducerConfiguration;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import static software.amazon.awssdk.regions.Region.AP_NORTHEAST_1;
@Configuration
public class KinesisAutoConfig {
@Value("${amazon.aws.accesskey}")
private String amazonAWSAccessKey;
@Value("${amazon.aws.secretkey}")
private String amazonAWSSecretKey;
@Bean
public AWSCredentialsProvider amazonAWSCredentialsProvider(AWSCredentials amazonAWSCredentials) {
return new AWSStaticCredentialsProvider(amazonAWSCredentials);
}
@Bean
public AWSCredentials amazonAWSCredentials() {
return new BasicAWSCredentials(amazonAWSAccessKey, amazonAWSSecretKey);
}
@Bean
public AmazonKinesis kinesisConfig(AWSCredentials amazonAWSCredentials) {
ClientConfiguration clientConfiguration=new ClientConfiguration();
clientConfiguration.setMaxErrorRetry(3);
clientConfiguration.setRequestTimeout(100000);
clientConfiguration.setMaxConnections(100000);
clientConfiguration.setUseTcpKeepAlive(true);
clientConfiguration.setUseGzip(false);
clientConfiguration.setClientExecutionTimeout(10000);
clientConfiguration.setConnectionMaxIdleMillis(100000);
return AmazonKinesisClientBuilder.standard()
.withClientConfiguration(clientConfiguration)
.withCredentials(new AWSStaticCredentialsProvider(amazonAWSCredentials))
.withRegion(Regions.AP_NORTHEAST_1) // 选择适合你的区域
.build();
}
}

194
src/main/java/com/techsor/datacenter/sender/config/LettuceRedisConfig.java

@ -0,0 +1,194 @@
package com.techsor.datacenter.sender.config;
import com.fasterxml.jackson.annotation.JsonAutoDetect;
import com.fasterxml.jackson.annotation.PropertyAccessor;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.ser.impl.SimpleBeanPropertyFilter;
import com.fasterxml.jackson.databind.ser.impl.SimpleFilterProvider;
import com.techsor.datacenter.sender.listener.RedisNotificationMessageSubscriber;
import org.apache.commons.pool2.impl.GenericObjectPoolConfig;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Primary;
import org.springframework.context.annotation.Scope;
import org.springframework.core.env.Environment;
import org.springframework.data.redis.connection.RedisConnectionFactory;
import org.springframework.data.redis.connection.RedisStandaloneConfiguration;
import org.springframework.data.redis.connection.lettuce.LettuceConnectionFactory;
import org.springframework.data.redis.connection.lettuce.LettucePoolingClientConfiguration;
import org.springframework.data.redis.core.HashOperations;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.listener.PatternTopic;
import org.springframework.data.redis.listener.RedisMessageListenerContainer;
import org.springframework.data.redis.listener.adapter.MessageListenerAdapter;
import org.springframework.data.redis.serializer.GenericJackson2JsonRedisSerializer;
import org.springframework.data.redis.serializer.RedisSerializer;
import org.springframework.data.redis.serializer.StringRedisSerializer;
import org.springframework.integration.redis.util.RedisLockRegistry;
@Configuration
public class LettuceRedisConfig {
@Value("${alarm.redis.host}")
private String REDIS_HOST;
@Value("${alarm.redis.port}")
private Integer REDIS_PORT;
@Value("${alarm.redis.password}")
private String REDIS_PASSWORD;
@Value("${alarm.redis.database}")
private Integer REDIS_DATABASE;
@Value("${spring.redis.database}")
private Integer SPRING_REDIS_DATABASE;
@Bean("redisConnectionFactory")
public RedisConnectionFactory redisConnectionFactory(){
RedisStandaloneConfiguration redisStandaloneConfiguration = new RedisStandaloneConfiguration();
redisStandaloneConfiguration.setHostName(REDIS_HOST);
redisStandaloneConfiguration.setPort(REDIS_PORT);
if (REDIS_PASSWORD != null && !REDIS_PASSWORD.isEmpty()) {
redisStandaloneConfiguration.setPassword(REDIS_PASSWORD);
}
redisStandaloneConfiguration.setDatabase(SPRING_REDIS_DATABASE);
LettucePoolingClientConfiguration lettucePoolingClientConfiguration = LettucePoolingClientConfiguration.builder()
.poolConfig(new GenericObjectPoolConfig())
.build();
LettuceConnectionFactory lettuceConnectionFactory = new LettuceConnectionFactory(redisStandaloneConfiguration, lettucePoolingClientConfiguration);
return lettuceConnectionFactory;
}
@Bean("alarmRedisConnectionFactory")
public RedisConnectionFactory alarmRedisConnectionFactory(){
RedisStandaloneConfiguration redisStandaloneConfiguration = new RedisStandaloneConfiguration();
redisStandaloneConfiguration.setHostName(REDIS_HOST);
redisStandaloneConfiguration.setPort(REDIS_PORT);
if (REDIS_PASSWORD != null && !REDIS_PASSWORD.isEmpty()) {
redisStandaloneConfiguration.setPassword(REDIS_PASSWORD);
}
redisStandaloneConfiguration.setDatabase(REDIS_DATABASE);
LettucePoolingClientConfiguration lettucePoolingClientConfiguration = LettucePoolingClientConfiguration.builder()
.poolConfig(new GenericObjectPoolConfig())
.build();
LettuceConnectionFactory lettuceConnectionFactory = new LettuceConnectionFactory(redisStandaloneConfiguration, lettucePoolingClientConfiguration);
return lettuceConnectionFactory;
}
@Bean("alramRedisTemplate")
public RedisTemplate<String, Object> alramRedisTemplate(@Qualifier("alarmRedisConnectionFactory") RedisConnectionFactory redisConnectionFactory) {
RedisTemplate<String, Object> redisTemplate = getRedisTemplate(redisConnectionFactory);
return redisTemplate;
}
@Bean("redisTemplate")
public RedisTemplate<String, Object> redisTemplate(@Qualifier("redisConnectionFactory") RedisConnectionFactory redisConnectionFactory) {
RedisTemplate<String, Object> redisTemplate = getRedisTemplate(redisConnectionFactory);
return redisTemplate;
}
@Bean
public HashOperations<String, String, Object> hashOperations(@Qualifier("alramRedisTemplate") RedisTemplate<String, Object> alramRedisTemplate) {
return alramRedisTemplate.opsForHash();
}
@Bean("stringRedisTemplate")
public RedisTemplate<String, Object> stringRedisTemplate(@Qualifier("redisConnectionFactory") RedisConnectionFactory redisConnectionFactory) {
return getStringRedisTemplate(redisConnectionFactory);
}
public RedisTemplate<String, Object> getStringRedisTemplate(RedisConnectionFactory redisConnectionFactory) {
RedisTemplate<String, Object> redisTemplate = new RedisTemplate<>();
redisTemplate.setConnectionFactory(redisConnectionFactory);
RedisSerializer<String> stringSerializer = new StringRedisSerializer();
redisTemplate.setKeySerializer(stringSerializer);
redisTemplate.setHashKeySerializer(stringSerializer);
// 设置序列化接口
ObjectMapper mapper = new ObjectMapper();
mapper.setVisibility(PropertyAccessor.FIELD, JsonAutoDetect.Visibility.ANY);
mapper.setVisibility(PropertyAccessor.GETTER, JsonAutoDetect.Visibility.NONE);
mapper.setVisibility(PropertyAccessor.IS_GETTER, JsonAutoDetect.Visibility.NONE);
SimpleFilterProvider filterProvider = new SimpleFilterProvider();
filterProvider.setDefaultFilter(SimpleBeanPropertyFilter.serializeAll());
mapper.setFilterProvider(filterProvider);
GenericJackson2JsonRedisSerializer jackson2JsonRedisSerializer = new GenericJackson2JsonRedisSerializer(mapper);
// key 序列化
redisTemplate.setKeySerializer(stringSerializer);
// value 序列化
redisTemplate.setValueSerializer(jackson2JsonRedisSerializer);
// Hash key 序列化
redisTemplate.setHashKeySerializer(stringSerializer);
// Hash value 序列化
redisTemplate.setHashValueSerializer(jackson2JsonRedisSerializer);
redisTemplate.afterPropertiesSet();
return redisTemplate;
}
public RedisTemplate getRedisTemplate(RedisConnectionFactory redisConnectionFactory) {
RedisTemplate<String, Object> redisTemplate = new RedisTemplate<>();
redisTemplate.setConnectionFactory(redisConnectionFactory);
RedisSerializer<String> stringSerializer = new StringRedisSerializer();
redisTemplate.setKeySerializer(stringSerializer);
redisTemplate.setHashKeySerializer(stringSerializer);
//设置序列化接口
ObjectMapper mapper = new ObjectMapper();
mapper.setVisibility(PropertyAccessor.FIELD, JsonAutoDetect.Visibility.ANY);
mapper.setVisibility(PropertyAccessor.GETTER, JsonAutoDetect.Visibility.NONE);
mapper.setVisibility(PropertyAccessor.IS_GETTER, JsonAutoDetect.Visibility.NONE);
SimpleFilterProvider filterProvider = new SimpleFilterProvider();
filterProvider.setDefaultFilter(SimpleBeanPropertyFilter.serializeAll());
mapper.setFilterProvider(filterProvider);
GenericJackson2JsonRedisSerializer jackson2JsonRedisSerializer = new GenericJackson2JsonRedisSerializer(mapper);
// key序列化
redisTemplate.setKeySerializer(stringSerializer);
// value序列化
redisTemplate.setValueSerializer(jackson2JsonRedisSerializer);
// Hash key序列化
redisTemplate.setHashKeySerializer(stringSerializer);
// Hash value序列化
redisTemplate.setHashValueSerializer(jackson2JsonRedisSerializer);
redisTemplate.afterPropertiesSet();
return redisTemplate;
}
@Value("${redis.lock.expire}")
private Integer lockAttempTimeout ;
/***
* 定义redis分布式锁
* **/
@Bean
public RedisLockRegistry redisLockRegistry(RedisConnectionFactory redisConnectionFactory){
return new RedisLockRegistry(redisConnectionFactory, "redis-lock",lockAttempTimeout);
}
@Bean
RedisMessageListenerContainer container( @Qualifier("redisConnectionFactory") RedisConnectionFactory connectionFactory,
MessageListenerAdapter listenerAdapter) {
RedisMessageListenerContainer container = new RedisMessageListenerContainer();
container.setConnectionFactory(connectionFactory);
container.addMessageListener(listenerAdapter, new PatternTopic("notificationReceiver"));
return container;
}
@Bean
MessageListenerAdapter listenerAdapter(RedisNotificationMessageSubscriber subscriber) {
return new MessageListenerAdapter(subscriber);
}
}

66
src/main/java/com/techsor/datacenter/sender/config/RestTemplateConfig.java

@ -0,0 +1,66 @@
package com.techsor.datacenter.sender.config;
import okhttp3.ConnectionPool;
import okhttp3.OkHttpClient;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.http.client.ClientHttpRequestFactory;
import org.springframework.http.client.OkHttp3ClientHttpRequestFactory;
import org.springframework.web.client.RestTemplate;
import java.util.concurrent.TimeUnit;
/***
* 使用okhttp connectionFactory
* **/
@Configuration
public class RestTemplateConfig {
@Value("${ok.http.connect-timeout}")
private Integer connectTimeout;
@Value("${ok.http.read-timeout}")
private Integer readTimeout;
@Value("${ok.http.write-timeout}")
private Integer writeTimeout;
@Value("${ok.http.max-idle-connections}")
private Integer maxIdleConnections;
@Value("${ok.http.keep-alive-duration}")
private Long keepAliveDuration;
/**
* 声明 RestTemplate
*/
@Bean
public RestTemplate httpRestTemplate() {
ClientHttpRequestFactory factory = httpRequestFactory();
RestTemplate restTemplate = new RestTemplate(factory);
return restTemplate;
}
public ClientHttpRequestFactory httpRequestFactory() {
return new OkHttp3ClientHttpRequestFactory(okHttpConfigClient());
}
public OkHttpClient okHttpConfigClient(){
return new OkHttpClient().newBuilder()
.connectionPool(pool())
.connectTimeout(connectTimeout, TimeUnit.SECONDS)
.readTimeout(readTimeout, TimeUnit.SECONDS)
.writeTimeout(writeTimeout, TimeUnit.SECONDS)
.hostnameVerifier((hostname, session) -> true)
.build();
}
public ConnectionPool pool() {
return new ConnectionPool(maxIdleConnections, keepAliveDuration, TimeUnit.SECONDS);
}
}

80
src/main/java/com/techsor/datacenter/sender/config/SysMqttConfiguration.java

@ -0,0 +1,80 @@
package com.techsor.datacenter.sender.config;
import org.eclipse.paho.client.mqttv3.*;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
//@Configuration
public class SysMqttConfiguration {
private static final Logger log = LoggerFactory.getLogger(SysMqttConfiguration.class);
@Value("${sys.mqtt.endpoint}")
private String sysMqttEndpoint;
@Value("${sys.mqtt.port}")
private int sysMqttPort;
@Value("${sys.mqtt.username}")
private String sysMqttUsername;
@Value("${sys.mqtt.password}")
private String sysMqttPassword;
@Value("${sys.mqtt.clientId}")
private String sysMqttClientId;
@Bean(name = "sysMqttClient")
public MqttClient sysMqttClient() {
try {
String brokerUrl = "tcp://" + sysMqttEndpoint + ":" + sysMqttPort;
String clientId = sysMqttClientId + "-" + System.currentTimeMillis();
log.info("Initializing SYS MQTT client: {}", clientId);
log.info("Broker: {}", brokerUrl);
MqttClient client = new MqttClient(brokerUrl, clientId, null);
MqttConnectOptions options = new MqttConnectOptions();
options.setCleanSession(true);
options.setAutomaticReconnect(true);
options.setKeepAliveInterval(30);
if (sysMqttUsername != null && !sysMqttUsername.isEmpty()) {
options.setUserName(sysMqttUsername);
}
if (sysMqttPassword != null && !sysMqttPassword.isEmpty()) {
options.setPassword(sysMqttPassword.toCharArray());
}
client.setCallback(new MqttCallback() {
@Override
public void connectionLost(Throwable cause) {
log.warn("SYS MQTT connection lost: {}", cause.getMessage());
}
@Override
public void messageArrived(String topic, MqttMessage message) {
log.info("SYS MQTT message arrived. Topic: {}, Message: {}", topic, new String(message.getPayload()));
}
@Override
public void deliveryComplete(IMqttDeliveryToken token) {
log.info("SYS MQTT delivery complete: {}", token.getMessageId());
}
});
client.connect(options);
log.info("SYS MQTT connected successfully.....");
return client;
} catch (Exception e) {
log.error("Failed to initialize SYS MQTT client", e);
return null;
}
}
}

32
src/main/java/com/techsor/datacenter/sender/config/UidConfiguration.java

@ -0,0 +1,32 @@
package com.techsor.datacenter.sender.config;
import com.baidu.fsg.uid.UidGenerator;
import com.baidu.fsg.uid.impl.DefaultUidGenerator;
import com.baidu.fsg.uid.worker.DisposableWorkerIdAssigner;
import com.baidu.fsg.uid.worker.WorkerIdAssigner;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
@Configuration
@EnableConfigurationProperties(UidProperties.class)
@ConditionalOnProperty(prefix = "uid", value = "enable", matchIfMissing = true)
public class UidConfiguration {
@ConditionalOnProperty(prefix = "uid", name = "enableCache", havingValue = "true")
@Bean
public UidGenerator cacheUidGenerator() {
return new DefaultUidGenerator();
}
@ConditionalOnProperty(matchIfMissing = true, prefix = "uid", name = "enableCache", havingValue = "false")
@Bean
public UidGenerator uidGenerator() {
return new DefaultUidGenerator();
}
@Bean
public WorkerIdAssigner workerIdAssigner(){
return new DisposableWorkerIdAssigner();
}
}

52
src/main/java/com/techsor/datacenter/sender/config/UidProperties.java

@ -0,0 +1,52 @@
package com.techsor.datacenter.sender.config;
import org.springframework.boot.context.properties.ConfigurationProperties;
@ConfigurationProperties(prefix = "uid")
public class UidProperties {
private boolean enable;
private boolean enableCache;
private int timeBits = 31;
private int workerBits = 17;
private int seqBits = 15;
public int getTimeBits() {
return timeBits;
}
public void setTimeBits(int timeBits) {
this.timeBits = timeBits;
}
public int getWorkerBits() {
return workerBits;
}
public void setWorkerBits(int workerBits) {
this.workerBits = workerBits;
}
public int getSeqBits() {
return seqBits;
}
public void setSeqBits(int seqBits) {
this.seqBits = seqBits;
}
public boolean isEnable() {
return enable;
}
public void setEnable(boolean enable) {
this.enable = enable;
}
public boolean isEnableCache() {
return enableCache;
}
public void setEnableCache(boolean enableCache) {
this.enableCache = enableCache;
}
}

12
src/main/java/com/techsor/datacenter/sender/constants/CompanyConstants.java

@ -0,0 +1,12 @@
package com.techsor.datacenter.sender.constants;
public class CompanyConstants {
public final static String ZIFISENSE="zifisense";
public final static String NBI="nbi";
public final static String OVIPHONE="oviphone";
public final static String NITTAN="nittan";
public final static String OCR="ocr";
public final static String DELTA="delta";
public final static String METCOM="metcom";
}

52
src/main/java/com/techsor/datacenter/sender/constants/Constants.java

@ -0,0 +1,52 @@
package com.techsor.datacenter.sender.constants;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Configuration;
@Configuration
public class Constants {
public static final String REDIS_DEVICE_ALARM_KEY = "lambda_device_alarm";
public static final String REDIS_DEVICE_CANCEL_ALARM_KEY = "device_cancel_alarm";
public static final String STATUS_ALARM = "alert";
public static final String STATUS_ALERT_CANCEL = "alert_cancel";
public static final String ALERT_CANCEL_INFO = "【%s アラートメール】%s %s の%s解除を検知しました";
public static final String ALERT_INFO = "【%s アラートメール】%s %s で%sしました";
// public static Logger logger = LoggerFactory.getLogger(AlarmDataPush.class);
// //"http://tokyo-build-web-alb-481573367.ap-northeast-1.elb.amazonaws.com:20008/api/targetConfig/config/queryByDeviceId?deviceId=";
// public static final String QUERY_PUSH_INFO = "http://tokyo-build-prod-alb-2098411302.ap-northeast-1.elb.amazonaws.com:20008/targetConfig/config/v1/queryAlertForwardConfigByDeviceId?deviceId=";
// //"http://47.91.16.51:8080/rawJson/post/metcom"
//// public static final String PUSH_URL_METCOM = "http://43.163.239.12:8030/nesic/deviceId/metcom";
// //"http://47.91.16.51:8080/healthCheck"
//// public static final String HEALTHCHECK_URL = "http://47.91.16.51:8080/healthCheck";
@Value("${query.push.info:}")
public String QUERY_PUSH_INFO;
@Value("${roid.alarm.url:}")
public String ROID_ALARM_URL;
@Value("${roid.alarm.cancel.url:}")
public String ROID_ALARM_CANCEL_URL;
@Value("${roid.authorization:}")
public String ROID_AUTHORIZATION;
@Value("${alarm.receiver:}")
public String ALARM_RECEIVER ;
@Value("${email.restful.url:}")
public String EMAIL_RESULT_URL;
public static final String SWITCH_STATUS_PREFIX="switch:stats:status";
public static final String STATISTICS_ACCUMULATE_LATEST_PREFIX = "statistics:accumulate:latest_value:";
public static final String STATISTICS_MEASURE_LATEST_PREFIX = "statistics:measure:latest_value:";
}

6
src/main/java/com/techsor/datacenter/sender/constants/DeviceTypeConstants.java

@ -0,0 +1,6 @@
package com.techsor.datacenter.sender.constants;
public class DeviceTypeConstants {
public final static int normal=40; // 普通数据
public final static int difference=43; // 差值数据
}

19
src/main/java/com/techsor/datacenter/sender/constants/MsgConstants.java

@ -0,0 +1,19 @@
package com.techsor.datacenter.sender.constants;
public class MsgConstants {
public static String MSG_SERVER_ERROR="服务器问题,请联系管理员";
public static String MSG_WRONG_VERIFYCODE="验证码错误";
public static String MSG_USER_NOT_REGISTERED="用户未注册,请注册";
public static String REDIS_COMMAND_NOTIFICATION_TYPE="notification";
public static String REIDS_COMMAND_SWITCH_TYPE="switch";
public static final String SWITCH_STATUS_PREFIX="switch:stats:status";
public static final String REDIS_COMMAND_STAT_EVENT="startStat";
}

9
src/main/java/com/techsor/datacenter/sender/constants/TypeConstants.java

@ -0,0 +1,9 @@
package com.techsor.datacenter.sender.constants;
/**
* Store some special type's id.
* Notice: These types id should be fixed. Cannot be changed.
*/
public class TypeConstants {
public final static Integer KINGIOSERVER = 79;
}

42
src/main/java/com/techsor/datacenter/sender/controllers/HealthController.java

@ -0,0 +1,42 @@
package com.techsor.datacenter.sender.controllers;
import com.alibaba.fastjson2.JSON;
import org.springframework.core.io.ClassPathResource;
import org.springframework.core.io.Resource;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;
import java.io.IOException;
import java.lang.management.ManagementFactory;
import java.lang.management.RuntimeMXBean;
import java.util.HashMap;
import java.util.Map;
import java.util.Properties;
@RestController
public class HealthController {
@GetMapping("/healthcheck")
public String healhealthcheck(){
return "ok";
}
@GetMapping("/health")
public String health(){
RuntimeMXBean runtimeMXBean = ManagementFactory.getRuntimeMXBean();
long startTime = runtimeMXBean.getStartTime();
Map<String,String> resultMap=new HashMap<>();
resultMap.put("status","UP");
resultMap.put("startUpDate",String.valueOf(startTime));
return JSON.toJSONString(resultMap);
}
@GetMapping("/version")
public String getVersion() throws IOException {
Properties properties = new Properties();
Resource currentResource = new ClassPathResource("git.properties");
properties.load(currentResource.getInputStream());
String version=properties.getProperty("git.commit.id.abbrev");
return version;
}
}

308
src/main/java/com/techsor/datacenter/sender/controllers/MainReceiverController.java

@ -0,0 +1,308 @@
package com.techsor.datacenter.sender.controllers;
import com.google.gson.Gson;
import com.techsor.datacenter.sender.components.CommonOpt;
import com.techsor.datacenter.sender.config.DataSourceContextHolder;
import com.techsor.datacenter.sender.constants.CompanyConstants;
import com.techsor.datacenter.sender.entitiy.*;
import com.techsor.datacenter.sender.entitiy.zaiot.ProcessZAIoTRAWEntity;
import com.techsor.datacenter.sender.processers.*;
import com.techsor.datacenter.sender.service.IDataProcessService;
import com.techsor.datacenter.sender.service.KingIOServerService;
import com.techsor.datacenter.sender.service.St150Service;
import com.techsor.datacenter.sender.service.ZAIoTInnerService;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RestController;
import jakarta.annotation.Resource;
import java.text.ParseException;
/*
* 基础接收控制器从接收组件转发来的数据都先进入这里
* */
@RestController
@RequestMapping("v1/")
public class MainReceiverController {
private static final Logger logger = LoggerFactory.getLogger(MainReceiverController.class);
@Resource
DeltaProcessor deltaIProcessor;
@Resource
MetcomProcessor metcomProcessor;
@Resource
ZETAProcessor zetaProcessor;
@Resource
NBIProcessor nbiProcessor;
@Resource
OviphoneProcessor oviphoneProcessor;
@Resource
NittanProcessor nittanProcessor;
@Resource
OCRProcessor ocrProcessor;
@Resource
KingIOServerService kingIOServerService;
@Resource
St150Service st150Service;
@Resource
ZAIoTInnerService zaIoTInnerService;
@Autowired
private AsyncDataProcessor asyncDataProcessor;
@Resource
private DuplicateDataProcessor duplicateDataProcessor;
@Resource
private CommonOpt commonOpt;
@Resource
private IDataProcessService dataProcessService;
@RequestMapping(value = "generic/process", method = RequestMethod.POST)
public JsonResponse processReceiver(@RequestBody ProcessRAWEntity rawEntity){
logger.warn("DataSrcCode:{},Content:{}",new Object[]{rawEntity.getDataSrcCode(),rawEntity.getContent()});
boolean flag=this.duplicateDataProcessor.removeDuplicateData(rawEntity.getContent());
if (!flag){
return JsonResponse.buildSuccess("success");
}
logger.debug("After Duplicate =====>DataSrcCode:{},Content:{}",new Object[]{rawEntity.getDataSrcCode(),rawEntity.getContent()});
String deviceId=rawEntity.getDataSrcCode();
//处理数据,转发数据
String resultJson="";
try{
resultJson=this.dataProcessService.processData(rawEntity.getContent(),deviceId);
}catch (Exception e){
logger.error("Process data error:{}",e.getMessage());
}
return JsonResponse.buildSuccess(resultJson);
}
/**
* Special process for ioserver
* @param rawEntity
* @return
*/
@RequestMapping(value = "generic/ioserver_process", method = RequestMethod.POST)
public JsonResponse ioserverProcess(@RequestBody ProcessRAWEntity rawEntity){
logger.warn("DataSrcCode:{},Content:{}",new Object[]{rawEntity.getDataSrcCode(),rawEntity.getContent()});
boolean flag=this.duplicateDataProcessor.removeDuplicateData(rawEntity.getContent());
if (!flag){
return JsonResponse.buildSuccess("success");
}
logger.debug("After Duplicate =====>DataSrcCode:{},Content:{}",new Object[]{rawEntity.getDataSrcCode(),rawEntity.getContent()});
//处理数据,转发数据
// 异步执行耗时任务
asyncDataProcessor.processKingIOServerAsync(rawEntity.getContent(), kingIOServerService, dataProcessService);
// String resultJson="";
// try{
// //解析IOServer数据
// String processJson=this.kingIOServerService.start(rawEntity.getContent());
// dataProcessService.processKingIOServerData(processJson);
//
// }catch (Exception e){
// logger.error("Process data error:{}",e.getMessage());
// logger.error(e.getMessage(),e);
// }
return JsonResponse.buildSuccess("received");
}
/**
* Special process for ZT-150 Gateway
* @param rawEntity
* @return
*/
@RequestMapping(value = "generic/st150_process", method = RequestMethod.POST)
public JsonResponse st150Process(@RequestBody ProcessRAWEntity rawEntity){
logger.warn("DataSrcCode:{},Content:{}",new Object[]{rawEntity.getDataSrcCode(),rawEntity.getContent()});
boolean flag=this.duplicateDataProcessor.removeDuplicateData(rawEntity.getContent());
if (!flag){
return JsonResponse.buildSuccess("success");
}
logger.debug("After Duplicate =====>DataSrcCode:{},Content:{}",new Object[]{rawEntity.getDataSrcCode(),rawEntity.getContent()});
//处理数据,转发数据
// 异步执行耗时任务
asyncDataProcessor.processST150Async(rawEntity.getContent(), st150Service, dataProcessService);
// String resultJson="";
// try{
// //解析IOServer数据
// String processJson=this.kingIOServerService.start(rawEntity.getContent());
// dataProcessService.processKingIOServerData(processJson);
//
// }catch (Exception e){
// logger.error("Process data error:{}",e.getMessage());
// logger.error(e.getMessage(),e);
// }
return JsonResponse.buildSuccess("received");
}
/**
* Special process for ZETA zaiot sensor/振動センサー
* Since 振動センサー has two different device type to process.
* @param rawEntity
* @return
*/
@RequestMapping(value = "generic/zaiot_process", method = RequestMethod.POST)
public JsonResponse zaiotProcess(@RequestBody ProcessZAIoTRAWEntity rawEntity){
logger.warn("DataSrcCode:{},Content:{}",new Object[]{rawEntity.getDeviceId(),rawEntity.getContent()});
logger.debug("After Duplicate =====>DataSrcCode:{},Content:{}",new Object[]{rawEntity.getDeviceId(),rawEntity.getContent()});
//处理数据,转发数据
String resultJson="";
try{
//解析振動センサー数据
ResultDeviceIdEntity resultDeviceIdEntity=this.zaIoTInnerService.start(rawEntity.getContent(),rawEntity.getIdentify());
if (resultDeviceIdEntity!=null){
dataProcessService.processZAIoTData(resultDeviceIdEntity);
}
}catch (Exception e){
logger.error("Process data error:{}",e.getMessage());
logger.error(e.getMessage(),e);
}
return JsonResponse.buildSuccess(resultJson);
}
@RequestMapping(value = "generic/mockJsonData", method = RequestMethod.POST)
public JsonResponse mockJsonData(@RequestBody ProcessRAWEntity rawEntity){
logger.warn("Received: "+new Gson().toJson(rawEntity));
String deviceId=rawEntity.getDataSrcCode();
//处理数据,转发数据
String resultJson="";
try{
resultJson=this.dataProcessService.mockJsonData(rawEntity.getContent(),deviceId);
}catch (Exception e){
logger.error("Process data error:{}",e.getMessage());
}
return JsonResponse.buildSuccess(resultJson);
}
@RequestMapping(value = "generic/mockMinuteLevelStorage", method = RequestMethod.POST)
public JsonResponse mockMinuteLevelStorage(@RequestBody DynamodbEntity rawEntity){
logger.warn("mockMinuteLevelStorage Received: "+new Gson().toJson(rawEntity));
//处理数据
String resultJson="";
try{
String topCompanyId= commonOpt.getTopCompanyId(rawEntity.getDeviceId());
//Switch database
DataSourceContextHolder.setCurrentDataSourceKey("dataSourceForCompany_"+topCompanyId);
this.dataProcessService.minuteLevelStorage(rawEntity);
}catch (Exception e){
logger.error("Process data error:{}",e.getMessage());
}
return JsonResponse.buildSuccess(resultJson);
}
@RequestMapping(value = "main_receiver", method = RequestMethod.POST)
public JsonResponse mainReceiver(@RequestBody RAWEntity rawEntity) throws ParseException, InterruptedException {
logger.warn("Company:{} ,Content:{}",new Object[]{rawEntity.getCompany(),rawEntity.getContent()});
boolean flag=this.duplicateDataProcessor.removeDuplicateData(rawEntity.getContent());
if (!flag){
return JsonResponse.buildSuccess("success");
}
//数据类型筛选
switch (rawEntity.getCompany()){
case CompanyConstants.ZIFISENSE:
return zifiReceiver(rawEntity.getContent());
case CompanyConstants.NBI:
return nbiReceiver(rawEntity.getContent());
case CompanyConstants.OVIPHONE:
return oviphoneReceiver(rawEntity.getContent());
case CompanyConstants.NITTAN:
return nittanReceiver(rawEntity.getContent());
case CompanyConstants.OCR:
return ocrReceiver(rawEntity.getContent());
case CompanyConstants.DELTA:
return deltaReceiver(rawEntity.getContent());
case CompanyConstants.METCOM:
return metcomReceiver(rawEntity.getContent());
}
return JsonResponse.buildError(-1,"Invalid data, not from zifisense , NBI , oviphone , ocr , delta");
}
//Zifisense设备数据处理入口
private JsonResponse zifiReceiver(String content){
if (content.contains("msUid")){
zetaProcessor.start(content);
return JsonResponse.buildSuccess("Received ZETA Data");
}else{
return JsonResponse.buildError(-1,"Received ZETA Data, but not MS upload data");
}
}
//nbi设备数据处理接口
private JsonResponse nbiReceiver(String content){
JsonResponse jsonResponse = nbiProcessor.start(content);
return jsonResponse;
}
//oviphone设备数据处理接口
private JsonResponse oviphoneReceiver(String content) throws ParseException, InterruptedException {
JsonResponse jsonResponse = oviphoneProcessor.start(content);
return jsonResponse;
}
//nittan设备数据处理接口
private JsonResponse nittanReceiver(String content){
JsonResponse jsonResponse = null;
try {
jsonResponse = nittanProcessor.start(content);
} catch (Exception e) {
logger.error("nittan error occurs!! {}",e.getMessage(),e);
jsonResponse = JsonResponse.buildError("Error parsing data.");
}
return jsonResponse;
}
//ocr设备数据处理接口
private JsonResponse ocrReceiver(String content){
JsonResponse jsonResponse = ocrProcessor.start(content);
return jsonResponse;
}
//delta设备数据处理接口
private JsonResponse deltaReceiver(String content){
JsonResponse jsonResponse = JsonResponse.buildError("deltaReceiver process Error");
try{
jsonResponse = deltaIProcessor.start(content);
}catch (Exception e){
logger.error(e.getMessage());
}
return jsonResponse;
}
private JsonResponse metcomReceiver(String content){
JsonResponse jsonResponse = JsonResponse.buildError("metcomProcessor process Error");
try{
jsonResponse = metcomProcessor.start(content);
}catch (Exception e){
logger.error("metcomReceiver {}",e);
}
return jsonResponse;
}
}

72
src/main/java/com/techsor/datacenter/sender/dao/BaStatusDao.java

@ -0,0 +1,72 @@
package com.techsor.datacenter.sender.dao;
import com.techsor.datacenter.sender.entitiy.bastatus.BaStatusEntity;
import lombok.extern.slf4j.Slf4j;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.stereotype.Component;
import jakarta.annotation.Resource;
import java.util.List;
@Slf4j
@Component
public class BaStatusDao {
@Resource
private JdbcTemplate jdbcTemplate;
/**
* Get all dataList by DeviceId
* @param deviceId
* @return
*/
public BaStatusEntity getByDeviceId(String deviceId) {
String sql="SELECT " +
"ba_status_statistics.id as id,ba_status_statistics.device_info_id,ba_status_statistics.is_running,ba_status_statistics.latest_ts," +
"ba_status_statistics.continuous_running_time,ba_status_statistics.aggregated_running_time,ba_status_statistics.running_count,ba_status_statistics.last_start_time,ba_status_statistics.last_stop_time " +
" FROM ba_status_statistics,device_info " +
"where ba_status_statistics.device_info_id=device_info.id " +
"and device_info.device_id='#deviceId';";
sql = sql.replaceAll("#deviceId",deviceId);
List<BaStatusEntity> dataList = jdbcTemplate.query(sql,
(rs, rowNum) -> {
BaStatusEntity item = new BaStatusEntity();
item.setId(rs.getInt("id"));
item.setDeviceInfoId(rs.getInt("device_info_id"));
item.setIsRunning(rs.getInt("is_running"));
item.setLatest_ts(rs.getString("latest_ts"));
item.setContinuousRunningTime(rs.getLong("continuous_running_time"));
item.setAggregatedRunningTime(rs.getLong("aggregated_running_time"));
item.setRunningCount(rs.getInt("running_count"));
item.setLastStopTime(rs.getLong("last_stop_time"));
item.setLastStartTime(rs.getLong("last_start_time"));
return item;
});
if (dataList.size()==0){
return null;
}else{
return dataList.get(dataList.size()-1);
}
}
public Boolean insert(BaStatusEntity entity) {
String sql= "INSERT INTO `ba_status_statistics` (" +
"`device_info_id`, `is_running`, `latest_ts`, `continuous_running_time`, `aggregated_running_time`, `running_count`, `last_start_time`, `last_stop_time`" +
") VALUES (?, ?, ?, ?, ?, ?, ?, ?)";
int rows = jdbcTemplate.update(sql,entity.getDeviceInfoId(),entity.getIsRunning(),entity.getLatest_ts(),entity.getContinuousRunningTime(),entity.getAggregatedRunningTime(),entity.getRunningCount(),entity.getLastStartTime(),entity.getLastStopTime());
return (rows>0);
}
public Boolean update(BaStatusEntity entity) {
String sql= "UPDATE ba_status_statistics SET " +
"device_info_id = ?, is_running = ?, latest_ts = ?, continuous_running_time = ?, aggregated_running_time = ?, running_count = ? , last_start_time = ? , last_stop_time = ? " +
"WHERE id = ?";
int rows = jdbcTemplate.update(sql,entity.getDeviceInfoId(),entity.getIsRunning(),entity.getLatest_ts(),entity.getContinuousRunningTime(),entity.getAggregatedRunningTime(),entity.getRunningCount(),entity.getLastStartTime(),entity.getLastStopTime(),entity.getId());
return (rows>0);
}
}

124
src/main/java/com/techsor/datacenter/sender/dao/CommonDAO.java

@ -0,0 +1,124 @@
package com.techsor.datacenter.sender.dao;
import com.techsor.datacenter.sender.entitiy.DeviceEntity;
import cn.hutool.core.collection.CollectionUtil;
import org.apache.commons.lang3.StringUtils;
import org.jetbrains.annotations.NotNull;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.cache.annotation.Cacheable;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.stereotype.Component;
import jakarta.annotation.Resource;
import java.util.ArrayList;
import java.util.List;
@Component
public class CommonDAO {
@Resource
private JdbcTemplate jdbcTemplate ;
private static final Logger logger = LoggerFactory.getLogger(CommonDAO.class);
//根据设备id获取对应的WS客户端ID
@Cacheable(value = "CommonDAO::getWSClientByDeviceId", key = "#deviceId")
public List<DeviceEntity> getWSClientByDeviceId(String deviceId) {
String sql = "";
if (StringUtils.isEmpty(deviceId)){
return new ArrayList<>();
}
sql = "SELECT * FROM device_info,jg_ws_clients WHERE device_id='"+deviceId+"' and device_info.wsclient_id = jg_ws_clients.id";
logger.debug("Execute SQL: {}",sql);
List<DeviceEntity> dataList = jdbcTemplate.query(sql,
(rs, rowNum) -> {
DeviceEntity item = new DeviceEntity();
item.setId(rs.getInt("id"));
item.setDeviceId(rs.getString("device_id"));
item.setTypeId(rs.getInt("type_id"));
item.setWsClientId(rs.getString("client_id"));
return item;
});
return dataList;
}
//根据设备SN获取对应信息
@Cacheable(value = "getDeviceInfoBySN", key = "#sn")
public List<DeviceEntity> getDeviceInfoBySN(String sn) {
String sql = "";
sql = "SELECT * FROM device_info,jg_ws_clients WHERE device_sn='"+sn+"' and device_info.wsclient_id = jg_ws_clients.id";
logger.debug("Execute SQL: {}",sql);
return getDeviceEntities(sql);
}
//根据设备DeviceId获取对应信息
@Cacheable(value = "CommonDAO::getDeviceInfoByDeviceId", key = "#deviceId")
public List<DeviceEntity> getDeviceInfoByDeviceId(String deviceId) {
String sql = "";
sql = "SELECT * FROM device_info,jg_ws_clients WHERE device_id='"+deviceId+"' and device_info.wsclient_id = jg_ws_clients.id";
logger.debug("Execute SQL: {}",sql);
return getDeviceEntities(sql);
}
public List<DeviceEntity> getDeviceEntities(String sql) {
List<DeviceEntity> dataList = jdbcTemplate.query(sql,
(rs, rowNum) -> {
DeviceEntity item = new DeviceEntity();
item.setId(rs.getInt("id"));
item.setDeviceId(rs.getString("device_id"));
item.setDeviceSN(rs.getString("device_sn"));
item.setTypeId(rs.getInt("type_id"));
item.setWsClientId(rs.getString("client_id"));
return item;
});
return dataList;
}
//根据typeId获取设备信息列表
public List<DeviceEntity> getDeviceInfoByTypeIds(List<Integer> typeIdList) {
if (CollectionUtil.isEmpty(typeIdList)){
return new ArrayList<>();
}
String sql = "";
String factorSql = "";
for (int i=0;i<typeIdList.size();i++) {
factorSql = factorSql+" device_info.type_id="+typeIdList.get(i).toString()+" ";
if (i+1< typeIdList.size()){
factorSql = factorSql+" or";
}
}
sql = "SELECT * FROM device_info,jg_ws_clients WHERE ("+factorSql+") and device_info.wsclient_id = jg_ws_clients.id";
logger.debug("Execute SQL: {}",sql);
return getDeviceEntities(sql);
}
//获取所有属于该typeId的wsclient
@Cacheable(value = "getWsClientIdListByTypeId", key = "#typeIdList")
public List<String> getWsClientIdListByTypeIds(List<Integer> typeIdList) {
if (CollectionUtil.isEmpty(typeIdList)){
return new ArrayList<>();
}
String sql = "";
String factorSql = "";
for (int i=0;i<typeIdList.size();i++) {
factorSql = factorSql+" device_info.type_id="+typeIdList.get(i).toString()+" ";
if (i+1< typeIdList.size()){
factorSql = factorSql+" or";
}
}
sql = "SELECT client_id FROM device_info,jg_ws_clients WHERE ("+factorSql+") and device_info.wsclient_id = jg_ws_clients.id group by device_info.wsclient_id";
logger.debug("Execute SQL: {}",sql);
List<String> dataList = jdbcTemplate.query(sql,
(rs, rowNum) -> rs.getString("client_id"));
return dataList;
}
}

83
src/main/java/com/techsor/datacenter/sender/dao/CompanyInfoDao.java

@ -0,0 +1,83 @@
package com.techsor.datacenter.sender.dao;
import com.techsor.datacenter.sender.entitiy.company.CompanyEntity;
import lombok.extern.slf4j.Slf4j;
import org.springframework.cache.annotation.Cacheable;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.stereotype.Component;
import jakarta.annotation.Resource;
import java.util.List;
import java.util.concurrent.atomic.AtomicLong;
@Slf4j
@Component
public class CompanyInfoDao {
@Resource
private JdbcTemplate jdbcTemplate;
@Cacheable(value = "CompanyInfoDao::getCompanyList",key = "'CompanyList'")
public List<CompanyEntity> getCompanyList() {
// String sql="SELECT id,parent_id,company_name,bearer_token,third_api_host FROM data_center_admin.basic_company;";
String sql="SELECT id,parent_id,company_name,bearer_token,third_api_host FROM data_center_aeon_admin.basic_company;";
List<CompanyEntity> dataList = jdbcTemplate.query(sql,
(rs, rowNum) -> {
CompanyEntity item = new CompanyEntity();
item.setId(rs.getLong("id"));
item.setParentId(rs.getLong("parent_id"));
item.setCompanyName(rs.getString("company_name"));
item.setBearerToken(rs.getString("bearer_token"));
item.setThirdApiHost(rs.getString("third_api_host"));
return item;
});
return dataList;
}
@Cacheable(value = "CompanyInfoDao::getCompanyById",key = "#companyId")
public CompanyEntity getCompanyById(String companyId) {
// String sql="SELECT id,parent_id,company_name,bearer_token,third_api_host FROM data_center_admin.basic_company where id="+companyId;
String sql="SELECT id,parent_id,company_name,bearer_token,third_api_host FROM data_center_aeon_admin.basic_company where id="+companyId;
List<CompanyEntity> dataList = jdbcTemplate.query(sql,
(rs, rowNum) -> {
CompanyEntity item = new CompanyEntity();
item.setId(rs.getLong("id"));
item.setParentId(rs.getLong("parent_id"));
item.setCompanyName(rs.getString("company_name"));
item.setBearerToken(rs.getString("bearer_token"));
item.setThirdApiHost(rs.getString("third_api_host"));
return item;
});
if (dataList.size()==0){
return null;
}else{
return dataList.get(0);
}
}
@Cacheable(value = "CompanyInfoDao::getCompanyList",key = "#companyId")
public long getTopCompanyId(String companyId) {
String sql="SELECT "
+ " bcom.id, bcom.parent_id parentId"
+ " FROM data_center_aeon_admin.basic_company bcom "
+ " WHERE bcom.flag != 1 and bcom.id = " + companyId;
AtomicLong parentId = new AtomicLong(0);
AtomicLong id = new AtomicLong(0);
jdbcTemplate.query(sql,rs -> {
parentId.set(rs.getLong("parentId"));
id.set(rs.getLong("id"));
});
//Recursive logiczA
if (1 == parentId.get() || -1 == parentId.get() || parentId.get() == 0 || parentId.get() == id.get()) {
return id.get();
} else {
log.error("Notice query,parentId:"+parentId.get());
return getTopCompanyId(parentId.get()+"");
}
}
}

116
src/main/java/com/techsor/datacenter/sender/dao/DashboardAlertDao.java

@ -0,0 +1,116 @@
package com.techsor.datacenter.sender.dao;
import com.techsor.datacenter.sender.entitiy.AlertHistoryDTO;
import com.techsor.datacenter.sender.entitiy.DynamodbEntity;
import lombok.extern.slf4j.Slf4j;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.List;
import org.apache.commons.collections.CollectionUtils;
import org.apache.commons.lang.StringUtils;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.jdbc.core.RowMapper;
import org.springframework.stereotype.Component;
import jakarta.annotation.Resource;
@Slf4j
@Component
public class DashboardAlertDao {
@Resource
private JdbcTemplate jdbcTemplate;
public void upsertDeviceRawData(DynamodbEntity entity) {
if (StringUtils.isEmpty(entity.getDeviceId())) {
return;
}
Integer year = Integer.valueOf(entity.getYearKey());
Integer month = Integer.valueOf(entity.getMonthKey());
Integer day = Integer.valueOf(entity.getDayKey());
int updateCount = jdbcTemplate.update(
"UPDATE device_rawdata_realtime SET " +
"building_id = ?, status = ?, receive_ts = ?, alert_title = ?, " +
"alert_content = ?, alert_cancel_title = ?, alert_cancel_content = ?, " +
"raw_data = ?, upload_year = ?, upload_month = ?, upload_day = ? " +
"WHERE device_id = ?",
entity.getDbBuildingId(), entity.getStatus(), entity.getReceive_ts(), entity.getAlertTitle(),
entity.getAlertContent(), entity.getAlertCancelTitle(), entity.getAlertCancelContent(),
entity.getRawData(), year, month, day,
entity.getDeviceId()
);
if (updateCount == 0) {
jdbcTemplate.update(
"INSERT INTO device_rawdata_realtime (" +
"device_id, building_id, status, receive_ts, alert_title, alert_content, " +
"alert_cancel_title, alert_cancel_content, raw_data, upload_year, upload_month, upload_day) " +
"VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)",
entity.getDeviceId(), entity.getDbBuildingId(), entity.getStatus(), entity.getReceive_ts(),
entity.getAlertTitle(), entity.getAlertContent(), entity.getAlertCancelTitle(), entity.getAlertCancelContent(),
entity.getRawData(), year, month, day
);
}
}
public void insertAlertHistory(DynamodbEntity entity) {
String sql = "INSERT INTO alert_history (" +
"device_id, receive_ts, retain_alert" +
") VALUES (?, ?, ?)";
jdbcTemplate.update(sql,
entity.getDeviceId(),
entity.getReceive_ts(),
entity.getRetainAlert()
);
}
public void updateLatestAlertToAutoRecovered(DynamodbEntity entity) {
String sql = "SELECT * FROM alert_history WHERE device_id = ? ORDER BY id DESC LIMIT 1";
List<AlertHistoryDTO> result = jdbcTemplate.query(sql, new RowMapper<AlertHistoryDTO>() {
@Override
public AlertHistoryDTO mapRow(ResultSet rs, int rowNum) throws SQLException {
AlertHistoryDTO dto = new AlertHistoryDTO();
dto.setId(rs.getLong("id"));
dto.setDeviceId(rs.getString("device_id"));
dto.setReceiveTs(rs.getLong("receive_ts"));
dto.setConfirmStatus(rs.getInt("confirm_status"));
dto.setHandleStatus(rs.getInt("handle_status"));
dto.setAlertStatus(rs.getInt("alert_status"));
dto.setRetainAlert(rs.getInt("retain_alert"));
return dto;
}
}, entity.getDeviceId());
if (CollectionUtils.isEmpty(result)) {
log.debug("Alert history not found");
return;
}
AlertHistoryDTO alertHistoryDTO = result.get(0);
if (1 == alertHistoryDTO.getAlertStatus()) {
log.debug("The alert has been processed");
return;
}
Long alertHistoryId = alertHistoryDTO.getId();
// 更新 alert_history
String updateAlertHistorySql = "UPDATE alert_history SET handle_status = 4, alert_status = 1 WHERE id = ?";
jdbcTemplate.update(updateAlertHistorySql, alertHistoryId);
// 更新 alert_handle_history
// status值不能是完成status != 3
String updateHandleHistorySql = "UPDATE alert_handle_history SET status = 4, alert_status = 1 WHERE alert_history_id = ? and status != 3";
jdbcTemplate.update(updateHandleHistorySql, alertHistoryId);
}
}

118
src/main/java/com/techsor/datacenter/sender/dao/DashboardStatisticsDao.java

@ -0,0 +1,118 @@
package com.techsor.datacenter.sender.dao;
import com.techsor.datacenter.sender.entitiy.StatisticsAccumulateInfo;
import com.techsor.datacenter.sender.entitiy.StatisticsMeasureInfo;
import lombok.extern.slf4j.Slf4j;
import java.math.BigDecimal;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.stereotype.Component;
import jakarta.annotation.Resource;
@Slf4j
@Component
public class DashboardStatisticsDao {
@Resource
private JdbcTemplate jdbcTemplate;
public void insertDeviceMeasureInfo(String uploadValue, String deviceId, StatisticsMeasureInfo info) {
String sql = "INSERT INTO dashboard_record_measure " +
"(device_id, date_year, date_month, date_day, date_hour, date_minute, date_second, " +
"upload_value, upload_at) " +
"VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?)";
jdbcTemplate.update(sql,
deviceId,
info.getYearKey(),
info.getMonthKey(),
info.getDayKey(),
info.getHourKey(),
info.getMinuteKey(),
info.getSecondKey(),
uploadValue,
info.getUploadAt()
);
}
public void upsertDeviceRealtimeMeasure(String uploadValue, String deviceId, BigDecimal minValue,
BigDecimal maxValue, StatisticsMeasureInfo info) {
String sql = "INSERT INTO dashboard_realtime_measure (" +
"device_id, date_year, date_month, date_day, date_hour, date_minute, date_second, " +
"upload_value, min_value, max_value, upload_at) " +
"VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?) " +
"ON DUPLICATE KEY UPDATE " +
"date_year = VALUES(date_year), " +
"date_month = VALUES(date_month), " +
"date_day = VALUES(date_day), " +
"date_hour = VALUES(date_hour), " +
"date_minute = VALUES(date_minute), " +
"date_second = VALUES(date_second), " +
"upload_value = VALUES(upload_value), " +
"min_value = VALUES(min_value), " +
"max_value = VALUES(max_value), " +
"upload_at = VALUES(upload_at)";
jdbcTemplate.update(sql,
deviceId,
info.getYearKey(),
info.getMonthKey(),
info.getDayKey(),
info.getHourKey(),
info.getMinuteKey(),
info.getSecondKey(),
uploadValue,
minValue != null ? minValue.toString() : null,
maxValue != null ? maxValue.toString() : null,
info.getUploadAt()
);
}
public void insertDeviceAccumulateInfo(String uploadValue, String deviceId, Double incrementToday,
Double incrementMinute, StatisticsAccumulateInfo info) {
String sql = "INSERT INTO dashboard_record_accumulate " +
"(device_id, date_year, date_month, date_day, date_hour, date_minute, date_second, " +
"upload_value, increment_today, increment_minute, upload_at) " +
"VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)";
jdbcTemplate.update(sql,
deviceId,
info.getYearKey(),
info.getMonthKey(),
info.getDayKey(),
info.getHourKey(),
info.getMinuteKey(),
info.getSecondKey(),
uploadValue,
incrementToday,
incrementMinute,
info.getUploadAt()
);
}
public void insertOrUpdateRealtimeAccumulateDay(String uploadValue, String deviceId,
Double incrementToday, StatisticsAccumulateInfo info) {
String sql = "INSERT INTO dashboard_realtime_accumulate_day " +
"(device_id, date_year, date_month, date_day, upload_value, increment_today, upload_at) " +
"VALUES (?, ?, ?, ?, ?, ?, ?) " +
"ON DUPLICATE KEY UPDATE " +
"upload_value = VALUES(upload_value), " +
"increment_today = VALUES(increment_today), " +
"upload_at = VALUES(upload_at)";
jdbcTemplate.update(sql,
deviceId,
info.getYearKey(),
info.getMonthKey(),
info.getDayKey(),
uploadValue,
incrementToday,
info.getUploadAt()
);
}
}

40
src/main/java/com/techsor/datacenter/sender/dao/DataSrcConfigDao.java

@ -0,0 +1,40 @@
package com.techsor.datacenter.sender.dao;
import com.techsor.datacenter.sender.entitiy.DataSrcConfigInfoEntity;
import org.apache.commons.lang3.StringUtils;
import org.springframework.cache.annotation.Cacheable;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.stereotype.Component;
import jakarta.annotation.Resource;
import java.util.ArrayList;
import java.util.List;
@Component
public class DataSrcConfigDao {
@Resource
private JdbcTemplate jdbcTemplate ;
@Cacheable(value = "DataSrcConfigDao::getDataSrcConfigByCode", key = "#code")
public List<DataSrcConfigInfoEntity> getDataSrcConfigByCode(String code){
List<DataSrcConfigInfoEntity> resultList=new ArrayList<>();
if (StringUtils.isEmpty(code)){
return resultList;
}
String sql="select * from data_src_config where code='"+code+"' ";
resultList=this.jdbcTemplate.query(sql,(rs,rowNum)->{
DataSrcConfigInfoEntity dataSrcConfigInfoEntity=new DataSrcConfigInfoEntity();
dataSrcConfigInfoEntity.setCode(rs.getString("code"));
dataSrcConfigInfoEntity.setName(rs.getString("name"));
dataSrcConfigInfoEntity.setMethodType(rs.getString("method_type"));
return dataSrcConfigInfoEntity;
});
return resultList;
}
}

63
src/main/java/com/techsor/datacenter/sender/dao/DeviceAlertConfigDao.java

@ -0,0 +1,63 @@
package com.techsor.datacenter.sender.dao;
import com.techsor.datacenter.sender.dto.DeviceAlertInfo;
import com.techsor.datacenter.sender.entitiy.DeviceAlertConfigEntity;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.stereotype.Component;
import jakarta.annotation.Resource;
import java.util.List;
@Component
public class DeviceAlertConfigDao {
@Resource
private JdbcTemplate jdbcTemplate ;
/*
* id int auto_increment
primary key,
device_config_id bigint not null comment '设备类别配置ID',
alert_name varchar(50) null comment '设备告警名称',
level varchar(20) null comment '告警级别',
contents varchar(200) null comment '告警内容',
type varchar(100) null comment '告警类型',
message varchar(200) null comment '告警信息',
flag int default 0 null comment '0 开启1关闭'
**/
public List<DeviceAlertConfigEntity> selectCurrentDeviceAlertConfigByDeviceId(Long deviceId){
String sql="select * from device_alert_config where device_config_id="+deviceId+" and flag!=1";
List<DeviceAlertConfigEntity> dataList=this.jdbcTemplate.query(sql,(rs, rowNum)->{
DeviceAlertConfigEntity deviceAlertConfigEntity=new DeviceAlertConfigEntity();
deviceAlertConfigEntity.setId(rs.getInt("id"));
deviceAlertConfigEntity.setDeviceConfigId(rs.getLong("device_config_id"));
deviceAlertConfigEntity.setAlertName(rs.getString("alert_name"));
deviceAlertConfigEntity.setLevel(rs.getString("level"));
deviceAlertConfigEntity.setContents(rs.getString("contents"));
deviceAlertConfigEntity.setType(rs.getString("type"));
deviceAlertConfigEntity.setMessage(rs.getString("message"));
deviceAlertConfigEntity.setAlertCancelMessage(rs.getString("alert_cancel_message"));
deviceAlertConfigEntity.setAlertTitle(rs.getString("alert_title"));
deviceAlertConfigEntity.setAlertCancelTitle(rs.getString("alert_cancel_title"));
deviceAlertConfigEntity.setFlag(rs.getInt("flag"));
deviceAlertConfigEntity.setTargetId(rs.getString("target_id"));
deviceAlertConfigEntity.setProblemReportCategoryId(rs.getString("problem_report_category_id"));
deviceAlertConfigEntity.setForwardType(rs.getString("forward_type"));
deviceAlertConfigEntity.setBuildingId(rs.getString("building_id"));
deviceAlertConfigEntity.setBuildingCode(rs.getString("building_code"));
return deviceAlertConfigEntity;
});
return dataList;
}
}

20
src/main/java/com/techsor/datacenter/sender/dao/DeviceAlertTemplateBindDao.java

@ -0,0 +1,20 @@
package com.techsor.datacenter.sender.dao;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.stereotype.Component;
import jakarta.annotation.Resource;
import java.util.List;
@Component
public class DeviceAlertTemplateBindDao {
@Resource
private JdbcTemplate jdbcTemplate;
public List<Long> selectDeviceAlertTemplateBindByDeviceId(Long deviceId){
String sql="select device_alert_template_id from device_alert_template_bind where device_info_id="+deviceId;
return this.jdbcTemplate.query(sql,(rs, rowNum)-> rs.getLong("device_alert_template_id"));
}
}

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

Loading…
Cancel
Save