commit
28d4d40b0c
280 changed files with 23234 additions and 0 deletions
@ -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 |
|||
@ -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(); |
|||
} |
|||
|
|||
} |
|||
Binary file not shown.
@ -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 |
|||
@ -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 |
|||
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
@ -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----- |
|||
@ -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 |
|||
@ -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 |
|||
@ -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 "$@" |
|||
@ -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% |
|||
@ -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> |
|||
|
|||
|
|||
<!-- <!– https://mvnrepository.com/artifact/software.amazon.awssdk/dynamodb –>--> |
|||
<!-- <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> |
|||
|
|||
<!--<!– 正式环境 –>--> |
|||
<!-- <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> |
|||
@ -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} |
|||
``` |
|||
|
|||
@ -0,0 +1,3 @@ |
|||
git pull |
|||
mvn clean |
|||
mvn package -DskipTests=true docker:build |
|||
Binary file not shown.
@ -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 |
|||
@ -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); |
|||
} |
|||
|
|||
} |
|||
@ -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); |
|||
|
|||
} |
|||
@ -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; |
|||
} |
|||
|
|||
} |
|||
@ -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); |
|||
} |
|||
@ -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); |
|||
} |
|||
@ -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); |
|||
} |
|||
@ -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(); |
|||
} |
|||
|
|||
} |
|||
@ -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); |
|||
} |
|||
|
|||
} |
|||
@ -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) << |
|||
* {@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; |
|||
} |
|||
|
|||
} |
|||
@ -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()); |
|||
} |
|||
} |
|||
} |
|||
@ -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()); |
|||
} |
|||
|
|||
} |
|||
@ -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); |
|||
} |
|||
} |
|||
|
|||
} |
|||
@ -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); |
|||
} |
|||
|
|||
} |
|||
@ -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; |
|||
} |
|||
|
|||
} |
|||
@ -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(); |
|||
} |
|||
|
|||
} |
|||
@ -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; |
|||
} |
|||
|
|||
} |
|||
@ -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(); |
|||
} |
|||
@ -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; |
|||
} |
|||
|
|||
} |
|||
@ -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(); |
|||
|
|||
} |
|||
@ -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; |
|||
} |
|||
|
|||
} |
|||
@ -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; |
|||
} |
|||
} |
|||
@ -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); |
|||
} |
|||
@ -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!"); |
|||
} |
|||
|
|||
} |
|||
@ -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; |
|||
} |
|||
} |
|||
} |
|||
|
|||
|
|||
|
|||
@ -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; |
|||
} |
|||
} |
|||
@ -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); |
|||
} |
|||
} |
|||
@ -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; |
|||
} |
|||
|
|||
} |
|||
@ -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); |
|||
} |
|||
} |
|||
} |
|||
} |
|||
@ -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; |
|||
} |
|||
|
|||
} |
|||
@ -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); |
|||
} |
|||
} |
|||
} |
|||
@ -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(); |
|||
} |
|||
} |
|||
@ -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(); |
|||
} |
|||
} |
|||
@ -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(); |
|||
} |
|||
} |
|||
} |
|||
@ -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(); |
|||
} |
|||
} |
|||
|
|||
} |
|||
@ -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 { |
|||
} |
|||
@ -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; |
|||
|
|||
|
|||
} |
|||
@ -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); |
|||
} |
|||
|
|||
|
|||
} |
|||
@ -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(); |
|||
} |
|||
} |
|||
@ -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(); |
|||
} |
|||
} |
|||
@ -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); |
|||
} |
|||
|
|||
|
|||
} |
|||
@ -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); |
|||
} |
|||
} |
|||
|
|||
@ -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);
|
|||
// }
|
|||
//}
|
|||
@ -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(); |
|||
} |
|||
|
|||
|
|||
} |
|||
@ -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); |
|||
} |
|||
|
|||
} |
|||
@ -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); |
|||
} |
|||
|
|||
} |
|||
@ -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; |
|||
} |
|||
} |
|||
} |
|||
@ -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(); |
|||
} |
|||
} |
|||
@ -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; |
|||
} |
|||
} |
|||
@ -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"; |
|||
|
|||
} |
|||
@ -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:"; |
|||
|
|||
|
|||
} |
|||
@ -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; // 差值数据
|
|||
} |
|||
@ -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"; |
|||
} |
|||
@ -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; |
|||
} |
|||
@ -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; |
|||
} |
|||
} |
|||
@ -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; |
|||
} |
|||
} |
|||
@ -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); |
|||
} |
|||
|
|||
|
|||
} |
|||
@ -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; |
|||
} |
|||
|
|||
} |
|||
@ -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()+""); |
|||
} |
|||
} |
|||
|
|||
} |
|||
@ -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); |
|||
} |
|||
|
|||
} |
|||
@ -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() |
|||
); |
|||
} |
|||
|
|||
|
|||
} |
|||
@ -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; |
|||
|
|||
} |
|||
} |
|||
@ -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; |
|||
} |
|||
|
|||
|
|||
|
|||
|
|||
} |
|||
@ -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…
Reference in new issue