From 1ec59d51fce38c33f10676e380cd099d3e87221c Mon Sep 17 00:00:00 2001 From: zhongjie Date: Tue, 15 Jun 2021 11:26:48 +0800 Subject: [PATCH 01/28] add Win boot script --- .github/workflows/maven.yml | 2 + README.en-us.md | 3 +- README.md | 3 +- fizz-bootstrap/pom.xml | 2 + fizz-bootstrap/sh/boot.cmd | 69 +++++++++++++++++++ .../src/main/resources/application.yml | 2 +- 6 files changed, 78 insertions(+), 3 deletions(-) create mode 100644 fizz-bootstrap/sh/boot.cmd diff --git a/.github/workflows/maven.yml b/.github/workflows/maven.yml index a505dfe..1862d18 100644 --- a/.github/workflows/maven.yml +++ b/.github/workflows/maven.yml @@ -51,8 +51,10 @@ jobs: mkdir fizz-gateway-community cp ./fizz-bootstrap/target/fizz-bootstrap-*.jar ./fizz-gateway-community/fizz-gateway-community.jar cp ./fizz-bootstrap/target/classes/application.yml ./fizz-gateway-community/application.yml + cp ./fizz-bootstrap/target/classes/bootstrap.yml ./fizz-gateway-community/bootstrap.yml cp ./fizz-bootstrap/target/classes/log4j2-spring.xml ./fizz-gateway-community/log4j2-spring.xml cp ./fizz-bootstrap/sh/boot.sh ./fizz-gateway-community/boot.sh + cp ./fizz-bootstrap/sh/boot.cmd ./fizz-gateway-community/boot.cmd zip -r ./fizz-gateway-community-${{ steps.releaseVersion.outputs.substring }}.zip ./fizz-gateway-community/* - name: Release uses: softprops/action-gh-release@v1 diff --git a/README.en-us.md b/README.en-us.md index c38ef3e..970854b 100644 --- a/README.en-us.md +++ b/README.en-us.md @@ -176,7 +176,8 @@ Installation method 1: binary package: 1. Download the latest binary package of fizz-gateway-community and upzip to a directory, modify the configuration of the configuration center, registry, and redis in the application.yml configuration file (redis configuration needs to be consistent with the management backend). 2. Modify the apollo connection and JVM memory configuration of the boot.sh script -3. Execute `./boot.sh start` command to start the service, support start/stop/restart/status command +3. Linux startup Execute `./boot.sh start` command to start the service, support start/stop/restart/status command +4. Windows startup Execute `.\boot.cmd start` command to start the service, support start/stop/restart/status command Installation method 2: source code: diff --git a/README.md b/README.md index cd03dad..42b1ef4 100644 --- a/README.md +++ b/README.md @@ -174,7 +174,8 @@ docker run --rm -d -p 8000:8000 \ 1. 下载fizz-gateway-community的二进制安装包,解压修改application.yml配置文件里配置中心、注册中心、redis(redis配置需与管理后台一致)的配置 2. 根据需要修改boot.sh脚本的apollo连接,不使用apollo配置中心可跳过 -3. 执行 `./boot.sh start` 命令启动服务,支持 start/stop/restart/status命令 +3. Linux启动 执行 `./boot.sh start` 命令启动服务,支持 start/stop/restart/status命令 +4. Windows启动 执行`.\boot.cmd start` 命令启动服务,支持 start/stop/restart/status命令 安装方式二:源码安装: diff --git a/fizz-bootstrap/pom.xml b/fizz-bootstrap/pom.xml index 11a701c..e4b72ea 100644 --- a/fizz-bootstrap/pom.xml +++ b/fizz-bootstrap/pom.xml @@ -87,11 +87,13 @@ sh boot.sh + boot.cmd true src/main/resources application.yml + bootstrap.yml log4j2-spring.xml true diff --git a/fizz-bootstrap/sh/boot.cmd b/fizz-bootstrap/sh/boot.cmd new file mode 100644 index 0000000..0e6051e --- /dev/null +++ b/fizz-bootstrap/sh/boot.cmd @@ -0,0 +1,69 @@ +@echo off + +if not exist "%JAVA_HOME%\bin\java.exe" echo Please set the JAVA_HOME variable in your environment. & EXIT /B 1 + +setlocal enabledelayedexpansion + +set BASE_DIR=%~dp0 +set APOLLO_META_SERVER=http://localhost:66 +set APOLLO_ENV=prod +set SPRING_PROFILES_ACTIVE=prod +set APP_NAME=fizz-gateway-community +set APP_NAME_JAR=%APP_NAME%.jar +set APP_DEP_DIR=%BASE_DIR% +set APP_LOG_DIR=%APP_DEP_DIR%logs +set JAVA_CMD="%JAVA_HOME%\bin\java.exe" + +IF NOT EXIST "%APP_LOG_DIR%" ( + MKDIR "%APP_LOG_DIR%" +) + +if "%1" == "stop" goto stop +if "%1" == "status" goto status + +if not "%1" == "start" if not "%1" == "restart" ( + echo "Usage: %0 {start|stop|restart|status}" + goto end +) + +rem JVM CONFIG +set MEM_OPTS=-Xms256m -Xmx4096m -XX:MetaspaceSize=128m -XX:MaxMetaspaceSize=256m + +set JAVA_OPTS=%MEM_OPTS% -XX:+AggressiveOpts -XX:+UseBiasedLocking -XX:+UseG1GC -XX:+HeapDumpOnOutOfMemoryError -XX:-OmitStackTraceInFastThrow -verbose:gc -XX:+PrintGCDetails -XX:+PrintGCDateStamps -XX:+PrintHeapAtGC -Xloggc:"%APP_LOG_DIR%\%START_DATE_TIME%.gc" -XX:+HeapDumpOnOutOfMemoryError -XX:HeapDumpPath="%APP_LOG_DIR%\dump.logs" -Dreactor.netty.pool.maxIdleTime=120000 -Dorg.jboss.netty.epollBugWorkaround=true + +if "%1" == "start" goto start +if "%1" == "restart" goto stop + +:status +for /f "tokens=1" %%i in ('jps -m ^| find /I "%APP_NAME%"') do ( + echo "%APP_NAME_JAR% is runing" + goto end +) +echo "%APP_NAME_JAR% is not runing" +goto end + +:stop +for /f "tokens=1" %%i in ('jps -m ^| find /I "%APP_NAME%"') do ( + goto doStop +) +echo "WARN:%APP_NAME_JAR% is not runing" +if "%1" == "restart" goto start +goto end + +:doStop +echo "Stoping %APP_NAME_JAR%..." +for /f "tokens=1" %%i in ('jps -m ^| find "%APP_NAME%"') do ( taskkill /F /PID %%i ) +if "%1" == "restart" goto start +goto end + +:start +for /f "tokens=1" %%i in ('jps -m ^| find /I "%APP_NAME%"') do ( + echo "WARN:%APP_NAME_JAR% already started! Ignoring startup request." + goto end +) + +echo "Starting %APP_NAME_JAR% ..." +%JAVA_CMD% %JAVA_OPTS% -Dfile.encoding=UTF-8 -Dspring.profiles.active=%SPRING_PROFILES_ACTIVE% -Denv=%APOLLO_ENV% -Dapollo.meta=%APOLLO_META_SERVER% -Dlogging.config=log4j2-spring.xml -jar "%APP_DEP_DIR%%APP_NAME_JAR%" +goto end + +:end diff --git a/fizz-bootstrap/src/main/resources/application.yml b/fizz-bootstrap/src/main/resources/application.yml index e9b925e..0739244 100644 --- a/fizz-bootstrap/src/main/resources/application.yml +++ b/fizz-bootstrap/src/main/resources/application.yml @@ -57,7 +57,7 @@ aggregate: # need replace password: 123456 #please input the redis password (default:123456) # need replace - database: 10 #please input the redis database (default:9) + database: 9 #please input the redis database (default:9) proxy-webclient: name: proxy aggr-webclient: From 6733cf08c906cbadb75197413d5bc543390d310c Mon Sep 17 00:00:00 2001 From: hongqiaowei Date: Wed, 23 Jun 2021 19:35:06 +0800 Subject: [PATCH 02/28] Support appid level flow control #212 --- .../src/main/java/we/util/NetworkUtils.java | 2 +- fizz-common/src/main/java/we/util/Utils.java | 22 ++ .../java/we/config/FlowStatSchedConfig.java | 189 ++++++++++++------ .../src/main/java/we/config/SystemConfig.java | 2 + .../we/controller/FlowControlController.java | 4 +- .../java/we/filter/FlowControlFilter.java | 162 +++++++++++---- .../ratelimit/ResourceRateLimitConfig.java | 128 +++++++++++- .../ResourceRateLimitConfigService.java | 81 +++++++- .../we/filter/FlowControlFilterTests.java | 32 ++- .../ResourceRateLimitConfigServiceTests.java | 11 +- .../ResourceRateLimitConfigTests.java | 27 +++ 11 files changed, 532 insertions(+), 128 deletions(-) diff --git a/fizz-common/src/main/java/we/util/NetworkUtils.java b/fizz-common/src/main/java/we/util/NetworkUtils.java index dc6a936..01a151b 100644 --- a/fizz-common/src/main/java/we/util/NetworkUtils.java +++ b/fizz-common/src/main/java/we/util/NetworkUtils.java @@ -42,7 +42,7 @@ public class NetworkUtils { private static String serverIp; - private static final String SERVER_IP = "SERVER_IP"; + private static final String SERVER_IP = "SERVER_IP"; public static String getServerIp() { try { diff --git a/fizz-common/src/main/java/we/util/Utils.java b/fizz-common/src/main/java/we/util/Utils.java index 8b64755..1d9976c 100644 --- a/fizz-common/src/main/java/we/util/Utils.java +++ b/fizz-common/src/main/java/we/util/Utils.java @@ -71,6 +71,28 @@ public abstract class Utils { b.append(k).append(c).append(v).append(separator); } + public static String extract(String str, char separator, int nx) { + int begin = 0, end = 0, n = 0, ny = nx + 1, l = str.length(); + for (int i = 0; i < l; i++) { + char c = str.charAt(i); + if (c == separator) { + n++; + if (n == nx) { + begin = i + 1; + } else if (n == ny) { + end = i; + break; + } + } + } + if (begin == 0) { + return Constants.Symbol.EMPTY; + } else if (end == 0) { + end = l; + } + return str.substring(begin, end); + } + public static String initials2lowerCase(String s) { if (StringUtils.isBlank(s)) { return s; diff --git a/fizz-core/src/main/java/we/config/FlowStatSchedConfig.java b/fizz-core/src/main/java/we/config/FlowStatSchedConfig.java index 017322a..2ab16df 100644 --- a/fizz-core/src/main/java/we/config/FlowStatSchedConfig.java +++ b/fizz-core/src/main/java/we/config/FlowStatSchedConfig.java @@ -68,6 +68,13 @@ public class FlowStatSchedConfig extends SchedConfig { private static final String _minRespTime = "\"minRespTime\":"; private static final String _maxRespTime = "\"maxRespTime\":"; + private static final String _app = "\"app\":"; + private static final String _sourceIp = "\"sourceIp\":"; + private static final String _service = "\"service\":"; + private static final String _path = "\"path\":"; + + private static final String parentResourceList = "$prl"; + @Resource private FlowStatSchedConfigProperties flowStatSchedConfigProperties; @@ -85,7 +92,7 @@ public class FlowStatSchedConfig extends SchedConfig { private long startTimeSlot = 0; - private Map key2totalBlockMap = new HashMap<>(); + private Map resourceTimeWindow2totalBlockRequestsMap = new HashMap<>(128); @Scheduled(cron = "${flow-stat-sched.cron}") public void sched() { @@ -105,78 +112,139 @@ public class FlowStatSchedConfig extends SchedConfig { return; } - key2totalBlockMap.clear(); + resourceTimeWindow2totalBlockRequestsMap.clear(); resourceTimeWindowStats.forEach(rtws -> { + String resource = rtws.getResourceId(); List wins = rtws.getWindows(); wins.forEach(w -> { - AtomicLong totalBlock = key2totalBlockMap.computeIfAbsent(String.format("%s%s", - ResourceRateLimitConfig.GLOBAL, w.getStartTime()), key -> new AtomicLong(0)); - totalBlock.addAndGet(w.getBlockRequests()); + long t = w.getStartTime(); + long blockRequests = w.getBlockRequests(); + resourceTimeWindow2totalBlockRequestsMap.put(resource + t, new AtomicLong(blockRequests)); + }); + }); + + resourceTimeWindowStats.forEach(rtws -> { + String resource = rtws.getResourceId(); + List wins = rtws.getWindows(); + wins.forEach(w -> { + accumulateParents(resource, w.getStartTime(), w.getBlockRequests()); }); }); resourceTimeWindowStats.forEach( rtws -> { String resource = rtws.getResourceId(); - ResourceRateLimitConfig config = resourceRateLimitConfigService.getResourceRateLimitConfig(resource); - int id = (config == null ? 0 : config.id); - int type; - if (ResourceRateLimitConfig.GLOBAL.equals(resource)) { - type = ResourceRateLimitConfig.Type.GLOBAL; - } else if (resource.charAt(0) == '/') { - type = ResourceRateLimitConfig.Type.API; - } else { - type = ResourceRateLimitConfig.Type.SERVICE; - } - List wins = rtws.getWindows(); - wins.forEach( - w -> { - StringBuilder b = ThreadContext.getStringBuilder(); - Long winStart = w.getStartTime(); - BigDecimal rps = w.getRps(); - double qps; - if (rps == null) { - qps = 0.00; - } else { - qps = rps.doubleValue(); - } - - AtomicLong totalBlock = key2totalBlockMap.get(String.format("%s%s", resource, winStart)); - Long totalBlockReqs = totalBlock != null ? totalBlock.get() : w.getBlockRequests(); - - b.append(Constants.Symbol.LEFT_BRACE); - b.append(_ip); toJsonStringValue(b, ip); b.append(Constants.Symbol.COMMA); - b.append(_id); b.append(id); b.append(Constants.Symbol.COMMA); - b.append(_resource); toJsonStringValue(b, resource); b.append(Constants.Symbol.COMMA); - b.append(_type); b.append(type); b.append(Constants.Symbol.COMMA); - b.append(_start); b.append(winStart); b.append(Constants.Symbol.COMMA); - b.append(_reqs); b.append(w.getTotal()); b.append(Constants.Symbol.COMMA); - b.append(_completeReqs); b.append(w.getCompReqs()); b.append(Constants.Symbol.COMMA); - b.append(_peakConcurrents); b.append(w.getPeakConcurrentReqeusts()); b.append(Constants.Symbol.COMMA); - b.append(_reqPerSec); b.append(qps); b.append(Constants.Symbol.COMMA); - b.append(_blockReqs); b.append(w.getBlockRequests()); b.append(Constants.Symbol.COMMA); - b.append(_totalBlockReqs); b.append(totalBlockReqs); b.append(Constants.Symbol.COMMA); - b.append(_errors); b.append(w.getErrors()); b.append(Constants.Symbol.COMMA); - b.append(_avgRespTime); b.append(w.getAvgRt()); b.append(Constants.Symbol.COMMA); - b.append(_maxRespTime); b.append(w.getMax()); b.append(Constants.Symbol.COMMA); - b.append(_minRespTime); b.append(w.getMin()); - b.append(Constants.Symbol.RIGHT_BRACE); - String msg = b.toString(); - if ("kafka".equals(flowStatSchedConfigProperties.getDest())) { // for internal use - log.warn(msg, LogService.HANDLE_STGY, LogService.toKF(flowStatSchedConfigProperties.getQueue())); - } else { - rt.convertAndSend(flowStatSchedConfigProperties.getQueue(), msg).subscribe(); - } - if (log.isDebugEnabled()) { - log.debug("report " + toDP19(winStart) + " win10: " + msg); - } + String app = null, pi = null, node = ResourceRateLimitConfig.NODE, service = null, path = null; + int type = ResourceRateLimitConfig.Type.NODE, id = 0; + ResourceRateLimitConfig c = resourceRateLimitConfigService.getResourceRateLimitConfig(resource); + if (c == null) { + service = ResourceRateLimitConfig.getService(resource); + if (service != null) { + type = ResourceRateLimitConfig.Type.SERVICE_DEFAULT; + } else { + app = ResourceRateLimitConfig.getApp(resource); + if (app != null) { + type = ResourceRateLimitConfig.Type.APP_DEFAULT; } - ); + } + } else { + app = c.app; + pi = c.ip; + service = c.service; + path = c.path; + type = c.type; + id = c.id; + } + + List wins = rtws.getWindows(); + for (int i = 0; i < wins.size(); i++) { + TimeWindowStat w = wins.get(i); + StringBuilder b = ThreadContext.getStringBuilder(); + long timeWin = w.getStartTime(); + BigDecimal rps = w.getRps(); + double qps; + if (rps == null) { + qps = 0.00; + } else { + qps = rps.doubleValue(); + } + + AtomicLong totalBlockRequests = resourceTimeWindow2totalBlockRequestsMap.get(resource + timeWin); + long tbrs = (totalBlockRequests == null ? w.getBlockRequests() : totalBlockRequests.longValue()); + + b.append(Constants.Symbol.LEFT_BRACE); + b.append(_ip); toJsonStringValue(b, ip); b.append(Constants.Symbol.COMMA); + b.append(_id); b.append(id); b.append(Constants.Symbol.COMMA); + + String r = null; + if (type == ResourceRateLimitConfig.Type.NODE) { + r = ResourceRateLimitConfig.NODE; + } else if (type == ResourceRateLimitConfig.Type.SERVICE_DEFAULT || type == ResourceRateLimitConfig.Type.SERVICE) { + r = service; + } + if (r != null) { + b.append(_resource); toJsonStringValue(b, r); b.append(Constants.Symbol.COMMA); + } + + b.append(_type); b.append(type); b.append(Constants.Symbol.COMMA); + + if (app != null) { + b.append(_app); toJsonStringValue(b, app); b.append(Constants.Symbol.COMMA); + } + + if (pi != null) { + b.append(_sourceIp); toJsonStringValue(b, pi); b.append(Constants.Symbol.COMMA); + } + + if (service != null) { + b.append(_service); toJsonStringValue(b, service); b.append(Constants.Symbol.COMMA); + } + + if (path != null) { + b.append(_path); toJsonStringValue(b, path); b.append(Constants.Symbol.COMMA); + } + + b.append(_start); b.append(timeWin); b.append(Constants.Symbol.COMMA); + b.append(_reqs); b.append(w.getTotal()); b.append(Constants.Symbol.COMMA); + b.append(_completeReqs); b.append(w.getCompReqs()); b.append(Constants.Symbol.COMMA); + b.append(_peakConcurrents); b.append(w.getPeakConcurrentReqeusts()); b.append(Constants.Symbol.COMMA); + b.append(_reqPerSec); b.append(qps); b.append(Constants.Symbol.COMMA); + b.append(_blockReqs); b.append(w.getBlockRequests()); b.append(Constants.Symbol.COMMA); + b.append(_totalBlockReqs); b.append(tbrs); b.append(Constants.Symbol.COMMA); + b.append(_errors); b.append(w.getErrors()); b.append(Constants.Symbol.COMMA); + b.append(_avgRespTime); b.append(w.getAvgRt()); b.append(Constants.Symbol.COMMA); + b.append(_maxRespTime); b.append(w.getMax()); b.append(Constants.Symbol.COMMA); + b.append(_minRespTime); b.append(w.getMin()); + b.append(Constants.Symbol.RIGHT_BRACE); + String msg = b.toString(); + if ("kafka".equals(flowStatSchedConfigProperties.getDest())) { // for internal use + log.warn(msg, LogService.HANDLE_STGY, LogService.toKF(flowStatSchedConfigProperties.getQueue())); + } else { + rt.convertAndSend(flowStatSchedConfigProperties.getQueue(), msg).subscribe(); + } + if (log.isDebugEnabled()) { + log.debug("report " + toDP19(timeWin) + " win10: " + msg); + } + } } ); startTimeSlot = recentEndTimeSlot; - log.info(toDP23(st) + " fss " + toDP23(System.currentTimeMillis())); + if (log.isInfoEnabled()) { + log.info(toDP23(st) + " fss " + toDP23(System.currentTimeMillis())); + } + } + + private void accumulateParents(String resource, long timeWin, long blockRequests) { + List prl = ThreadContext.getArrayList(parentResourceList, String.class); + resourceRateLimitConfigService.getParentsTo(resource, prl); + for (int i = 0; i < prl.size(); i++) { + String parentResource = prl.get(i); + AtomicLong parentTotalBlockRequests = resourceTimeWindow2totalBlockRequestsMap.get(parentResource + timeWin); + if (parentTotalBlockRequests != null) { + parentTotalBlockRequests.addAndGet(blockRequests); + } + } } private long getRecentEndTimeSlot(FlowStat flowStat) { @@ -198,8 +266,7 @@ public class FlowStatSchedConfig extends SchedConfig { } else { interval = 0; } - long recentEndTimeSlot = currentTimeSlot - interval * 1000 - 10 * 1000; - return recentEndTimeSlot; + return currentTimeSlot - interval * 1000 - 10 * 1000; } private String toDP19(long startTimeSlot) { diff --git a/fizz-core/src/main/java/we/config/SystemConfig.java b/fizz-core/src/main/java/we/config/SystemConfig.java index 2c559b8..e3fbe53 100644 --- a/fizz-core/src/main/java/we/config/SystemConfig.java +++ b/fizz-core/src/main/java/we/config/SystemConfig.java @@ -50,6 +50,8 @@ public class SystemConfig { public static final String DEFAULT_GATEWAY_TEST_PREFIX = "/_proxytest"; + public static final String DEFAULT_GATEWAY_TEST = "_proxytest"; + public static final String DEFAULT_GATEWAY_TEST_PREFIX0 = "/_proxytest/"; private String gatewayPrefix = DEFAULT_GATEWAY_PREFIX; diff --git a/fizz-core/src/main/java/we/controller/FlowControlController.java b/fizz-core/src/main/java/we/controller/FlowControlController.java index 0ea8944..780e777 100644 --- a/fizz-core/src/main/java/we/controller/FlowControlController.java +++ b/fizz-core/src/main/java/we/controller/FlowControlController.java @@ -72,11 +72,11 @@ public class FlowControlController { long currentTimeSlot = flowStat.currentTimeSlotId(); long startTimeSlot = currentTimeSlot - recent * 1000; TimeWindowStat timeWindowStat = null; - List wins = flowStat.getResourceTimeWindowStats(ResourceRateLimitConfig.GLOBAL, startTimeSlot, currentTimeSlot, recent); + List wins = flowStat.getResourceTimeWindowStats(ResourceRateLimitConfig.NODE_RESOURCE, startTimeSlot, currentTimeSlot, recent); if (wins == null || wins.isEmpty()) { result.put("rps", 0); } else { - concurrents = flowStat.getConcurrentRequests(ResourceRateLimitConfig.GLOBAL); + concurrents = flowStat.getConcurrentRequests(ResourceRateLimitConfig.NODE_RESOURCE); result.put("concurrents", concurrents); timeWindowStat = wins.get(0).getWindows().get(0); BigDecimal winrps = timeWindowStat.getRps(); diff --git a/fizz-core/src/main/java/we/filter/FlowControlFilter.java b/fizz-core/src/main/java/we/filter/FlowControlFilter.java index 37f2832..55a66fa 100644 --- a/fizz-core/src/main/java/we/filter/FlowControlFilter.java +++ b/fizz-core/src/main/java/we/filter/FlowControlFilter.java @@ -22,6 +22,7 @@ import java.util.List; import javax.annotation.Resource; +import org.apache.commons.lang3.StringUtils; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.beans.factory.annotation.Autowired; @@ -35,7 +36,11 @@ import org.springframework.web.server.WebFilterChain; import reactor.core.publisher.Mono; import reactor.core.publisher.SignalType; +import we.config.SystemConfig; import we.flume.clients.log4j2appender.LogService; +import we.legacy.RespEntity; +import we.plugin.auth.ApiConfigService; +import we.plugin.auth.AppService; import we.stats.BlockType; import we.stats.FlowStat; import we.stats.IncrRequestResult; @@ -43,6 +48,8 @@ import we.stats.ResourceConfig; import we.stats.ratelimit.ResourceRateLimitConfig; import we.stats.ratelimit.ResourceRateLimitConfigService; import we.util.Constants; +import we.util.JacksonUtils; +import we.util.ThreadContext; import we.util.WebUtils; /** @@ -69,10 +76,15 @@ public class FlowControlFilter extends FizzWebFilter { @Resource private ResourceRateLimitConfigService resourceRateLimitConfigService; - // @Resource @Autowired(required = false) private FlowStat flowStat; + @Resource + private ApiConfigService apiConfigService; + + @Resource + private AppService appService; + @Override public Mono doFilter(ServerWebExchange exchange, WebFilterChain chain) { @@ -81,61 +93,60 @@ public class FlowControlFilter extends FizzWebFilter { if (secFS == -1) { return WebUtils.responseError(exchange, HttpStatus.INTERNAL_SERVER_ERROR.value(), "request path should like /optional-prefix/service-name/real-biz-path"); } - String svc = path.substring(1, secFS); - boolean adminReq = false; - if (svc.equals(admin) || svc.equals(actuator)) { + String service = path.substring(1, secFS); + boolean adminReq = false, proxyTestReq = false; + if (service.equals(admin) || service.equals(actuator)) { adminReq = true; exchange.getAttributes().put(ADMIN_REQUEST, Constants.Symbol.EMPTY); + } else if (service.equals(SystemConfig.DEFAULT_GATEWAY_TEST)) { + proxyTestReq = true; + } else { + service = WebUtils.getClientService(exchange); } - if (flowControlFilterProperties.isFlowControl() && !adminReq) { - String service = WebUtils.getClientService(exchange); -// String reqPath = WebUtils.getClientReqPath(exchange); + if (flowControlFilterProperties.isFlowControl() && !adminReq && !proxyTestReq) { + LogService.setBizId(exchange.getRequest().getId()); + if (!apiConfigService.serviceConfigMap.containsKey(service)) { + String json = RespEntity.toJson(HttpStatus.FORBIDDEN.value(), "no service " + service, exchange.getRequest().getId()); + return WebUtils.buildJsonDirectResponse(exchange, HttpStatus.FORBIDDEN, null, json); + } + String app = WebUtils.getAppId(exchange); + if (app != null && !appService.getAppMap().containsKey(app)) { + String json = RespEntity.toJson(HttpStatus.FORBIDDEN.value(), "no app " + app, exchange.getRequest().getId()); + return WebUtils.buildJsonDirectResponse(exchange, HttpStatus.FORBIDDEN, null, json); + } + path = WebUtils.getClientReqPath(exchange); + String ip = WebUtils.getOriginIp(exchange); + long currentTimeSlot = flowStat.currentTimeSlotId(); - ResourceRateLimitConfig globalConfig = resourceRateLimitConfigService - .getResourceRateLimitConfig(ResourceRateLimitConfig.GLOBAL); - ResourceRateLimitConfig serviceConfig = resourceRateLimitConfigService.getResourceRateLimitConfig(service); - if (serviceConfig == null) { - serviceConfig = resourceRateLimitConfigService - .getResourceRateLimitConfig(ResourceRateLimitConfig.SERVICE_DEFAULT); - } - - // global - List resourceConfigs = new ArrayList<>(); - ResourceConfig globalResCfg = new ResourceConfig(ResourceRateLimitConfig.GLOBAL, 0, 0); - if (globalConfig != null && globalConfig.isEnable()) { - globalResCfg.setMaxCon(globalConfig.concurrents); - globalResCfg.setMaxQPS(globalConfig.qps); - } - resourceConfigs.add(globalResCfg); - - // service - ResourceConfig serviceResCfg = new ResourceConfig(service, 0, 0); - if (serviceConfig != null && serviceConfig.isEnable()) { - serviceResCfg.setMaxCon(serviceConfig.concurrents); - serviceResCfg.setMaxQPS(serviceConfig.qps); - } - resourceConfigs.add(serviceResCfg); - + List resourceConfigs = getFlowControlConfigs(app, ip, null, service, path); IncrRequestResult result = flowStat.incrRequest(resourceConfigs, currentTimeSlot); if (result != null && !result.isSuccess()) { + String blockedResourceId = result.getBlockedResourceId(); if (BlockType.CONCURRENT_REQUEST == result.getBlockType()) { - log.info("exceed {} flow limit, blocked by maximum concurrent requests", - result.getBlockedResourceId(), LogService.BIZ_ID, exchange.getRequest().getId()); + log.info("exceed {} flow limit, blocked by maximum concurrent requests", blockedResourceId, LogService.BIZ_ID, exchange.getRequest().getId()); } else { - log.info("exceed {} flow limit, blocked by maximum QPS", result.getBlockedResourceId(), - LogService.BIZ_ID, exchange.getRequest().getId()); + log.info("exceed {} flow limit, blocked by maximum QPS", blockedResourceId, LogService.BIZ_ID, exchange.getRequest().getId()); } -// ResourceRateLimitConfig config = result.getBlockedResourceId().equals(globalConfig.resource) -// ? globalConfig -// : serviceConfig; + ResourceRateLimitConfig c = resourceRateLimitConfigService.getResourceRateLimitConfig(ResourceRateLimitConfig.NODE_RESOURCE); + String rt = c.responseType, rc = c.responseContent; + c = resourceRateLimitConfigService.getResourceRateLimitConfig(blockedResourceId); + if (c != null) { + if (StringUtils.isNotBlank(c.responseType)) { + rt = c.responseType; + } + if (StringUtils.isNotBlank(c.responseContent)) { + rc = c.responseContent; + } + } ServerHttpResponse resp = exchange.getResponse(); resp.setStatusCode(HttpStatus.OK); - resp.getHeaders().add(HttpHeaders.CONTENT_TYPE, globalConfig.responseType); - return resp.writeWith(Mono.just(resp.bufferFactory().wrap(globalConfig.responseContent.getBytes()))); + resp.getHeaders().add(HttpHeaders.CONTENT_TYPE, rt); + return resp.writeWith(Mono.just(resp.bufferFactory().wrap(rc.getBytes()))); + } else { long start = System.currentTimeMillis(); return chain.filter(exchange).doFinally(s -> { @@ -151,4 +162,73 @@ public class FlowControlFilter extends FizzWebFilter { return chain.filter(exchange); } + + private List getFlowControlConfigs(String app, String ip, String node, String service, String path) { + if (log.isDebugEnabled()) { + log.debug("get flow control config by app={}, ip={}, node={}, service={}, path={}", app, ip, node, service, path); + } + List resourceConfigs = new ArrayList<>(9); + StringBuilder b = ThreadContext.getStringBuilder(); + + checkRateLimitConfigAndAddTo(resourceConfigs, b, null, null, ResourceRateLimitConfig.NODE, null, null, null); + checkRateLimitConfigAndAddTo(resourceConfigs, b, null, null, null, service, null, ResourceRateLimitConfig.SERVICE_DEFAULT); + checkRateLimitConfigAndAddTo(resourceConfigs, b, null, null, null, service, path, null); + + if (app != null) { + checkRateLimitConfigAndAddTo(resourceConfigs, b, app, null, null, null, null, ResourceRateLimitConfig.APP_DEFAULT); + checkRateLimitConfigAndAddTo(resourceConfigs, b, app, null, null, service, null, null); + checkRateLimitConfigAndAddTo(resourceConfigs, b, app, null, null, service, path, null); + } + + if (ip != null) { + checkRateLimitConfigAndAddTo(resourceConfigs, b, null, ip, null, null, null, null); + checkRateLimitConfigAndAddTo(resourceConfigs, b, null, ip, null, service, null, null); + checkRateLimitConfigAndAddTo(resourceConfigs, b, null, ip, null, service, path, null); + } + + if (log.isDebugEnabled()) { + log.debug("resource configs: " + JacksonUtils.writeValueAsString(resourceConfigs)); + } + return resourceConfigs; + } + + private void checkRateLimitConfigAndAddTo(List resourceConfigs, StringBuilder b, String app, String ip, String node, String service, String path, String defaultRateLimitConfigId) { + ResourceRateLimitConfig.buildResourceIdTo(b, app, ip, node, service, path); + String resourceId = b.toString(); + checkRateLimitConfigAndAddTo(resourceConfigs, resourceId, defaultRateLimitConfigId); + b.delete(0, b.length()); + } + + private void checkRateLimitConfigAndAddTo(List resourceConfigs, String resource, String defaultRateLimitConfigId) { + ResourceConfig rc = null; + ResourceRateLimitConfig rateLimitConfig = resourceRateLimitConfigService.getResourceRateLimitConfig(resource); + if (rateLimitConfig != null && rateLimitConfig.isEnable()) { + rc = new ResourceConfig(resource, rateLimitConfig.concurrents, rateLimitConfig.qps); + resourceConfigs.add(rc); + } else { + String node = ResourceRateLimitConfig.getNode(resource); + if (node != null && node.equals(ResourceRateLimitConfig.NODE)) { + rc = new ResourceConfig(resource, 0, 0); + } + if (defaultRateLimitConfigId != null) { + if (defaultRateLimitConfigId.equals(ResourceRateLimitConfig.SERVICE_DEFAULT)) { + rc = new ResourceConfig(resource, 0, 0); + rateLimitConfig = resourceRateLimitConfigService.getResourceRateLimitConfig(ResourceRateLimitConfig.SERVICE_DEFAULT_RESOURCE); + if (rateLimitConfig != null && rateLimitConfig.isEnable()) { + rc.setMaxCon(rateLimitConfig.concurrents); + rc.setMaxQPS(rateLimitConfig.qps); + } + } + if (defaultRateLimitConfigId.equals(ResourceRateLimitConfig.APP_DEFAULT)) { + rateLimitConfig = resourceRateLimitConfigService.getResourceRateLimitConfig(ResourceRateLimitConfig.APP_DEFAULT_RESOURCE); + if (rateLimitConfig != null && rateLimitConfig.isEnable()) { + rc = new ResourceConfig(resource, rateLimitConfig.concurrents, rateLimitConfig.qps); + } + } + } + if (rc != null) { + resourceConfigs.add(rc); + } + } + } } diff --git a/fizz-core/src/main/java/we/stats/ratelimit/ResourceRateLimitConfig.java b/fizz-core/src/main/java/we/stats/ratelimit/ResourceRateLimitConfig.java index 596538a..58a499c 100644 --- a/fizz-core/src/main/java/we/stats/ratelimit/ResourceRateLimitConfig.java +++ b/fizz-core/src/main/java/we/stats/ratelimit/ResourceRateLimitConfig.java @@ -17,7 +17,10 @@ package we.stats.ratelimit; +import com.fasterxml.jackson.annotation.JsonIgnore; +import we.util.Constants; import we.util.JacksonUtils; +import we.util.Utils; /** * @author hongqiaowei @@ -26,30 +29,51 @@ import we.util.JacksonUtils; public class ResourceRateLimitConfig { public static interface Type { - static final byte GLOBAL = 1; + static final byte NODE = 1; static final byte SERVICE_DEFAULT = 2; static final byte SERVICE = 3; static final byte API = 4; + static final byte APP_DEFAULT = 5; + static final byte APP = 6; + static final byte IP = 7; } - public static final int DELETED = 1; + public static final int DELETED = 1; - public static final String GLOBAL = "_global"; + public static final String NODE = "_global"; - public static final String SERVICE_DEFAULT = "service_default"; + public static final String NODE_RESOURCE = buildResourceId(null, null, NODE, null, null); - private static final int ENABLE = 1; + public static final String SERVICE_DEFAULT = "service_default"; - private static final int UNABLE = 0; + public static final String SERVICE_DEFAULT_RESOURCE = buildResourceId(null, null, null, SERVICE_DEFAULT, null); + + public static final String APP_DEFAULT = "app_default"; + + public static final String APP_DEFAULT_RESOURCE = buildResourceId(APP_DEFAULT, null, null, null, null); + + private static final int ENABLE = 1; + + private static final int UNABLE = 0; public int isDeleted = 0; public int id; - private boolean enable = true; + private boolean enable = true; public String resource; + public String service; + + public String path; + + public String app; + + public String ip; + + public String node; + public byte type; public long qps; @@ -72,6 +96,96 @@ public class ResourceRateLimitConfig { } } + public void setResource(String r) { + resource = r; + if (!resource.equals(NODE)) { + service = resource; + } + } + + public void setType(byte t) { + type = t; + if (type == Type.NODE) { + node = NODE; + } else if (type == Type.SERVICE_DEFAULT) { + service = SERVICE_DEFAULT; + } else if (type == Type.APP_DEFAULT) { + app = APP_DEFAULT; + } + } + + private String resourceId = null; + + @JsonIgnore + public String getResourceId() { + if (resourceId == null) { + resourceId = + (app == null ? "" : app) + '@' + + (ip == null ? "" : ip) + '@' + + (node == null ? "" : node) + '@' + + (service == null ? "" : service) + '@' + + (path == null ? "" : path) + ; + } + return resourceId; + } + + public static String buildResourceId(String app, String ip, String node, String service, String path) { + StringBuilder b = new StringBuilder(32); + buildResourceIdTo(b, app, ip, node, service, path); + return b.toString(); + } + + public static void buildResourceIdTo(StringBuilder b, String app, String ip, String node, String service, String path) { + b.append(app == null ? Constants.Symbol.EMPTY : app) .append(Constants.Symbol.AT); + b.append(ip == null ? Constants.Symbol.EMPTY : ip) .append(Constants.Symbol.AT); + b.append(node == null ? Constants.Symbol.EMPTY : node) .append(Constants.Symbol.AT); + b.append(service == null ? Constants.Symbol.EMPTY : service) .append(Constants.Symbol.AT); + b.append(path == null ? Constants.Symbol.EMPTY : path); + } + + public static String getApp(String resource) { + int i = resource.indexOf(Constants.Symbol.AT); + if (i == 0) { + return null; + } else { + return resource.substring(0, i); + } + } + + public static String getIp(String resource) { + String extract = Utils.extract(resource, Constants.Symbol.AT, 1); + if (extract.equals(Constants.Symbol.EMPTY)) { + return null; + } + return extract; + } + + public static String getNode(String resource) { + String extract = Utils.extract(resource, Constants.Symbol.AT, 2); + if (extract.equals(Constants.Symbol.EMPTY)) { + return null; + } + return extract; + } + + public static String getService(String resource) { + String extract = Utils.extract(resource, Constants.Symbol.AT, 3); + if (extract.equals(Constants.Symbol.EMPTY)) { + return null; + } + return extract; + } + + public static String getPath(String resource) { + int i = resource.lastIndexOf(Constants.Symbol.AT); + if (i == resource.length() - 1) { + return null; + } else { + return resource.substring(i); + } + } + @Override public String toString() { return JacksonUtils.writeValueAsString(this); diff --git a/fizz-core/src/main/java/we/stats/ratelimit/ResourceRateLimitConfigService.java b/fizz-core/src/main/java/we/stats/ratelimit/ResourceRateLimitConfigService.java index 9d84f9b..6f046da 100644 --- a/fizz-core/src/main/java/we/stats/ratelimit/ResourceRateLimitConfigService.java +++ b/fizz-core/src/main/java/we/stats/ratelimit/ResourceRateLimitConfigService.java @@ -27,13 +27,11 @@ import we.config.AggregateRedisConfig; import we.flume.clients.log4j2appender.LogService; import we.util.JacksonUtils; import we.util.ReactorUtils; +import we.util.ThreadContext; import javax.annotation.PostConstruct; import javax.annotation.Resource; -import java.util.AbstractMap; -import java.util.HashMap; -import java.util.Map; -import java.util.Objects; +import java.util.*; import java.util.concurrent.TimeUnit; import java.util.function.Supplier; @@ -130,7 +128,7 @@ public class ResourceRateLimitConfigService { ResourceRateLimitConfig rrlc = JacksonUtils.readValue(json, ResourceRateLimitConfig.class); ResourceRateLimitConfig r = oldResourceRateLimitConfigMap.remove(rrlc.id); if (rrlc.isDeleted != ResourceRateLimitConfig.DELETED && r != null) { - resourceRateLimitConfigMap.remove(r.resource); + resourceRateLimitConfigMap.remove(r.getResourceId()); } updateResourceRateLimitConfigMap(rrlc, resourceRateLimitConfigMap); if (rrlc.isDeleted != ResourceRateLimitConfig.DELETED) { @@ -158,11 +156,11 @@ public class ResourceRateLimitConfigService { private void updateResourceRateLimitConfigMap(ResourceRateLimitConfig rrlc, Map resourceRateLimitConfigMap) { if (rrlc.isDeleted == ResourceRateLimitConfig.DELETED) { - ResourceRateLimitConfig removedRrlc = resourceRateLimitConfigMap.remove(rrlc.resource); + ResourceRateLimitConfig removedRrlc = resourceRateLimitConfigMap.remove(rrlc.getResourceId()); log.info("remove " + removedRrlc); } else { - ResourceRateLimitConfig existRrlc = resourceRateLimitConfigMap.get(rrlc.resource); - resourceRateLimitConfigMap.put(rrlc.resource, rrlc); + ResourceRateLimitConfig existRrlc = resourceRateLimitConfigMap.get(rrlc.getResourceId()); + resourceRateLimitConfigMap.put(rrlc.getResourceId(), rrlc); if (existRrlc == null) { log.info("add " + rrlc); } else { @@ -182,4 +180,71 @@ public class ResourceRateLimitConfigService { public Map getResourceRateLimitConfigMap() { return resourceRateLimitConfigMap; } + + public void getParentsTo(String resource, List parentList) { + String app = null, ip = null, node = null, service = null, path = null; + ResourceRateLimitConfig c = resourceRateLimitConfigMap.get(resource); + if (c == null) { + service = ResourceRateLimitConfig.getService(resource); + if (service != null) { + parentList.add(ResourceRateLimitConfig.NODE_RESOURCE); + } + return; + } else { + if (c.type == ResourceRateLimitConfig.Type.NODE) { + return; + } + if (c.type == ResourceRateLimitConfig.Type.SERVICE) { + parentList.add(ResourceRateLimitConfig.NODE_RESOURCE); + return; + } + app = c.app; + ip = c.ip; + service = c.service; + path = c.path; + } + + StringBuilder b = ThreadContext.getStringBuilder(); + + if (app != null) { + if (path != null) { + ResourceRateLimitConfig.buildResourceIdTo(b, app, null, null, service, null); + checkRateLimitConfigAndAddTo(b, parentList); + ResourceRateLimitConfig.buildResourceIdTo(b, app, null, null, null, null); + checkRateLimitConfigAndAddTo(b, parentList); + } else if (service != null) { + ResourceRateLimitConfig.buildResourceIdTo(b, app, null, null, null, null); + checkRateLimitConfigAndAddTo(b, parentList); + } + } + + if (ip != null) { + if (path != null) { + ResourceRateLimitConfig.buildResourceIdTo(b, null, ip, null, service, null); + checkRateLimitConfigAndAddTo(b, parentList); + ResourceRateLimitConfig.buildResourceIdTo(b, null, ip, null, null, null); + checkRateLimitConfigAndAddTo(b, parentList); + } else if (service != null) { + ResourceRateLimitConfig.buildResourceIdTo(b, null, ip, null, null, null); + checkRateLimitConfigAndAddTo(b, parentList); + } + } + + if (path != null) { + ResourceRateLimitConfig.buildResourceIdTo(b, null, null, null, service, null); + parentList.add(b.toString()); + b.delete(0, b.length()); + } + + parentList.add(ResourceRateLimitConfig.NODE_RESOURCE); + } + + private void checkRateLimitConfigAndAddTo(StringBuilder resourceStringBuilder, List resourceList) { + String r = resourceStringBuilder.toString(); + ResourceRateLimitConfig c = resourceRateLimitConfigMap.get(r); + if (c != null) { + resourceList.add(r); + } + resourceStringBuilder.delete(0, resourceStringBuilder.length()); + } } diff --git a/fizz-core/src/test/java/we/filter/FlowControlFilterTests.java b/fizz-core/src/test/java/we/filter/FlowControlFilterTests.java index 5886e8f..e85f741 100644 --- a/fizz-core/src/test/java/we/filter/FlowControlFilterTests.java +++ b/fizz-core/src/test/java/we/filter/FlowControlFilterTests.java @@ -52,16 +52,24 @@ public class FlowControlFilterTests { // @Test void flowControlFilterTest() throws NoSuchFieldException, InterruptedException { - FlowControlFilter flowControlFilter = new FlowControlFilter(); - ReflectionUtils.set(flowControlFilter, "flowControl", true); + FlowControlFilter filter = new FlowControlFilter(); + FlowControlFilterProperties flowControlFilterProperties = new FlowControlFilterProperties(); + ReflectionUtils.set(flowControlFilterProperties, "flowControl", true); + ReflectionUtils.set(filter, "flowControlFilterProperties", flowControlFilterProperties); + FlowStat flowStat = new FlowStat(); - ReflectionUtils.set(flowControlFilter, "flowStat", flowStat); + ReflectionUtils.set(filter, "flowStat", flowStat); ResourceRateLimitConfigService resourceRateLimitConfigService = new ResourceRateLimitConfigService(); Map map = resourceRateLimitConfigService.getResourceRateLimitConfigMap(); + ResourceRateLimitConfig config = JacksonUtils.readValue("{\"concurrents\":66,\"enable\":1,\"id\":1,\"isDeleted\":0,\"resource\":\"_global\",\"type\":1}", ResourceRateLimitConfig.class); - map.put(ResourceRateLimitConfig.GLOBAL, config); - ReflectionUtils.set(flowControlFilter, "resourceRateLimitConfigService", resourceRateLimitConfigService); + map.put(ResourceRateLimitConfig.NODE_RESOURCE, config); + + config = JacksonUtils.readValue("{\"concurrents\":33,\"enable\":1,\"id\":2,\"isDeleted\":0, \"service\":\"xservice\", \"path\":\"/ypath\", \"type\":4}", ResourceRateLimitConfig.class); + map.put(config.getResourceId(), config); + + ReflectionUtils.set(filter, "resourceRateLimitConfigService", resourceRateLimitConfigService); WebTestClient client = WebTestClient.bindToWebHandler( new WebHandler() { @@ -74,14 +82,24 @@ public class FlowControlFilterTests { } } ) - .webFilter(flowControlFilter) + .webFilter(filter) .build(); + client.get().uri("/proxy/xservice/ypath").exchange(); Thread.sleep(1000); long currentTimeSlot = flowStat.currentTimeSlotId(); long startTimeSlot = currentTimeSlot - 10 * 1000; - List resourceTimeWindowStats = flowStat.getResourceTimeWindowStats("xservice", startTimeSlot, currentTimeSlot, 10); + + // System.err.println(JacksonUtils.writeValueAsString(flowStat.resourceStats)); + + String xservice = ResourceRateLimitConfig.buildResourceId(null, null, null, "xservice", null); + List resourceTimeWindowStats = flowStat.getResourceTimeWindowStats(xservice, startTimeSlot, currentTimeSlot, 10); TimeWindowStat win = resourceTimeWindowStats.get(0).getWindows().get(0); assertEquals(win.getCompReqs(), 1); + + String xserviceYpath = ResourceRateLimitConfig.buildResourceId(null, null, null, "xservice", "/ypath"); + resourceTimeWindowStats = flowStat.getResourceTimeWindowStats(xserviceYpath, startTimeSlot, currentTimeSlot, 10); + win = resourceTimeWindowStats.get(0).getWindows().get(0); + assertEquals(win.getCompReqs(), 1); } } diff --git a/fizz-core/src/test/java/we/stats/ratelimit/ResourceRateLimitConfigServiceTests.java b/fizz-core/src/test/java/we/stats/ratelimit/ResourceRateLimitConfigServiceTests.java index 8b59782..8c2bce0 100644 --- a/fizz-core/src/test/java/we/stats/ratelimit/ResourceRateLimitConfigServiceTests.java +++ b/fizz-core/src/test/java/we/stats/ratelimit/ResourceRateLimitConfigServiceTests.java @@ -9,9 +9,12 @@ import org.springframework.test.context.junit.jupiter.SpringJUnitConfig; import we.redis.RedisProperties; import we.redis.RedisServerConfiguration; import we.redis.RedisTemplateConfiguration; +import we.util.JacksonUtils; import javax.annotation.Resource; +import java.util.Map; + import static org.junit.jupiter.api.Assertions.assertEquals; /** @@ -46,11 +49,17 @@ public class ResourceRateLimitConfigServiceTests { @Test void initTest() throws Throwable { stringRedisTemplate.opsForHash().put("fizz_rate_limit", "2", "{\"concurrents\":66,\"enable\":1,\"id\":2,\"isDeleted\":0,\"resource\":\"service_default\",\"type\":2}"); + stringRedisTemplate.opsForHash().put("fizz_rate_limit", "3", "{\"concurrents\":88,\"enable\":1,\"id\":3,\"isDeleted\":0, \"type\":6, \"app\":\"xapp\", \"service\":\"yservice\" }"); resourceRateLimitConfigService.init(); - ResourceRateLimitConfig resourceRateLimitConfig = resourceRateLimitConfigService.getResourceRateLimitConfig("service_default"); + ResourceRateLimitConfig resourceRateLimitConfig = resourceRateLimitConfigService.getResourceRateLimitConfig(ResourceRateLimitConfig.SERVICE_DEFAULT_RESOURCE); + // Map resourceRateLimitConfigMap = resourceRateLimitConfigService.getResourceRateLimitConfigMap(); + // System.err.println(JacksonUtils.writeValueAsString(resourceRateLimitConfigMap)); assertEquals(resourceRateLimitConfig.concurrents, 66); // System.err.println(resourceRateLimitConfig); // Thread.currentThread().join(); + resourceRateLimitConfig = resourceRateLimitConfigService.getResourceRateLimitConfig("xapp@@@yservice@"); + assertEquals(resourceRateLimitConfig.concurrents, 88); + Thread.sleep(4000); // System.err.println("init test end"); } diff --git a/fizz-core/src/test/java/we/stats/ratelimit/ResourceRateLimitConfigTests.java b/fizz-core/src/test/java/we/stats/ratelimit/ResourceRateLimitConfigTests.java index d8fb086..80aaac2 100644 --- a/fizz-core/src/test/java/we/stats/ratelimit/ResourceRateLimitConfigTests.java +++ b/fizz-core/src/test/java/we/stats/ratelimit/ResourceRateLimitConfigTests.java @@ -17,4 +17,31 @@ public class ResourceRateLimitConfigTests { ResourceRateLimitConfig resourceRateLimitConfig = JacksonUtils.readValue(resourceRateLimitConfigJson, ResourceRateLimitConfig.class); assertEquals("application/json; charset=UTF-8", resourceRateLimitConfig.responseType); } + + @Test + void resourceIdTest() { + String resourceRateLimitConfigJson = "{\"concurrents\":1000,\"enable\":1,\"id\":1,\"isDeleted\":0,\"qps\":500, \"type\":1, \"resource\":\"_global\" }"; + ResourceRateLimitConfig c = JacksonUtils.readValue(resourceRateLimitConfigJson, ResourceRateLimitConfig.class); + String resourceId = c.getResourceId(); + assertEquals("@@_global@@", resourceId); + + String node = ResourceRateLimitConfig.getNode(resourceId); + assertEquals("_global", node); + + resourceRateLimitConfigJson = "{\"concurrents\":1000,\"enable\":1,\"id\":1,\"isDeleted\":0,\"qps\":500, \"type\":2, \"resource\":\"service_default\" }"; + c = JacksonUtils.readValue(resourceRateLimitConfigJson, ResourceRateLimitConfig.class); + resourceId = c.getResourceId(); + assertEquals("@@@service_default@", resourceId); + + resourceRateLimitConfigJson = "{\"concurrents\":1000,\"enable\":1,\"id\":1,\"isDeleted\":0,\"qps\":500, \"type\":3, \"resource\":\"xservice\" }"; + c = JacksonUtils.readValue(resourceRateLimitConfigJson, ResourceRateLimitConfig.class); + resourceId = c.getResourceId(); + assertEquals("@@@xservice@", resourceId); + + resourceId = ResourceRateLimitConfig.buildResourceId(null, null, ResourceRateLimitConfig.NODE, null, null); + assertEquals("@@_global@@", resourceId); + + resourceId = ResourceRateLimitConfig.buildResourceId(null, "192.168.1.1", null, "xservice", null); + assertEquals("@192.168.1.1@@xservice@", resourceId); + } } From 9c7c2c2ac11537bb9d143479a1df85e0f85a9503 Mon Sep 17 00:00:00 2001 From: hongqiaowei Date: Wed, 23 Jun 2021 22:17:28 +0800 Subject: [PATCH 03/28] Upgrade project dependencies #231 --- fizz-bootstrap/pom.xml | 7 +++++-- fizz-common/pom.xml | 10 +++++----- fizz-core/pom.xml | 21 ++++++++++++++++----- fizz-plugin/pom.xml | 15 ++++++++++----- fizz-spring-boot-starter/pom.xml | 17 +++++++++++------ pom.xml | 27 +++++++++++++++++---------- 6 files changed, 64 insertions(+), 33 deletions(-) diff --git a/fizz-bootstrap/pom.xml b/fizz-bootstrap/pom.xml index e4b72ea..3a39c10 100644 --- a/fizz-bootstrap/pom.xml +++ b/fizz-bootstrap/pom.xml @@ -17,11 +17,13 @@ 1.8 5.2.15.RELEASE - Dysprosium-SR20 + Dragonfruit-SR3 + Dysprosium-SR21 5.3.7.RELEASE 4.1.65.Final 4.4.14 - 2.13.3 + 2.14.1 + 1.7.31 3.12.0 1.18.20 2.7.5 @@ -29,6 +31,7 @@ 3.4.6 4.0.1 3.5.9 + 1.15 diff --git a/fizz-common/pom.xml b/fizz-common/pom.xml index 30e5d37..2504c1f 100644 --- a/fizz-common/pom.xml +++ b/fizz-common/pom.xml @@ -58,11 +58,6 @@ spring-session-data-redis - - commons-codec - commons-codec - - org.bouncycastle bcpkix-jdk15on @@ -98,6 +93,11 @@ + + + commons-codec + commons-codec + diff --git a/fizz-core/pom.xml b/fizz-core/pom.xml index b220edf..007d300 100644 --- a/fizz-core/pom.xml +++ b/fizz-core/pom.xml @@ -37,7 +37,7 @@ org.springframework.session spring-session-bom - Dragonfruit-RELEASE + Dragonfruit-SR3 pom import @@ -153,6 +153,12 @@ com.github.ben-manes.caffeine caffeine + + + error_prone_annotations + com.google.errorprone + + @@ -253,13 +259,18 @@ - commons-codec - commons-codec + org.bouncycastle + bcpkix-jdk15on - org.bouncycastle - bcpkix-jdk15on + com.google.guava + guava + + + + commons-codec + commons-codec diff --git a/fizz-plugin/pom.xml b/fizz-plugin/pom.xml index 648af6f..57e994d 100644 --- a/fizz-plugin/pom.xml +++ b/fizz-plugin/pom.xml @@ -34,7 +34,7 @@ org.springframework.session spring-session-bom - Dragonfruit-RELEASE + Dragonfruit-SR3 pom import @@ -245,13 +245,18 @@ - commons-codec - commons-codec + org.bouncycastle + bcpkix-jdk15on - org.bouncycastle - bcpkix-jdk15on + com.google.guava + guava + + + + commons-codec + commons-codec diff --git a/fizz-spring-boot-starter/pom.xml b/fizz-spring-boot-starter/pom.xml index a35041b..44f49fd 100644 --- a/fizz-spring-boot-starter/pom.xml +++ b/fizz-spring-boot-starter/pom.xml @@ -19,7 +19,7 @@ org.springframework.session spring-session-bom - Dragonfruit-RELEASE + Dragonfruit-SR3 pom import @@ -227,11 +227,6 @@ test - - commons-codec - commons-codec - - org.bouncycastle bcpkix-jdk15on @@ -255,6 +250,16 @@ com.fizzgate fizz-plugin + + + com.google.guava + guava + + + + commons-codec + commons-codec + \ No newline at end of file diff --git a/pom.xml b/pom.xml index 64f5ff5..8fe5738 100644 --- a/pom.xml +++ b/pom.xml @@ -7,12 +7,13 @@ 2.2.13.RELEASE 5.2.15.RELEASE - Dysprosium-SR20 + Dysprosium-SR21 5.3.7.RELEASE 2.2.5.RELEASE 4.1.65.Final 4.4.14 - 2.13.3 + 2.14.1 + 1.7.31 2.7.5 1.16.1 3.4.6 @@ -86,7 +87,7 @@ org.springframework.session spring-session-bom - Dragonfruit-RELEASE + Dragonfruit-SR3 pom import @@ -129,7 +130,7 @@ io.projectreactor reactor-test - 3.3.17.RELEASE + 3.3.18.RELEASE test @@ -342,12 +343,6 @@ test - - commons-codec - commons-codec - 1.15 - - org.bouncycastle bcpkix-jdk15on @@ -359,6 +354,18 @@ kxml2 2.3.0 + + + com.google.guava + guava + 21.0 + + + + commons-codec + commons-codec + 1.15 + From 76f51b598e5ef7b46452bede486f114397f8686f Mon Sep 17 00:00:00 2001 From: hongqiaowei Date: Wed, 23 Jun 2021 22:29:13 +0800 Subject: [PATCH 04/28] Release v2.2.0-beta1 --- fizz-bootstrap/pom.xml | 2 +- fizz-common/pom.xml | 2 +- fizz-core/pom.xml | 2 +- fizz-plugin/pom.xml | 2 +- fizz-spring-boot-starter/pom.xml | 2 +- pom.xml | 2 +- 6 files changed, 6 insertions(+), 6 deletions(-) diff --git a/fizz-bootstrap/pom.xml b/fizz-bootstrap/pom.xml index 3a39c10..483d2a2 100644 --- a/fizz-bootstrap/pom.xml +++ b/fizz-bootstrap/pom.xml @@ -12,7 +12,7 @@ com.fizzgate fizz-bootstrap - 2.0.0 + 2.2.0-beta1 1.8 diff --git a/fizz-common/pom.xml b/fizz-common/pom.xml index 2504c1f..ad97496 100644 --- a/fizz-common/pom.xml +++ b/fizz-common/pom.xml @@ -5,7 +5,7 @@ fizz-gateway-community com.fizzgate - 2.0.0 + 2.2.0-beta1 ../pom.xml 4.0.0 diff --git a/fizz-core/pom.xml b/fizz-core/pom.xml index 007d300..3838841 100644 --- a/fizz-core/pom.xml +++ b/fizz-core/pom.xml @@ -5,7 +5,7 @@ fizz-gateway-community com.fizzgate - 2.0.0 + 2.2.0-beta1 ../pom.xml 4.0.0 diff --git a/fizz-plugin/pom.xml b/fizz-plugin/pom.xml index 57e994d..ada2c51 100644 --- a/fizz-plugin/pom.xml +++ b/fizz-plugin/pom.xml @@ -5,7 +5,7 @@ fizz-gateway-community com.fizzgate - 2.0.0 + 2.2.0-beta1 ../pom.xml 4.0.0 diff --git a/fizz-spring-boot-starter/pom.xml b/fizz-spring-boot-starter/pom.xml index 44f49fd..969089b 100644 --- a/fizz-spring-boot-starter/pom.xml +++ b/fizz-spring-boot-starter/pom.xml @@ -5,7 +5,7 @@ fizz-gateway-community com.fizzgate - 2.0.0 + 2.2.0-beta1 ../pom.xml 4.0.0 diff --git a/pom.xml b/pom.xml index 8fe5738..cfb75e8 100644 --- a/pom.xml +++ b/pom.xml @@ -31,7 +31,7 @@ fizz-gateway-community ${project.artifactId} fizz gateway community - 2.0.0 + 2.2.0-beta1 pom fizz-common From f4f42455d07c76b4e58322747e3e93b899930e9a Mon Sep 17 00:00:00 2001 From: hongqiaowei Date: Thu, 24 Jun 2021 16:00:32 +0800 Subject: [PATCH 05/28] Release v2.2.0-beta2 --- fizz-bootstrap/pom.xml | 4 ++-- fizz-common/pom.xml | 2 +- fizz-core/pom.xml | 2 +- fizz-plugin/pom.xml | 2 +- fizz-spring-boot-starter/pom.xml | 2 +- pom.xml | 4 ++-- 6 files changed, 8 insertions(+), 8 deletions(-) diff --git a/fizz-bootstrap/pom.xml b/fizz-bootstrap/pom.xml index 483d2a2..e7746d6 100644 --- a/fizz-bootstrap/pom.xml +++ b/fizz-bootstrap/pom.xml @@ -12,11 +12,11 @@ com.fizzgate fizz-bootstrap - 2.2.0-beta1 + 2.2.0-beta2 1.8 - 5.2.15.RELEASE + 5.2.13.RELEASE Dragonfruit-SR3 Dysprosium-SR21 5.3.7.RELEASE diff --git a/fizz-common/pom.xml b/fizz-common/pom.xml index ad97496..8cd96fc 100644 --- a/fizz-common/pom.xml +++ b/fizz-common/pom.xml @@ -5,7 +5,7 @@ fizz-gateway-community com.fizzgate - 2.2.0-beta1 + 2.2.0-beta2 ../pom.xml 4.0.0 diff --git a/fizz-core/pom.xml b/fizz-core/pom.xml index 3838841..a2bc0a0 100644 --- a/fizz-core/pom.xml +++ b/fizz-core/pom.xml @@ -5,7 +5,7 @@ fizz-gateway-community com.fizzgate - 2.2.0-beta1 + 2.2.0-beta2 ../pom.xml 4.0.0 diff --git a/fizz-plugin/pom.xml b/fizz-plugin/pom.xml index ada2c51..865da1d 100644 --- a/fizz-plugin/pom.xml +++ b/fizz-plugin/pom.xml @@ -5,7 +5,7 @@ fizz-gateway-community com.fizzgate - 2.2.0-beta1 + 2.2.0-beta2 ../pom.xml 4.0.0 diff --git a/fizz-spring-boot-starter/pom.xml b/fizz-spring-boot-starter/pom.xml index 969089b..f2091be 100644 --- a/fizz-spring-boot-starter/pom.xml +++ b/fizz-spring-boot-starter/pom.xml @@ -5,7 +5,7 @@ fizz-gateway-community com.fizzgate - 2.2.0-beta1 + 2.2.0-beta2 ../pom.xml 4.0.0 diff --git a/pom.xml b/pom.xml index cfb75e8..95ceae9 100644 --- a/pom.xml +++ b/pom.xml @@ -6,7 +6,7 @@ 2.2.13.RELEASE - 5.2.15.RELEASE + 5.2.13.RELEASE Dysprosium-SR21 5.3.7.RELEASE 2.2.5.RELEASE @@ -31,7 +31,7 @@ fizz-gateway-community ${project.artifactId} fizz gateway community - 2.2.0-beta1 + 2.2.0-beta2 pom fizz-common From c91e8864ae0fcd104b9c0b467cc902bb49424ce8 Mon Sep 17 00:00:00 2001 From: Francis Dong Date: Fri, 25 Jun 2021 11:19:42 +0800 Subject: [PATCH 06/28] print access log of cancelled request #233 --- fizz-core/src/main/java/we/filter/FizzLogFilter.java | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/fizz-core/src/main/java/we/filter/FizzLogFilter.java b/fizz-core/src/main/java/we/filter/FizzLogFilter.java index 93e49a4..7756447 100644 --- a/fizz-core/src/main/java/we/filter/FizzLogFilter.java +++ b/fizz-core/src/main/java/we/filter/FizzLogFilter.java @@ -20,16 +20,15 @@ package we.filter; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.core.annotation.Order; -import org.springframework.http.HttpStatus; import org.springframework.stereotype.Component; import org.springframework.web.server.ServerWebExchange; import org.springframework.web.server.WebFilter; import org.springframework.web.server.WebFilterChain; + import reactor.core.publisher.Mono; import we.flume.clients.log4j2appender.LogService; -import we.util.Constants; import we.util.ThreadContext; -import we.util.WebUtils; +import we.util.WebUtils; /** * @author hongqiaowei @@ -49,8 +48,8 @@ public class FizzLogFilter implements WebFilter { public Mono filter(ServerWebExchange exchange, WebFilterChain chain) { long startTime = System.currentTimeMillis(); - return chain.filter(exchange).doAfterTerminate( - () -> { + return chain.filter(exchange).doFinally( + (c) -> { if (LOGGER.isInfoEnabled()) { StringBuilder b = ThreadContext.getStringBuilder(); WebUtils.request2stringBuilder(exchange, b); From ef8809598a5f5745458716a13ed84ea231995329 Mon Sep 17 00:00:00 2001 From: Francis Dong Date: Fri, 25 Jun 2021 11:40:02 +0800 Subject: [PATCH 07/28] ON_ERROR signal and 5xx http status are classified as errors #235 --- fizz-core/src/main/java/we/filter/FlowControlFilter.java | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/fizz-core/src/main/java/we/filter/FlowControlFilter.java b/fizz-core/src/main/java/we/filter/FlowControlFilter.java index 55a66fa..c2091c0 100644 --- a/fizz-core/src/main/java/we/filter/FlowControlFilter.java +++ b/fizz-core/src/main/java/we/filter/FlowControlFilter.java @@ -151,10 +151,10 @@ public class FlowControlFilter extends FizzWebFilter { long start = System.currentTimeMillis(); return chain.filter(exchange).doFinally(s -> { long rt = System.currentTimeMillis() - start; - if (s == SignalType.ON_COMPLETE) { - flowStat.addRequestRT(resourceConfigs, currentTimeSlot, rt, true); - } else { + if (s == SignalType.ON_ERROR || exchange.getResponse().getStatusCode().is5xxServerError()) { flowStat.addRequestRT(resourceConfigs, currentTimeSlot, rt, false); + } else { + flowStat.addRequestRT(resourceConfigs, currentTimeSlot, rt, true); } }); } From 6cec714a0aaf12a9baff7222e4a4526f84aa184f Mon Sep 17 00:00:00 2001 From: hongqiaowei Date: Fri, 25 Jun 2021 16:04:46 +0800 Subject: [PATCH 08/28] Release v2.2.0-beta3 --- fizz-bootstrap/pom.xml | 2 +- fizz-common/pom.xml | 2 +- fizz-core/pom.xml | 2 +- .../java/we/config/FlowStatSchedConfig.java | 29 ++++++++--- .../java/we/filter/FlowControlFilter.java | 50 +++++++++++++++++++ fizz-plugin/pom.xml | 2 +- fizz-spring-boot-starter/pom.xml | 2 +- pom.xml | 2 +- 8 files changed, 79 insertions(+), 12 deletions(-) diff --git a/fizz-bootstrap/pom.xml b/fizz-bootstrap/pom.xml index e7746d6..113dac1 100644 --- a/fizz-bootstrap/pom.xml +++ b/fizz-bootstrap/pom.xml @@ -12,7 +12,7 @@ com.fizzgate fizz-bootstrap - 2.2.0-beta2 + 2.2.0-beta3 1.8 diff --git a/fizz-common/pom.xml b/fizz-common/pom.xml index 8cd96fc..c55038a 100644 --- a/fizz-common/pom.xml +++ b/fizz-common/pom.xml @@ -5,7 +5,7 @@ fizz-gateway-community com.fizzgate - 2.2.0-beta2 + 2.2.0-beta3 ../pom.xml 4.0.0 diff --git a/fizz-core/pom.xml b/fizz-core/pom.xml index a2bc0a0..936b83d 100644 --- a/fizz-core/pom.xml +++ b/fizz-core/pom.xml @@ -5,7 +5,7 @@ fizz-gateway-community com.fizzgate - 2.2.0-beta2 + 2.2.0-beta3 ../pom.xml 4.0.0 diff --git a/fizz-core/src/main/java/we/config/FlowStatSchedConfig.java b/fizz-core/src/main/java/we/config/FlowStatSchedConfig.java index 2ab16df..ec820bc 100644 --- a/fizz-core/src/main/java/we/config/FlowStatSchedConfig.java +++ b/fizz-core/src/main/java/we/config/FlowStatSchedConfig.java @@ -137,14 +137,31 @@ public class FlowStatSchedConfig extends SchedConfig { String app = null, pi = null, node = ResourceRateLimitConfig.NODE, service = null, path = null; int type = ResourceRateLimitConfig.Type.NODE, id = 0; ResourceRateLimitConfig c = resourceRateLimitConfigService.getResourceRateLimitConfig(resource); - if (c == null) { - service = ResourceRateLimitConfig.getService(resource); - if (service != null) { - type = ResourceRateLimitConfig.Type.SERVICE_DEFAULT; + + if (c == null) { // _global, service, app, ip, ip+service + node = ResourceRateLimitConfig.getNode(resource); + if (node != null && node.equals(ResourceRateLimitConfig.NODE)) { } else { + service = ResourceRateLimitConfig.getService(resource); app = ResourceRateLimitConfig.getApp(resource); - if (app != null) { - type = ResourceRateLimitConfig.Type.APP_DEFAULT; + pi = ResourceRateLimitConfig.getIp(resource); + if (service == null) { + if (app == null) { + type = ResourceRateLimitConfig.Type.IP; + } else { + ResourceRateLimitConfig appConfig = resourceRateLimitConfigService.getResourceRateLimitConfig(ResourceRateLimitConfig.APP_DEFAULT_RESOURCE); + if (appConfig != null && appConfig.isEnable()) { + type = ResourceRateLimitConfig.Type.APP_DEFAULT; + } else { + type = ResourceRateLimitConfig.Type.APP; + } + } + } else { + if (pi == null) { + type = ResourceRateLimitConfig.Type.SERVICE_DEFAULT; + } else { + type = ResourceRateLimitConfig.Type.IP; + } } } } else { diff --git a/fizz-core/src/main/java/we/filter/FlowControlFilter.java b/fizz-core/src/main/java/we/filter/FlowControlFilter.java index c2091c0..6cecf7a 100644 --- a/fizz-core/src/main/java/we/filter/FlowControlFilter.java +++ b/fizz-core/src/main/java/we/filter/FlowControlFilter.java @@ -203,6 +203,7 @@ public class FlowControlFilter extends FizzWebFilter { ResourceConfig rc = null; ResourceRateLimitConfig rateLimitConfig = resourceRateLimitConfigService.getResourceRateLimitConfig(resource); if (rateLimitConfig != null && rateLimitConfig.isEnable()) { + something4appAndIp(resourceConfigs, rateLimitConfig); rc = new ResourceConfig(resource, rateLimitConfig.concurrents, rateLimitConfig.qps); resourceConfigs.add(rc); } else { @@ -231,4 +232,53 @@ public class FlowControlFilter extends FizzWebFilter { } } } + + private void something4appAndIp(List resourceConfigs, ResourceRateLimitConfig rateLimitConfig) { + int sz = resourceConfigs.size(); + String prev = null, prevPrev = null; + if (sz > 1) { + prev = resourceConfigs.get(sz - 1).getResourceId(); + prevPrev = resourceConfigs.get(sz - 2).getResourceId(); + + if (rateLimitConfig.type == ResourceRateLimitConfig.Type.APP) { + String app = ResourceRateLimitConfig.getApp(prev); + if (app == null) { + something4(resourceConfigs, rateLimitConfig.app, null, null); + } else { + String service = ResourceRateLimitConfig.getService(prev); + if (service == null) { + } else { + app = ResourceRateLimitConfig.getApp(prevPrev); + if (app == null) { + something4(resourceConfigs, rateLimitConfig.app, null, null); + } + } + } + + } else if (rateLimitConfig.type == ResourceRateLimitConfig.Type.IP) { + + String ip = ResourceRateLimitConfig.getIp(prev); + if (ip == null) { + something4(resourceConfigs, null, rateLimitConfig.ip, null); + something4(resourceConfigs, null, rateLimitConfig.ip, rateLimitConfig.service); + } else { + String service = ResourceRateLimitConfig.getService(prev); + if (service == null) { + something4(resourceConfigs, null, rateLimitConfig.ip, rateLimitConfig.service); + } else { + ip = ResourceRateLimitConfig.getIp(prevPrev); + if (ip == null) { + something4(resourceConfigs, null, rateLimitConfig.ip, null); + } + } + } + } + } + } + + private void something4(List resourceConfigs, String app, String ip, String service) { + String r = ResourceRateLimitConfig.buildResourceId(app, ip, null, service, null); + ResourceConfig rc = new ResourceConfig(r, 0, 0); + resourceConfigs.add(rc); + } } diff --git a/fizz-plugin/pom.xml b/fizz-plugin/pom.xml index 865da1d..4749c02 100644 --- a/fizz-plugin/pom.xml +++ b/fizz-plugin/pom.xml @@ -5,7 +5,7 @@ fizz-gateway-community com.fizzgate - 2.2.0-beta2 + 2.2.0-beta3 ../pom.xml 4.0.0 diff --git a/fizz-spring-boot-starter/pom.xml b/fizz-spring-boot-starter/pom.xml index f2091be..de1eea1 100644 --- a/fizz-spring-boot-starter/pom.xml +++ b/fizz-spring-boot-starter/pom.xml @@ -5,7 +5,7 @@ fizz-gateway-community com.fizzgate - 2.2.0-beta2 + 2.2.0-beta3 ../pom.xml 4.0.0 diff --git a/pom.xml b/pom.xml index 95ceae9..5270cb8 100644 --- a/pom.xml +++ b/pom.xml @@ -31,7 +31,7 @@ fizz-gateway-community ${project.artifactId} fizz gateway community - 2.2.0-beta2 + 2.2.0-beta3 pom fizz-common From e69e10ac647cfdef20e1fc31614f509b0426da6a Mon Sep 17 00:00:00 2001 From: hongqiaowei Date: Fri, 25 Jun 2021 17:57:02 +0800 Subject: [PATCH 09/28] Release v2.2.0-beta4 --- fizz-bootstrap/pom.xml | 2 +- fizz-common/pom.xml | 2 +- fizz-core/pom.xml | 2 +- .../ResourceRateLimitConfigService.java | 38 +++++++++++++++---- fizz-plugin/pom.xml | 2 +- fizz-spring-boot-starter/pom.xml | 2 +- pom.xml | 2 +- 7 files changed, 36 insertions(+), 14 deletions(-) diff --git a/fizz-bootstrap/pom.xml b/fizz-bootstrap/pom.xml index 113dac1..1fdddd3 100644 --- a/fizz-bootstrap/pom.xml +++ b/fizz-bootstrap/pom.xml @@ -12,7 +12,7 @@ com.fizzgate fizz-bootstrap - 2.2.0-beta3 + 2.2.0-beta4 1.8 diff --git a/fizz-common/pom.xml b/fizz-common/pom.xml index c55038a..0f3b5cf 100644 --- a/fizz-common/pom.xml +++ b/fizz-common/pom.xml @@ -5,7 +5,7 @@ fizz-gateway-community com.fizzgate - 2.2.0-beta3 + 2.2.0-beta4 ../pom.xml 4.0.0 diff --git a/fizz-core/pom.xml b/fizz-core/pom.xml index 936b83d..8d6e0d9 100644 --- a/fizz-core/pom.xml +++ b/fizz-core/pom.xml @@ -5,7 +5,7 @@ fizz-gateway-community com.fizzgate - 2.2.0-beta3 + 2.2.0-beta4 ../pom.xml 4.0.0 diff --git a/fizz-core/src/main/java/we/stats/ratelimit/ResourceRateLimitConfigService.java b/fizz-core/src/main/java/we/stats/ratelimit/ResourceRateLimitConfigService.java index 6f046da..60203f9 100644 --- a/fizz-core/src/main/java/we/stats/ratelimit/ResourceRateLimitConfigService.java +++ b/fizz-core/src/main/java/we/stats/ratelimit/ResourceRateLimitConfigService.java @@ -181,13 +181,28 @@ public class ResourceRateLimitConfigService { return resourceRateLimitConfigMap; } + // _global, service, app, ip, ip+service public void getParentsTo(String resource, List parentList) { String app = null, ip = null, node = null, service = null, path = null; ResourceRateLimitConfig c = resourceRateLimitConfigMap.get(resource); if (c == null) { - service = ResourceRateLimitConfig.getService(resource); - if (service != null) { - parentList.add(ResourceRateLimitConfig.NODE_RESOURCE); + node = ResourceRateLimitConfig.getNode(resource); + if (node != null && node.equals(ResourceRateLimitConfig.NODE)) { + } else { + service = ResourceRateLimitConfig.getService(resource); + app = ResourceRateLimitConfig.getApp(resource); + ip = ResourceRateLimitConfig.getIp(resource); + if (service == null) { + parentList.add(ResourceRateLimitConfig.NODE_RESOURCE); + } else { + if (ip == null) { + parentList.add(ResourceRateLimitConfig.NODE_RESOURCE); + } else { + String r = ResourceRateLimitConfig.buildResourceId(null, ip, null, null, null); + parentList.add(r); + parentList.add(ResourceRateLimitConfig.NODE_RESOURCE); + } + } } return; } else { @@ -211,7 +226,8 @@ public class ResourceRateLimitConfigService { ResourceRateLimitConfig.buildResourceIdTo(b, app, null, null, service, null); checkRateLimitConfigAndAddTo(b, parentList); ResourceRateLimitConfig.buildResourceIdTo(b, app, null, null, null, null); - checkRateLimitConfigAndAddTo(b, parentList); + // checkRateLimitConfigAndAddTo(b, parentList); + to(parentList, b); } else if (service != null) { ResourceRateLimitConfig.buildResourceIdTo(b, app, null, null, null, null); checkRateLimitConfigAndAddTo(b, parentList); @@ -221,9 +237,11 @@ public class ResourceRateLimitConfigService { if (ip != null) { if (path != null) { ResourceRateLimitConfig.buildResourceIdTo(b, null, ip, null, service, null); - checkRateLimitConfigAndAddTo(b, parentList); + // checkRateLimitConfigAndAddTo(b, parentList); + to(parentList, b); ResourceRateLimitConfig.buildResourceIdTo(b, null, ip, null, null, null); - checkRateLimitConfigAndAddTo(b, parentList); + // checkRateLimitConfigAndAddTo(b, parentList); + to(parentList, b); } else if (service != null) { ResourceRateLimitConfig.buildResourceIdTo(b, null, ip, null, null, null); checkRateLimitConfigAndAddTo(b, parentList); @@ -232,13 +250,17 @@ public class ResourceRateLimitConfigService { if (path != null) { ResourceRateLimitConfig.buildResourceIdTo(b, null, null, null, service, null); - parentList.add(b.toString()); - b.delete(0, b.length()); + to(parentList, b); } parentList.add(ResourceRateLimitConfig.NODE_RESOURCE); } + private void to(List parentList, StringBuilder b) { + parentList.add(b.toString()); + b.delete(0, b.length()); + } + private void checkRateLimitConfigAndAddTo(StringBuilder resourceStringBuilder, List resourceList) { String r = resourceStringBuilder.toString(); ResourceRateLimitConfig c = resourceRateLimitConfigMap.get(r); diff --git a/fizz-plugin/pom.xml b/fizz-plugin/pom.xml index 4749c02..6ee10a4 100644 --- a/fizz-plugin/pom.xml +++ b/fizz-plugin/pom.xml @@ -5,7 +5,7 @@ fizz-gateway-community com.fizzgate - 2.2.0-beta3 + 2.2.0-beta4 ../pom.xml 4.0.0 diff --git a/fizz-spring-boot-starter/pom.xml b/fizz-spring-boot-starter/pom.xml index de1eea1..3045428 100644 --- a/fizz-spring-boot-starter/pom.xml +++ b/fizz-spring-boot-starter/pom.xml @@ -5,7 +5,7 @@ fizz-gateway-community com.fizzgate - 2.2.0-beta3 + 2.2.0-beta4 ../pom.xml 4.0.0 diff --git a/pom.xml b/pom.xml index 5270cb8..8f2926e 100644 --- a/pom.xml +++ b/pom.xml @@ -31,7 +31,7 @@ fizz-gateway-community ${project.artifactId} fizz gateway community - 2.2.0-beta3 + 2.2.0-beta4 pom fizz-common From 384d3efb0d0901983b291e05948eaa0587e80787 Mon Sep 17 00:00:00 2001 From: Francis Dong Date: Mon, 28 Jun 2021 09:36:03 +0800 Subject: [PATCH 10/28] update log default config --- fizz-bootstrap/sh/boot.sh | 2 +- fizz-bootstrap/src/main/resources/log4j2-spring.xml | 3 ++- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/fizz-bootstrap/sh/boot.sh b/fizz-bootstrap/sh/boot.sh index 54e3f71..d719d17 100644 --- a/fizz-bootstrap/sh/boot.sh +++ b/fizz-bootstrap/sh/boot.sh @@ -103,7 +103,7 @@ start() { else echo "starting $APP_NAME ..." rm -f ${PID_FILE} - ${JAVA_CMD} -jar ${JAVA_OPTS} -Dspring.profiles.active=$SPRING_PROFILES_ACTIVE -Denv=$APOLLO_ENV -Dapollo.meta=${APOLLO_META_SERVER} ${APP_DEP_DIR}/${APP_NAME} > ${APP_LOG_DIR}/${APP_NAME}.log 2>&1 & + ${JAVA_CMD} -jar ${JAVA_OPTS} -Dlogging.config=${APP_DEP_DIR}/log4j2-spring.xml -Dspring.profiles.active=$SPRING_PROFILES_ACTIVE -Denv=$APOLLO_ENV -Dapollo.meta=${APOLLO_META_SERVER} ${APP_DEP_DIR}/${APP_NAME} > ${APP_LOG_DIR}/${APP_NAME}.log 2>&1 & echo $! > ${PID_FILE} fi } diff --git a/fizz-bootstrap/src/main/resources/log4j2-spring.xml b/fizz-bootstrap/src/main/resources/log4j2-spring.xml index b5358b9..8429c18 100644 --- a/fizz-bootstrap/src/main/resources/log4j2-spring.xml +++ b/fizz-bootstrap/src/main/resources/log4j2-spring.xml @@ -19,6 +19,7 @@ - + + From 1e1b023ed5862182b1b75a1768d5fd0b27517e67 Mon Sep 17 00:00:00 2001 From: hongqiaowei Date: Mon, 28 Jun 2021 17:01:56 +0800 Subject: [PATCH 11/28] Release v2.2.0-beta5 --- fizz-bootstrap/pom.xml | 2 +- fizz-common/pom.xml | 2 +- .../src/main/java/we/util/Constants.java | 1 + fizz-core/pom.xml | 2 +- .../java/we/filter/FlowControlFilter.java | 6 ++-- .../ratelimit/ResourceRateLimitConfig.java | 33 +++++++++++-------- .../ResourceRateLimitConfigServiceTests.java | 2 +- .../ResourceRateLimitConfigTests.java | 10 +++--- fizz-plugin/pom.xml | 2 +- fizz-spring-boot-starter/pom.xml | 2 +- pom.xml | 2 +- 11 files changed, 36 insertions(+), 28 deletions(-) diff --git a/fizz-bootstrap/pom.xml b/fizz-bootstrap/pom.xml index 1fdddd3..8cc05e1 100644 --- a/fizz-bootstrap/pom.xml +++ b/fizz-bootstrap/pom.xml @@ -12,7 +12,7 @@ com.fizzgate fizz-bootstrap - 2.2.0-beta4 + 2.2.0-beta5 1.8 diff --git a/fizz-common/pom.xml b/fizz-common/pom.xml index 0f3b5cf..cba3f59 100644 --- a/fizz-common/pom.xml +++ b/fizz-common/pom.xml @@ -5,7 +5,7 @@ fizz-gateway-community com.fizzgate - 2.2.0-beta4 + 2.2.0-beta5 ../pom.xml 4.0.0 diff --git a/fizz-common/src/main/java/we/util/Constants.java b/fizz-common/src/main/java/we/util/Constants.java index eba2a52..398e358 100644 --- a/fizz-common/src/main/java/we/util/Constants.java +++ b/fizz-common/src/main/java/we/util/Constants.java @@ -52,6 +52,7 @@ public final class Constants { public static final char RIGHT_SQUARE_BRACKET = ']'; public static final char LEFT_BRACE = '{'; public static final char RIGHT_BRACE = '}'; + public static final char SQUARE = '^'; public static final char LF = '\n'; public static final char TAB = '\t'; diff --git a/fizz-core/pom.xml b/fizz-core/pom.xml index 8d6e0d9..58fc7a7 100644 --- a/fizz-core/pom.xml +++ b/fizz-core/pom.xml @@ -5,7 +5,7 @@ fizz-gateway-community com.fizzgate - 2.2.0-beta4 + 2.2.0-beta5 ../pom.xml 4.0.0 diff --git a/fizz-core/src/main/java/we/filter/FlowControlFilter.java b/fizz-core/src/main/java/we/filter/FlowControlFilter.java index 6cecf7a..90481e1 100644 --- a/fizz-core/src/main/java/we/filter/FlowControlFilter.java +++ b/fizz-core/src/main/java/we/filter/FlowControlFilter.java @@ -165,7 +165,7 @@ public class FlowControlFilter extends FizzWebFilter { private List getFlowControlConfigs(String app, String ip, String node, String service, String path) { if (log.isDebugEnabled()) { - log.debug("get flow control config by app={}, ip={}, node={}, service={}, path={}", app, ip, node, service, path); + log.debug("get flow control configs by app={}, ip={}, node={}, service={}, path={}", app, ip, node, service, path); } List resourceConfigs = new ArrayList<>(9); StringBuilder b = ThreadContext.getStringBuilder(); @@ -240,7 +240,7 @@ public class FlowControlFilter extends FizzWebFilter { prev = resourceConfigs.get(sz - 1).getResourceId(); prevPrev = resourceConfigs.get(sz - 2).getResourceId(); - if (rateLimitConfig.type == ResourceRateLimitConfig.Type.APP) { + if (rateLimitConfig.type == ResourceRateLimitConfig.Type.APP && rateLimitConfig.path != null) { String app = ResourceRateLimitConfig.getApp(prev); if (app == null) { something4(resourceConfigs, rateLimitConfig.app, null, null); @@ -255,7 +255,7 @@ public class FlowControlFilter extends FizzWebFilter { } } - } else if (rateLimitConfig.type == ResourceRateLimitConfig.Type.IP) { + } else if (rateLimitConfig.type == ResourceRateLimitConfig.Type.IP && rateLimitConfig.path != null) { String ip = ResourceRateLimitConfig.getIp(prev); if (ip == null) { diff --git a/fizz-core/src/main/java/we/stats/ratelimit/ResourceRateLimitConfig.java b/fizz-core/src/main/java/we/stats/ratelimit/ResourceRateLimitConfig.java index 58a499c..039b6e2 100644 --- a/fizz-core/src/main/java/we/stats/ratelimit/ResourceRateLimitConfig.java +++ b/fizz-core/src/main/java/we/stats/ratelimit/ResourceRateLimitConfig.java @@ -18,6 +18,7 @@ package we.stats.ratelimit; import com.fasterxml.jackson.annotation.JsonIgnore; +import org.apache.commons.lang3.StringUtils; import we.util.Constants; import we.util.JacksonUtils; import we.util.Utils; @@ -114,16 +115,22 @@ public class ResourceRateLimitConfig { } } + public void setPath(String p) { + if (StringUtils.isNotBlank(p)) { + path = p; + } + } + private String resourceId = null; @JsonIgnore public String getResourceId() { if (resourceId == null) { resourceId = - (app == null ? "" : app) + '@' + - (ip == null ? "" : ip) + '@' + - (node == null ? "" : node) + '@' + - (service == null ? "" : service) + '@' + + (app == null ? "" : app) + '^' + + (ip == null ? "" : ip) + '^' + + (node == null ? "" : node) + '^' + + (service == null ? "" : service) + '^' + (path == null ? "" : path) ; } @@ -137,15 +144,15 @@ public class ResourceRateLimitConfig { } public static void buildResourceIdTo(StringBuilder b, String app, String ip, String node, String service, String path) { - b.append(app == null ? Constants.Symbol.EMPTY : app) .append(Constants.Symbol.AT); - b.append(ip == null ? Constants.Symbol.EMPTY : ip) .append(Constants.Symbol.AT); - b.append(node == null ? Constants.Symbol.EMPTY : node) .append(Constants.Symbol.AT); - b.append(service == null ? Constants.Symbol.EMPTY : service) .append(Constants.Symbol.AT); + b.append(app == null ? Constants.Symbol.EMPTY : app) .append(Constants.Symbol.SQUARE); + b.append(ip == null ? Constants.Symbol.EMPTY : ip) .append(Constants.Symbol.SQUARE); + b.append(node == null ? Constants.Symbol.EMPTY : node) .append(Constants.Symbol.SQUARE); + b.append(service == null ? Constants.Symbol.EMPTY : service) .append(Constants.Symbol.SQUARE); b.append(path == null ? Constants.Symbol.EMPTY : path); } public static String getApp(String resource) { - int i = resource.indexOf(Constants.Symbol.AT); + int i = resource.indexOf(Constants.Symbol.SQUARE); if (i == 0) { return null; } else { @@ -154,7 +161,7 @@ public class ResourceRateLimitConfig { } public static String getIp(String resource) { - String extract = Utils.extract(resource, Constants.Symbol.AT, 1); + String extract = Utils.extract(resource, Constants.Symbol.SQUARE, 1); if (extract.equals(Constants.Symbol.EMPTY)) { return null; } @@ -162,7 +169,7 @@ public class ResourceRateLimitConfig { } public static String getNode(String resource) { - String extract = Utils.extract(resource, Constants.Symbol.AT, 2); + String extract = Utils.extract(resource, Constants.Symbol.SQUARE, 2); if (extract.equals(Constants.Symbol.EMPTY)) { return null; } @@ -170,7 +177,7 @@ public class ResourceRateLimitConfig { } public static String getService(String resource) { - String extract = Utils.extract(resource, Constants.Symbol.AT, 3); + String extract = Utils.extract(resource, Constants.Symbol.SQUARE, 3); if (extract.equals(Constants.Symbol.EMPTY)) { return null; } @@ -178,7 +185,7 @@ public class ResourceRateLimitConfig { } public static String getPath(String resource) { - int i = resource.lastIndexOf(Constants.Symbol.AT); + int i = resource.lastIndexOf(Constants.Symbol.SQUARE); if (i == resource.length() - 1) { return null; } else { diff --git a/fizz-core/src/test/java/we/stats/ratelimit/ResourceRateLimitConfigServiceTests.java b/fizz-core/src/test/java/we/stats/ratelimit/ResourceRateLimitConfigServiceTests.java index 8c2bce0..ae758bd 100644 --- a/fizz-core/src/test/java/we/stats/ratelimit/ResourceRateLimitConfigServiceTests.java +++ b/fizz-core/src/test/java/we/stats/ratelimit/ResourceRateLimitConfigServiceTests.java @@ -57,7 +57,7 @@ public class ResourceRateLimitConfigServiceTests { assertEquals(resourceRateLimitConfig.concurrents, 66); // System.err.println(resourceRateLimitConfig); // Thread.currentThread().join(); - resourceRateLimitConfig = resourceRateLimitConfigService.getResourceRateLimitConfig("xapp@@@yservice@"); + resourceRateLimitConfig = resourceRateLimitConfigService.getResourceRateLimitConfig("xapp^^^yservice^"); assertEquals(resourceRateLimitConfig.concurrents, 88); Thread.sleep(4000); diff --git a/fizz-core/src/test/java/we/stats/ratelimit/ResourceRateLimitConfigTests.java b/fizz-core/src/test/java/we/stats/ratelimit/ResourceRateLimitConfigTests.java index 80aaac2..2a2fab0 100644 --- a/fizz-core/src/test/java/we/stats/ratelimit/ResourceRateLimitConfigTests.java +++ b/fizz-core/src/test/java/we/stats/ratelimit/ResourceRateLimitConfigTests.java @@ -23,7 +23,7 @@ public class ResourceRateLimitConfigTests { String resourceRateLimitConfigJson = "{\"concurrents\":1000,\"enable\":1,\"id\":1,\"isDeleted\":0,\"qps\":500, \"type\":1, \"resource\":\"_global\" }"; ResourceRateLimitConfig c = JacksonUtils.readValue(resourceRateLimitConfigJson, ResourceRateLimitConfig.class); String resourceId = c.getResourceId(); - assertEquals("@@_global@@", resourceId); + assertEquals("^^_global^^", resourceId); String node = ResourceRateLimitConfig.getNode(resourceId); assertEquals("_global", node); @@ -31,17 +31,17 @@ public class ResourceRateLimitConfigTests { resourceRateLimitConfigJson = "{\"concurrents\":1000,\"enable\":1,\"id\":1,\"isDeleted\":0,\"qps\":500, \"type\":2, \"resource\":\"service_default\" }"; c = JacksonUtils.readValue(resourceRateLimitConfigJson, ResourceRateLimitConfig.class); resourceId = c.getResourceId(); - assertEquals("@@@service_default@", resourceId); + assertEquals("^^^service_default^", resourceId); resourceRateLimitConfigJson = "{\"concurrents\":1000,\"enable\":1,\"id\":1,\"isDeleted\":0,\"qps\":500, \"type\":3, \"resource\":\"xservice\" }"; c = JacksonUtils.readValue(resourceRateLimitConfigJson, ResourceRateLimitConfig.class); resourceId = c.getResourceId(); - assertEquals("@@@xservice@", resourceId); + assertEquals("^^^xservice^", resourceId); resourceId = ResourceRateLimitConfig.buildResourceId(null, null, ResourceRateLimitConfig.NODE, null, null); - assertEquals("@@_global@@", resourceId); + assertEquals("^^_global^^", resourceId); resourceId = ResourceRateLimitConfig.buildResourceId(null, "192.168.1.1", null, "xservice", null); - assertEquals("@192.168.1.1@@xservice@", resourceId); + assertEquals("^192.168.1.1^^xservice^", resourceId); } } diff --git a/fizz-plugin/pom.xml b/fizz-plugin/pom.xml index 6ee10a4..8591649 100644 --- a/fizz-plugin/pom.xml +++ b/fizz-plugin/pom.xml @@ -5,7 +5,7 @@ fizz-gateway-community com.fizzgate - 2.2.0-beta4 + 2.2.0-beta5 ../pom.xml 4.0.0 diff --git a/fizz-spring-boot-starter/pom.xml b/fizz-spring-boot-starter/pom.xml index 3045428..f9860b0 100644 --- a/fizz-spring-boot-starter/pom.xml +++ b/fizz-spring-boot-starter/pom.xml @@ -5,7 +5,7 @@ fizz-gateway-community com.fizzgate - 2.2.0-beta4 + 2.2.0-beta5 ../pom.xml 4.0.0 diff --git a/pom.xml b/pom.xml index 8f2926e..10f503a 100644 --- a/pom.xml +++ b/pom.xml @@ -31,7 +31,7 @@ fizz-gateway-community ${project.artifactId} fizz gateway community - 2.2.0-beta4 + 2.2.0-beta5 pom fizz-common From 24bb6cbf0043416087ebbe5c8656eaf67ce54360 Mon Sep 17 00:00:00 2001 From: linwaiwai Date: Tue, 29 Jun 2021 11:28:08 +0800 Subject: [PATCH 12/28] Update README.md --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 42b1ef4..a9a8863 100644 --- a/README.md +++ b/README.md @@ -120,7 +120,7 @@ API地址:http://demo.fizzgate.com/proxy/[服务名]/[API_Path] #### 一、安装管理后台 -从github的releases(https://github.com/wehotel/fizz-gateway-community/releases) 下载 fizz-manager-professional 安装包 +从github的releases(https://wj.qq.com/s2/8682608/8fe2/) 下载 fizz-manager-professional 安装包 ##### 管理后台(fizz-manager-professional) From 82e6fe63adc54eaa1843ff2c62367161fce36de8 Mon Sep 17 00:00:00 2001 From: hongqiaowei Date: Wed, 30 Jun 2021 14:47:33 +0800 Subject: [PATCH 13/28] Release v2.2.0-beta6 --- fizz-bootstrap/pom.xml | 2 +- fizz-common/pom.xml | 2 +- fizz-core/pom.xml | 2 +- .../java/we/config/FlowStatSchedConfig.java | 3 +- .../java/we/filter/FlowControlFilter.java | 36 +++++++++++-------- .../ratelimit/ResourceRateLimitConfig.java | 14 ++++++-- fizz-plugin/pom.xml | 2 +- fizz-spring-boot-starter/pom.xml | 2 +- pom.xml | 2 +- 9 files changed, 41 insertions(+), 24 deletions(-) diff --git a/fizz-bootstrap/pom.xml b/fizz-bootstrap/pom.xml index 8cc05e1..628a4c9 100644 --- a/fizz-bootstrap/pom.xml +++ b/fizz-bootstrap/pom.xml @@ -12,7 +12,7 @@ com.fizzgate fizz-bootstrap - 2.2.0-beta5 + 2.2.0-beta6 1.8 diff --git a/fizz-common/pom.xml b/fizz-common/pom.xml index cba3f59..71294c2 100644 --- a/fizz-common/pom.xml +++ b/fizz-common/pom.xml @@ -5,7 +5,7 @@ fizz-gateway-community com.fizzgate - 2.2.0-beta5 + 2.2.0-beta6 ../pom.xml 4.0.0 diff --git a/fizz-core/pom.xml b/fizz-core/pom.xml index 58fc7a7..317819f 100644 --- a/fizz-core/pom.xml +++ b/fizz-core/pom.xml @@ -5,7 +5,7 @@ fizz-gateway-community com.fizzgate - 2.2.0-beta5 + 2.2.0-beta6 ../pom.xml 4.0.0 diff --git a/fizz-core/src/main/java/we/config/FlowStatSchedConfig.java b/fizz-core/src/main/java/we/config/FlowStatSchedConfig.java index ec820bc..cf8f6c4 100644 --- a/fizz-core/src/main/java/we/config/FlowStatSchedConfig.java +++ b/fizz-core/src/main/java/we/config/FlowStatSchedConfig.java @@ -240,7 +240,8 @@ public class FlowStatSchedConfig extends SchedConfig { rt.convertAndSend(flowStatSchedConfigProperties.getQueue(), msg).subscribe(); } if (log.isDebugEnabled()) { - log.debug("report " + toDP19(timeWin) + " win10: " + msg); + String wt = 'w' + toDP19(timeWin); + log.debug("report " + wt + ": " + msg, LogService.BIZ_ID, wt); } } } diff --git a/fizz-core/src/main/java/we/filter/FlowControlFilter.java b/fizz-core/src/main/java/we/filter/FlowControlFilter.java index 90481e1..fcda08f 100644 --- a/fizz-core/src/main/java/we/filter/FlowControlFilter.java +++ b/fizz-core/src/main/java/we/filter/FlowControlFilter.java @@ -255,23 +255,31 @@ public class FlowControlFilter extends FizzWebFilter { } } - } else if (rateLimitConfig.type == ResourceRateLimitConfig.Type.IP && rateLimitConfig.path != null) { + } else if (rateLimitConfig.type == ResourceRateLimitConfig.Type.IP) { - String ip = ResourceRateLimitConfig.getIp(prev); - if (ip == null) { - something4(resourceConfigs, null, rateLimitConfig.ip, null); - something4(resourceConfigs, null, rateLimitConfig.ip, rateLimitConfig.service); - } else { - String service = ResourceRateLimitConfig.getService(prev); - if (service == null) { - something4(resourceConfigs, null, rateLimitConfig.ip, rateLimitConfig.service); + if (rateLimitConfig.service == null && rateLimitConfig.path == null) { + } else if (rateLimitConfig.path == null) { + String ip = ResourceRateLimitConfig.getIp(prev); + if (ip == null) { + something4(resourceConfigs, null, rateLimitConfig.ip, null); + } } else { - ip = ResourceRateLimitConfig.getIp(prevPrev); - if (ip == null) { - something4(resourceConfigs, null, rateLimitConfig.ip, null); - } + String ip = ResourceRateLimitConfig.getIp(prev); + if (ip == null) { + something4(resourceConfigs, null, rateLimitConfig.ip, null); + something4(resourceConfigs, null, rateLimitConfig.ip, rateLimitConfig.service); + } else { + String service = ResourceRateLimitConfig.getService(prev); + if (service == null) { + something4(resourceConfigs, null, rateLimitConfig.ip, rateLimitConfig.service); + } else { + ip = ResourceRateLimitConfig.getIp(prevPrev); + if (ip == null) { + something4(resourceConfigs, null, rateLimitConfig.ip, null); + } + } + } } - } } } } diff --git a/fizz-core/src/main/java/we/stats/ratelimit/ResourceRateLimitConfig.java b/fizz-core/src/main/java/we/stats/ratelimit/ResourceRateLimitConfig.java index 039b6e2..464f065 100644 --- a/fizz-core/src/main/java/we/stats/ratelimit/ResourceRateLimitConfig.java +++ b/fizz-core/src/main/java/we/stats/ratelimit/ResourceRateLimitConfig.java @@ -98,9 +98,11 @@ public class ResourceRateLimitConfig { } public void setResource(String r) { - resource = r; - if (!resource.equals(NODE)) { - service = resource; + if (StringUtils.isNotBlank(r)) { + resource = r; + if (!resource.equals(NODE)) { + service = resource; + } } } @@ -115,6 +117,12 @@ public class ResourceRateLimitConfig { } } + public void setService(String s) { + if (StringUtils.isNotBlank(s)) { + service = s; + } + } + public void setPath(String p) { if (StringUtils.isNotBlank(p)) { path = p; diff --git a/fizz-plugin/pom.xml b/fizz-plugin/pom.xml index 8591649..6079cba 100644 --- a/fizz-plugin/pom.xml +++ b/fizz-plugin/pom.xml @@ -5,7 +5,7 @@ fizz-gateway-community com.fizzgate - 2.2.0-beta5 + 2.2.0-beta6 ../pom.xml 4.0.0 diff --git a/fizz-spring-boot-starter/pom.xml b/fizz-spring-boot-starter/pom.xml index f9860b0..37a19b0 100644 --- a/fizz-spring-boot-starter/pom.xml +++ b/fizz-spring-boot-starter/pom.xml @@ -5,7 +5,7 @@ fizz-gateway-community com.fizzgate - 2.2.0-beta5 + 2.2.0-beta6 ../pom.xml 4.0.0 diff --git a/pom.xml b/pom.xml index 10f503a..7f8c28b 100644 --- a/pom.xml +++ b/pom.xml @@ -31,7 +31,7 @@ fizz-gateway-community ${project.artifactId} fizz gateway community - 2.2.0-beta5 + 2.2.0-beta6 pom fizz-common From 20e91b18c53c5f4192b97a2871dfee9785c06e7b Mon Sep 17 00:00:00 2001 From: Francis Dong Date: Mon, 5 Jul 2021 17:02:27 +0800 Subject: [PATCH 14/28] support total block requests --- .../src/main/java/we/stats/FlowStat.java | 36 +++++++++++++++++++ .../src/main/java/we/stats/ResourceStat.java | 11 ++++++ .../src/main/java/we/stats/TimeSlot.java | 13 +++++++ .../main/java/we/stats/TimeWindowStat.java | 13 +++++++ 4 files changed, 73 insertions(+) diff --git a/fizz-core/src/main/java/we/stats/FlowStat.java b/fizz-core/src/main/java/we/stats/FlowStat.java index 417fcf8..6ad7bcb 100644 --- a/fizz-core/src/main/java/we/stats/FlowStat.java +++ b/fizz-core/src/main/java/we/stats/FlowStat.java @@ -28,6 +28,7 @@ import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; import java.util.concurrent.locks.Lock; import java.util.concurrent.locks.ReentrantReadWriteLock; +import java.util.function.BiFunction; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -110,6 +111,21 @@ public class FlowStat { * @return IncrRequestResult */ public IncrRequestResult incrRequest(List resourceConfigs, long curTimeSlotId) { + return incrRequest(resourceConfigs, curTimeSlotId, null); + } + + /** + * Increase concurrent request counter for given resources chain + * + * @param resourceConfigs Resource configurations + * @param curTimeSlotId current time slot ID, it should be generated by + * Flowstat.currentTimeSlotId() + * @param totalBlockFunc [optional] callback function for statistic of total + * block requests of the resource and its parent resources + * @return IncrRequestResult + */ + public IncrRequestResult incrRequest(List resourceConfigs, long curTimeSlotId, + BiFunction, List> totalBlockFunc) { if (resourceConfigs == null || resourceConfigs.size() == 0) { return null; } @@ -126,6 +142,16 @@ public class FlowStat { long n = resourceStat.getConcurrentRequests().get(); if (n >= maxCon) { resourceStat.incrBlockRequestToTimeSlot(curTimeSlotId); + if (totalBlockFunc != null) { + List parentResCfgs = totalBlockFunc.apply(resourceConfig, + resourceConfigs); + if (parentResCfgs != null && parentResCfgs.size() > 0) { + for (ResourceConfig pResCfg : parentResCfgs) { + getResourceStat(pResCfg.getResourceId()) + .incrTotalBlockRequestToTimeSlot(curTimeSlotId); + } + } + } return IncrRequestResult.block(resourceConfig.getResourceId(), BlockType.CONCURRENT_REQUEST); } @@ -136,6 +162,16 @@ public class FlowStat { long total = resourceStat.getTimeSlot(curTimeSlotId).getCounter().get(); if (total >= maxQPS) { resourceStat.incrBlockRequestToTimeSlot(curTimeSlotId); + if (totalBlockFunc != null) { + List parentResCfgs = totalBlockFunc.apply(resourceConfig, + resourceConfigs); + if (parentResCfgs != null && parentResCfgs.size() > 0) { + for (ResourceConfig pResCfg : parentResCfgs) { + getResourceStat(pResCfg.getResourceId()) + .incrTotalBlockRequestToTimeSlot(curTimeSlotId); + } + } + } return IncrRequestResult.block(resourceConfig.getResourceId(), BlockType.QPS); } } diff --git a/fizz-core/src/main/java/we/stats/ResourceStat.java b/fizz-core/src/main/java/we/stats/ResourceStat.java index d8a23e6..92b3652 100644 --- a/fizz-core/src/main/java/we/stats/ResourceStat.java +++ b/fizz-core/src/main/java/we/stats/ResourceStat.java @@ -128,6 +128,14 @@ public class ResourceStat { public void incrBlockRequestToTimeSlot(long timeSlotId) { this.getTimeSlot(timeSlotId).getBlockRequests().incrementAndGet(); } + + /** + * Increase total block request to the specified time slot + * + */ + public void incrTotalBlockRequestToTimeSlot(long timeSlotId) { + this.getTimeSlot(timeSlotId).getTotalBlockRequests().incrementAndGet(); + } /** * Add request to the specified time slot @@ -197,6 +205,7 @@ public class ResourceStat { long peakConcurrences = 0; long errors = 0; long blockReqs = 0; + long totalBlockReqs = 0; long compReqs = 0; for (long i = startSlotId; i < endSlotId;) { if (timeSlots.containsKey(i)) { @@ -210,6 +219,7 @@ public class ResourceStat { totalRt = totalRt + timeSlot.getTotalRt().get(); errors = errors + timeSlot.getErrors().get(); blockReqs = blockReqs + timeSlot.getBlockRequests().get(); + totalBlockReqs = totalBlockReqs + timeSlot.getTotalBlockRequests().get(); compReqs = compReqs + timeSlot.getCompReqs().get(); } i = i + FlowStat.INTERVAL; @@ -220,6 +230,7 @@ public class ResourceStat { tws.setTotal(totalReqs); tws.setErrors(errors); tws.setBlockRequests(blockReqs); + tws.setTotalBlockRequests(totalBlockReqs); tws.setCompReqs(compReqs); if (compReqs > 0) { diff --git a/fizz-core/src/main/java/we/stats/TimeSlot.java b/fizz-core/src/main/java/we/stats/TimeSlot.java index 13743cb..765eed4 100644 --- a/fizz-core/src/main/java/we/stats/TimeSlot.java +++ b/fizz-core/src/main/java/we/stats/TimeSlot.java @@ -70,6 +70,11 @@ public class TimeSlot { * Block requests
*/ private AtomicLong blockRequests = new AtomicLong(0); + + /** + * Total block requests of the resource and its underlying resources
+ */ + private AtomicLong totalBlockRequests = new AtomicLong(0); public TimeSlot(long id) { this.id = id; @@ -181,4 +186,12 @@ public class TimeSlot { this.compReqs = compReqs; } + public AtomicLong getTotalBlockRequests() { + return totalBlockRequests; + } + + public void setTotalBlockRequests(AtomicLong totalBlockRequests) { + this.totalBlockRequests = totalBlockRequests; + } + } diff --git a/fizz-core/src/main/java/we/stats/TimeWindowStat.java b/fizz-core/src/main/java/we/stats/TimeWindowStat.java index 796f4e2..2204208 100644 --- a/fizz-core/src/main/java/we/stats/TimeWindowStat.java +++ b/fizz-core/src/main/java/we/stats/TimeWindowStat.java @@ -79,6 +79,11 @@ public class TimeWindowStat { * Block requests */ private Long blockRequests; + + /** + * Total block requests + */ + private Long totalBlockRequests; public Long getBlockRequests() { return blockRequests; @@ -168,4 +173,12 @@ public class TimeWindowStat { this.compReqs = compReqs; } + public Long getTotalBlockRequests() { + return totalBlockRequests; + } + + public void setTotalBlockRequests(Long totalBlockRequests) { + this.totalBlockRequests = totalBlockRequests; + } + } From 1bb09f76d6bf1910b090b14aa56fd6488607f374 Mon Sep 17 00:00:00 2001 From: hongqiaowei Date: Tue, 6 Jul 2021 09:00:04 +0800 Subject: [PATCH 15/28] handle total block requests --- .../java/we/config/FlowStatSchedConfig.java | 73 +++++---- .../java/we/filter/FlowControlFilter.java | 49 +++++- .../ResourceRateLimitConfigService.java | 154 +++++++++--------- 3 files changed, 167 insertions(+), 109 deletions(-) diff --git a/fizz-core/src/main/java/we/config/FlowStatSchedConfig.java b/fizz-core/src/main/java/we/config/FlowStatSchedConfig.java index cf8f6c4..a4034af 100644 --- a/fizz-core/src/main/java/we/config/FlowStatSchedConfig.java +++ b/fizz-core/src/main/java/we/config/FlowStatSchedConfig.java @@ -92,7 +92,7 @@ public class FlowStatSchedConfig extends SchedConfig { private long startTimeSlot = 0; - private Map resourceTimeWindow2totalBlockRequestsMap = new HashMap<>(128); + // private Map resourceTimeWindow2totalBlockRequestsMap = new HashMap<>(128); @Scheduled(cron = "${flow-stat-sched.cron}") public void sched() { @@ -112,24 +112,24 @@ public class FlowStatSchedConfig extends SchedConfig { return; } - resourceTimeWindow2totalBlockRequestsMap.clear(); - resourceTimeWindowStats.forEach(rtws -> { - String resource = rtws.getResourceId(); - List wins = rtws.getWindows(); - wins.forEach(w -> { - long t = w.getStartTime(); - long blockRequests = w.getBlockRequests(); - resourceTimeWindow2totalBlockRequestsMap.put(resource + t, new AtomicLong(blockRequests)); - }); - }); + // resourceTimeWindow2totalBlockRequestsMap.clear(); + // resourceTimeWindowStats.forEach(rtws -> { + // String resource = rtws.getResourceId(); + // List wins = rtws.getWindows(); + // wins.forEach(w -> { + // long t = w.getStartTime(); + // long blockRequests = w.getBlockRequests(); + // resourceTimeWindow2totalBlockRequestsMap.put(resource + t, new AtomicLong(blockRequests)); + // }); + // }); - resourceTimeWindowStats.forEach(rtws -> { - String resource = rtws.getResourceId(); - List wins = rtws.getWindows(); - wins.forEach(w -> { - accumulateParents(resource, w.getStartTime(), w.getBlockRequests()); - }); - }); + // resourceTimeWindowStats.forEach(rtws -> { + // String resource = rtws.getResourceId(); + // List wins = rtws.getWindows(); + // wins.forEach(w -> { + // accumulateParents(resource, w.getStartTime(), w.getBlockRequests()); + // }); + // }); resourceTimeWindowStats.forEach( rtws -> { @@ -138,7 +138,7 @@ public class FlowStatSchedConfig extends SchedConfig { int type = ResourceRateLimitConfig.Type.NODE, id = 0; ResourceRateLimitConfig c = resourceRateLimitConfigService.getResourceRateLimitConfig(resource); - if (c == null) { // _global, service, app, ip, ip+service + if (c == null) { // _global, service, app, app+service, ip, ip+service node = ResourceRateLimitConfig.getNode(resource); if (node != null && node.equals(ResourceRateLimitConfig.NODE)) { } else { @@ -157,10 +157,14 @@ public class FlowStatSchedConfig extends SchedConfig { } } } else { - if (pi == null) { + if (app == null && pi == null) { type = ResourceRateLimitConfig.Type.SERVICE_DEFAULT; } else { - type = ResourceRateLimitConfig.Type.IP; + if (app == null) { + type = ResourceRateLimitConfig.Type.IP; + } else { + type = ResourceRateLimitConfig.Type.APP; + } } } } @@ -186,8 +190,9 @@ public class FlowStatSchedConfig extends SchedConfig { qps = rps.doubleValue(); } - AtomicLong totalBlockRequests = resourceTimeWindow2totalBlockRequestsMap.get(resource + timeWin); - long tbrs = (totalBlockRequests == null ? w.getBlockRequests() : totalBlockRequests.longValue()); + // AtomicLong totalBlockRequests = resourceTimeWindow2totalBlockRequestsMap.get(resource + timeWin); + // long tbrs = (totalBlockRequests == null ? w.getBlockRequests() : w.getBlockRequests() + totalBlockRequests.longValue()); + long tbrs = w.getTotalBlockRequests(); b.append(Constants.Symbol.LEFT_BRACE); b.append(_ip); toJsonStringValue(b, ip); b.append(Constants.Symbol.COMMA); @@ -253,17 +258,17 @@ public class FlowStatSchedConfig extends SchedConfig { } } - private void accumulateParents(String resource, long timeWin, long blockRequests) { - List prl = ThreadContext.getArrayList(parentResourceList, String.class); - resourceRateLimitConfigService.getParentsTo(resource, prl); - for (int i = 0; i < prl.size(); i++) { - String parentResource = prl.get(i); - AtomicLong parentTotalBlockRequests = resourceTimeWindow2totalBlockRequestsMap.get(parentResource + timeWin); - if (parentTotalBlockRequests != null) { - parentTotalBlockRequests.addAndGet(blockRequests); - } - } - } + // private void accumulateParents(String resource, long timeWin, long blockRequests) { + // List prl = ThreadContext.getArrayList(parentResourceList, String.class); + // resourceRateLimitConfigService.getParentsTo(resource, prl); + // for (int i = 0; i < prl.size(); i++) { + // String parentResource = prl.get(i); + // AtomicLong parentTotalBlockRequests = resourceTimeWindow2totalBlockRequestsMap.get(parentResource + timeWin); + // if (parentTotalBlockRequests != null) { + // parentTotalBlockRequests.addAndGet(blockRequests); + // } + // } + // } private long getRecentEndTimeSlot(FlowStat flowStat) { long currentTimeSlot = flowStat.currentTimeSlotId(); diff --git a/fizz-core/src/main/java/we/filter/FlowControlFilter.java b/fizz-core/src/main/java/we/filter/FlowControlFilter.java index fcda08f..af2001c 100644 --- a/fizz-core/src/main/java/we/filter/FlowControlFilter.java +++ b/fizz-core/src/main/java/we/filter/FlowControlFilter.java @@ -120,7 +120,9 @@ public class FlowControlFilter extends FizzWebFilter { long currentTimeSlot = flowStat.currentTimeSlotId(); List resourceConfigs = getFlowControlConfigs(app, ip, null, service, path); - IncrRequestResult result = flowStat.incrRequest(resourceConfigs, currentTimeSlot); + IncrRequestResult result = flowStat.incrRequest(resourceConfigs, currentTimeSlot, (rc, rcs) -> { + return getResourceConfigItselfAndParents(rc, rcs); + }); if (result != null && !result.isSuccess()) { String blockedResourceId = result.getBlockedResourceId(); @@ -163,6 +165,49 @@ public class FlowControlFilter extends FizzWebFilter { return chain.filter(exchange); } + private List getResourceConfigItselfAndParents(ResourceConfig rc, List rcs) { + boolean check = false; + String rcId = rc.getResourceId(); + String rcApp = ResourceRateLimitConfig.getApp(rcId); + String rcIp = ResourceRateLimitConfig.getIp(rcId); + List result = new ArrayList<>(); + for (int i = rcs.size() - 1; i > -1; i--) { + ResourceConfig r = rcs.get(i); + String id = r.getResourceId(); + String app = ResourceRateLimitConfig.getApp(id); + String ip = ResourceRateLimitConfig.getIp(id); + String path = ResourceRateLimitConfig.getPath(id); + if (check) { + if (rcIp != null) { + if (ip != null) { + result.add(r); + } else { + if (app == null && path == null) { + result.add(r); + } + } + } else if (rcApp != null) { + if (app != null) { + result.add(r); + } else { + if (path == null) { + result.add(r); + } + } + } else { + result.add(r); + } + } else if (id.equals(rcId)) { + result.add(r); + check = true; + } + } + if (log.isDebugEnabled()) { + log.debug("getResourceConfigItselfAndParents:\n" + JacksonUtils.writeValueAsString(rc) + '\n' + JacksonUtils.writeValueAsString(result)); + } + return result; + } + private List getFlowControlConfigs(String app, String ip, String node, String service, String path) { if (log.isDebugEnabled()) { log.debug("get flow control configs by app={}, ip={}, node={}, service={}, path={}", app, ip, node, service, path); @@ -244,9 +289,11 @@ public class FlowControlFilter extends FizzWebFilter { String app = ResourceRateLimitConfig.getApp(prev); if (app == null) { something4(resourceConfigs, rateLimitConfig.app, null, null); + something4(resourceConfigs, rateLimitConfig.app, null, rateLimitConfig.service); } else { String service = ResourceRateLimitConfig.getService(prev); if (service == null) { + something4(resourceConfigs, rateLimitConfig.app, null, rateLimitConfig.service); } else { app = ResourceRateLimitConfig.getApp(prevPrev); if (app == null) { diff --git a/fizz-core/src/main/java/we/stats/ratelimit/ResourceRateLimitConfigService.java b/fizz-core/src/main/java/we/stats/ratelimit/ResourceRateLimitConfigService.java index 60203f9..9cb0b08 100644 --- a/fizz-core/src/main/java/we/stats/ratelimit/ResourceRateLimitConfigService.java +++ b/fizz-core/src/main/java/we/stats/ratelimit/ResourceRateLimitConfigService.java @@ -181,80 +181,86 @@ public class ResourceRateLimitConfigService { return resourceRateLimitConfigMap; } - // _global, service, app, ip, ip+service - public void getParentsTo(String resource, List parentList) { - String app = null, ip = null, node = null, service = null, path = null; - ResourceRateLimitConfig c = resourceRateLimitConfigMap.get(resource); - if (c == null) { - node = ResourceRateLimitConfig.getNode(resource); - if (node != null && node.equals(ResourceRateLimitConfig.NODE)) { - } else { - service = ResourceRateLimitConfig.getService(resource); - app = ResourceRateLimitConfig.getApp(resource); - ip = ResourceRateLimitConfig.getIp(resource); - if (service == null) { - parentList.add(ResourceRateLimitConfig.NODE_RESOURCE); - } else { - if (ip == null) { - parentList.add(ResourceRateLimitConfig.NODE_RESOURCE); - } else { - String r = ResourceRateLimitConfig.buildResourceId(null, ip, null, null, null); - parentList.add(r); - parentList.add(ResourceRateLimitConfig.NODE_RESOURCE); - } - } - } - return; - } else { - if (c.type == ResourceRateLimitConfig.Type.NODE) { - return; - } - if (c.type == ResourceRateLimitConfig.Type.SERVICE) { - parentList.add(ResourceRateLimitConfig.NODE_RESOURCE); - return; - } - app = c.app; - ip = c.ip; - service = c.service; - path = c.path; - } - - StringBuilder b = ThreadContext.getStringBuilder(); - - if (app != null) { - if (path != null) { - ResourceRateLimitConfig.buildResourceIdTo(b, app, null, null, service, null); - checkRateLimitConfigAndAddTo(b, parentList); - ResourceRateLimitConfig.buildResourceIdTo(b, app, null, null, null, null); - // checkRateLimitConfigAndAddTo(b, parentList); - to(parentList, b); - } else if (service != null) { - ResourceRateLimitConfig.buildResourceIdTo(b, app, null, null, null, null); - checkRateLimitConfigAndAddTo(b, parentList); - } - } - - if (ip != null) { - if (path != null) { - ResourceRateLimitConfig.buildResourceIdTo(b, null, ip, null, service, null); - // checkRateLimitConfigAndAddTo(b, parentList); - to(parentList, b); - ResourceRateLimitConfig.buildResourceIdTo(b, null, ip, null, null, null); - // checkRateLimitConfigAndAddTo(b, parentList); - to(parentList, b); - } else if (service != null) { - ResourceRateLimitConfig.buildResourceIdTo(b, null, ip, null, null, null); - checkRateLimitConfigAndAddTo(b, parentList); - } - } - - if (path != null) { - ResourceRateLimitConfig.buildResourceIdTo(b, null, null, null, service, null); - to(parentList, b); - } - - parentList.add(ResourceRateLimitConfig.NODE_RESOURCE); - } + // _global, service, app, app+service, ip, ip+service + // public void getParentsTo(String resource, List parentList) { + // String app = null, ip = null, node = null, service = null, path = null; + // ResourceRateLimitConfig c = resourceRateLimitConfigMap.get(resource); + // if (c == null) { + // node = ResourceRateLimitConfig.getNode(resource); + // if (node != null && node.equals(ResourceRateLimitConfig.NODE)) { + // } else { + // service = ResourceRateLimitConfig.getService(resource); + // app = ResourceRateLimitConfig.getApp(resource); + // ip = ResourceRateLimitConfig.getIp(resource); + // if (service == null) { // or app ip + // parentList.add(ResourceRateLimitConfig.NODE_RESOURCE); + // } else { + // if (app == null && ip == null) { + // parentList.add(ResourceRateLimitConfig.NODE_RESOURCE); + // } else { + // String r = null; + // if (app == null) { + // r = ResourceRateLimitConfig.buildResourceId(null, ip, null, null, null); + // } else { + // r = ResourceRateLimitConfig.buildResourceId(app, null, null, null, null); + // } + // parentList.add(r); + // parentList.add( ResourceRateLimitConfig.buildResourceId(null, null, null, service, null) ); + // parentList.add(ResourceRateLimitConfig.NODE_RESOURCE); + // } + // } + // } + // return; + // } else { + // if (c.type == ResourceRateLimitConfig.Type.NODE) { + // return; + // } + // if (c.type == ResourceRateLimitConfig.Type.SERVICE) { + // parentList.add(ResourceRateLimitConfig.NODE_RESOURCE); + // return; + // } + // app = c.app; + // ip = c.ip; + // service = c.service; + // path = c.path; + // } + // + // StringBuilder b = ThreadContext.getStringBuilder(); + // + // if (app != null) { + // if (path != null) { + // ResourceRateLimitConfig.buildResourceIdTo(b, app, null, null, service, null); + // checkRateLimitConfigAndAddTo(b, parentList); + // ResourceRateLimitConfig.buildResourceIdTo(b, app, null, null, null, null); + // // checkRateLimitConfigAndAddTo(b, parentList); + // to(parentList, b); + // } else if (service != null) { + // ResourceRateLimitConfig.buildResourceIdTo(b, app, null, null, null, null); + // checkRateLimitConfigAndAddTo(b, parentList); + // } + // } + // + // if (ip != null) { + // if (path != null) { + // ResourceRateLimitConfig.buildResourceIdTo(b, null, ip, null, service, null); + // // checkRateLimitConfigAndAddTo(b, parentList); + // to(parentList, b); + // ResourceRateLimitConfig.buildResourceIdTo(b, null, ip, null, null, null); + // // checkRateLimitConfigAndAddTo(b, parentList); + // to(parentList, b); + // } else if (service != null) { + // ResourceRateLimitConfig.buildResourceIdTo(b, null, ip, null, null, null); + // checkRateLimitConfigAndAddTo(b, parentList); + // } + // } + // + // if (path != null) { + // ResourceRateLimitConfig.buildResourceIdTo(b, null, null, null, service, null); + // to(parentList, b); + // } + // + // parentList.add(ResourceRateLimitConfig.NODE_RESOURCE); + // } private void to(List parentList, StringBuilder b) { parentList.add(b.toString()); From a8a752feb9387f7aecbf313ca19bd8e238a35c95 Mon Sep 17 00:00:00 2001 From: hongqiaowei Date: Tue, 6 Jul 2021 17:24:20 +0800 Subject: [PATCH 16/28] Release 2.2.0-beta7 --- fizz-bootstrap/pom.xml | 2 +- fizz-common/pom.xml | 2 +- fizz-core/pom.xml | 2 +- .../java/we/filter/FlowControlFilter.java | 34 +++++++++++-------- fizz-plugin/pom.xml | 2 +- fizz-spring-boot-starter/pom.xml | 2 +- pom.xml | 2 +- 7 files changed, 26 insertions(+), 20 deletions(-) diff --git a/fizz-bootstrap/pom.xml b/fizz-bootstrap/pom.xml index 628a4c9..8b6a76e 100644 --- a/fizz-bootstrap/pom.xml +++ b/fizz-bootstrap/pom.xml @@ -12,7 +12,7 @@ com.fizzgate fizz-bootstrap - 2.2.0-beta6 + 2.2.0-beta7 1.8 diff --git a/fizz-common/pom.xml b/fizz-common/pom.xml index 71294c2..1d584a9 100644 --- a/fizz-common/pom.xml +++ b/fizz-common/pom.xml @@ -5,7 +5,7 @@ fizz-gateway-community com.fizzgate - 2.2.0-beta6 + 2.2.0-beta7 ../pom.xml 4.0.0 diff --git a/fizz-core/pom.xml b/fizz-core/pom.xml index 317819f..b6ed397 100644 --- a/fizz-core/pom.xml +++ b/fizz-core/pom.xml @@ -5,7 +5,7 @@ fizz-gateway-community com.fizzgate - 2.2.0-beta6 + 2.2.0-beta7 ../pom.xml 4.0.0 diff --git a/fizz-core/src/main/java/we/filter/FlowControlFilter.java b/fizz-core/src/main/java/we/filter/FlowControlFilter.java index af2001c..655d32a 100644 --- a/fizz-core/src/main/java/we/filter/FlowControlFilter.java +++ b/fizz-core/src/main/java/we/filter/FlowControlFilter.java @@ -285,22 +285,28 @@ public class FlowControlFilter extends FizzWebFilter { prev = resourceConfigs.get(sz - 1).getResourceId(); prevPrev = resourceConfigs.get(sz - 2).getResourceId(); - if (rateLimitConfig.type == ResourceRateLimitConfig.Type.APP && rateLimitConfig.path != null) { - String app = ResourceRateLimitConfig.getApp(prev); - if (app == null) { - something4(resourceConfigs, rateLimitConfig.app, null, null); - something4(resourceConfigs, rateLimitConfig.app, null, rateLimitConfig.service); - } else { - String service = ResourceRateLimitConfig.getService(prev); - if (service == null) { - something4(resourceConfigs, rateLimitConfig.app, null, rateLimitConfig.service); + if (rateLimitConfig.type == ResourceRateLimitConfig.Type.APP) { + String app = ResourceRateLimitConfig.getApp(prev); + if (rateLimitConfig.path == null) { + if (rateLimitConfig.service != null && app == null) { + something4(resourceConfigs, rateLimitConfig.app, null, null); + } } else { - app = ResourceRateLimitConfig.getApp(prevPrev); - if (app == null) { - something4(resourceConfigs, rateLimitConfig.app, null, null); - } + if (app == null) { + something4(resourceConfigs, rateLimitConfig.app, null, null); + something4(resourceConfigs, rateLimitConfig.app, null, rateLimitConfig.service); + } else { + String service = ResourceRateLimitConfig.getService(prev); + if (service == null) { + something4(resourceConfigs, rateLimitConfig.app, null, rateLimitConfig.service); + } else { + app = ResourceRateLimitConfig.getApp(prevPrev); + if (app == null) { + something4(resourceConfigs, rateLimitConfig.app, null, null); + } + } + } } - } } else if (rateLimitConfig.type == ResourceRateLimitConfig.Type.IP) { diff --git a/fizz-plugin/pom.xml b/fizz-plugin/pom.xml index 6079cba..c6bff1e 100644 --- a/fizz-plugin/pom.xml +++ b/fizz-plugin/pom.xml @@ -5,7 +5,7 @@ fizz-gateway-community com.fizzgate - 2.2.0-beta6 + 2.2.0-beta7 ../pom.xml 4.0.0 diff --git a/fizz-spring-boot-starter/pom.xml b/fizz-spring-boot-starter/pom.xml index 37a19b0..1d49a14 100644 --- a/fizz-spring-boot-starter/pom.xml +++ b/fizz-spring-boot-starter/pom.xml @@ -5,7 +5,7 @@ fizz-gateway-community com.fizzgate - 2.2.0-beta6 + 2.2.0-beta7 ../pom.xml 4.0.0 diff --git a/pom.xml b/pom.xml index 7f8c28b..34a0752 100644 --- a/pom.xml +++ b/pom.xml @@ -31,7 +31,7 @@ fizz-gateway-community ${project.artifactId} fizz gateway community - 2.2.0-beta6 + 2.2.0-beta7 pom fizz-common From c9fc3990135ed29bf4695b8427660ec9150724d4 Mon Sep 17 00:00:00 2001 From: hongqiaowei Date: Tue, 6 Jul 2021 18:53:57 +0800 Subject: [PATCH 17/28] Release 2.2.0-beta8 --- fizz-bootstrap/pom.xml | 2 +- fizz-common/pom.xml | 2 +- fizz-core/pom.xml | 2 +- fizz-core/src/main/java/we/filter/FlowControlFilter.java | 8 ++++---- fizz-plugin/pom.xml | 2 +- fizz-spring-boot-starter/pom.xml | 2 +- pom.xml | 2 +- 7 files changed, 10 insertions(+), 10 deletions(-) diff --git a/fizz-bootstrap/pom.xml b/fizz-bootstrap/pom.xml index 8b6a76e..a4c7142 100644 --- a/fizz-bootstrap/pom.xml +++ b/fizz-bootstrap/pom.xml @@ -12,7 +12,7 @@ com.fizzgate fizz-bootstrap - 2.2.0-beta7 + 2.2.0-beta8 1.8 diff --git a/fizz-common/pom.xml b/fizz-common/pom.xml index 1d584a9..e3276c1 100644 --- a/fizz-common/pom.xml +++ b/fizz-common/pom.xml @@ -5,7 +5,7 @@ fizz-gateway-community com.fizzgate - 2.2.0-beta7 + 2.2.0-beta8 ../pom.xml 4.0.0 diff --git a/fizz-core/pom.xml b/fizz-core/pom.xml index b6ed397..b190420 100644 --- a/fizz-core/pom.xml +++ b/fizz-core/pom.xml @@ -5,7 +5,7 @@ fizz-gateway-community com.fizzgate - 2.2.0-beta7 + 2.2.0-beta8 ../pom.xml 4.0.0 diff --git a/fizz-core/src/main/java/we/filter/FlowControlFilter.java b/fizz-core/src/main/java/we/filter/FlowControlFilter.java index 655d32a..7df67c3 100644 --- a/fizz-core/src/main/java/we/filter/FlowControlFilter.java +++ b/fizz-core/src/main/java/we/filter/FlowControlFilter.java @@ -111,10 +111,10 @@ public class FlowControlFilter extends FizzWebFilter { return WebUtils.buildJsonDirectResponse(exchange, HttpStatus.FORBIDDEN, null, json); } String app = WebUtils.getAppId(exchange); - if (app != null && !appService.getAppMap().containsKey(app)) { - String json = RespEntity.toJson(HttpStatus.FORBIDDEN.value(), "no app " + app, exchange.getRequest().getId()); - return WebUtils.buildJsonDirectResponse(exchange, HttpStatus.FORBIDDEN, null, json); - } + // if (app != null && !appService.getAppMap().containsKey(app)) { + // String json = RespEntity.toJson(HttpStatus.FORBIDDEN.value(), "no app " + app, exchange.getRequest().getId()); + // return WebUtils.buildJsonDirectResponse(exchange, HttpStatus.FORBIDDEN, null, json); + // } path = WebUtils.getClientReqPath(exchange); String ip = WebUtils.getOriginIp(exchange); diff --git a/fizz-plugin/pom.xml b/fizz-plugin/pom.xml index c6bff1e..5a95aec 100644 --- a/fizz-plugin/pom.xml +++ b/fizz-plugin/pom.xml @@ -5,7 +5,7 @@ fizz-gateway-community com.fizzgate - 2.2.0-beta7 + 2.2.0-beta8 ../pom.xml 4.0.0 diff --git a/fizz-spring-boot-starter/pom.xml b/fizz-spring-boot-starter/pom.xml index 1d49a14..4ef3aab 100644 --- a/fizz-spring-boot-starter/pom.xml +++ b/fizz-spring-boot-starter/pom.xml @@ -5,7 +5,7 @@ fizz-gateway-community com.fizzgate - 2.2.0-beta7 + 2.2.0-beta8 ../pom.xml 4.0.0 diff --git a/pom.xml b/pom.xml index 34a0752..213ce5b 100644 --- a/pom.xml +++ b/pom.xml @@ -31,7 +31,7 @@ fizz-gateway-community ${project.artifactId} fizz gateway community - 2.2.0-beta7 + 2.2.0-beta8 pom fizz-common From f26cd1530e1a5e42a47166dae20beed8ba4054a9 Mon Sep 17 00:00:00 2001 From: hongqiaowei Date: Wed, 7 Jul 2021 14:20:01 +0800 Subject: [PATCH 18/28] Release 2.2.0-beta9 --- fizz-bootstrap/pom.xml | 2 +- fizz-common/pom.xml | 2 +- fizz-core/pom.xml | 2 +- .../main/java/we/filter/PreprocessFilter.java | 32 +++++++++++++++---- .../java/we/plugin/FixedPluginFilter.java | 1 + fizz-plugin/pom.xml | 2 +- fizz-spring-boot-starter/pom.xml | 2 +- pom.xml | 2 +- 8 files changed, 33 insertions(+), 12 deletions(-) diff --git a/fizz-bootstrap/pom.xml b/fizz-bootstrap/pom.xml index a4c7142..8db531c 100644 --- a/fizz-bootstrap/pom.xml +++ b/fizz-bootstrap/pom.xml @@ -12,7 +12,7 @@ com.fizzgate fizz-bootstrap - 2.2.0-beta8 + 2.2.0-beta9 1.8 diff --git a/fizz-common/pom.xml b/fizz-common/pom.xml index e3276c1..6593347 100644 --- a/fizz-common/pom.xml +++ b/fizz-common/pom.xml @@ -5,7 +5,7 @@ fizz-gateway-community com.fizzgate - 2.2.0-beta8 + 2.2.0-beta9 ../pom.xml 4.0.0 diff --git a/fizz-core/pom.xml b/fizz-core/pom.xml index b190420..c70b2de 100644 --- a/fizz-core/pom.xml +++ b/fizz-core/pom.xml @@ -5,7 +5,7 @@ fizz-gateway-community com.fizzgate - 2.2.0-beta8 + 2.2.0-beta9 ../pom.xml 4.0.0 diff --git a/fizz-core/src/main/java/we/filter/PreprocessFilter.java b/fizz-core/src/main/java/we/filter/PreprocessFilter.java index ac7329f..82e9dfd 100644 --- a/fizz-core/src/main/java/we/filter/PreprocessFilter.java +++ b/fizz-core/src/main/java/we/filter/PreprocessFilter.java @@ -17,15 +17,13 @@ package we.filter; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; -import org.springframework.context.ApplicationContext; import org.springframework.core.annotation.Order; import org.springframework.http.HttpStatus; import org.springframework.stereotype.Component; import org.springframework.web.server.ServerWebExchange; import org.springframework.web.server.WebFilterChain; import reactor.core.publisher.Mono; +import we.plugin.FixedPluginFilter; import we.plugin.FizzPluginFilterChain; import we.plugin.PluginFilter; import we.plugin.auth.ApiConfig; @@ -37,6 +35,7 @@ import we.util.WebUtils; import javax.annotation.Resource; import java.util.HashMap; +import java.util.List; import java.util.Map; import java.util.function.Function; @@ -75,15 +74,22 @@ public class PreprocessFilter extends FizzWebFilter { if (authRes instanceof ApiConfig) { ApiConfig ac = (ApiConfig) authRes; afterAuth(exchange, ac); + m = executeFixedPluginFilters(exchange); + m = m.defaultIfEmpty(ReactorUtils.NULL); if (ac.pluginConfigs == null || ac.pluginConfigs.isEmpty()) { return m.flatMap(func(exchange, chain)); } else { - eas.put(FizzPluginFilterChain.WEB_FILTER_CHAIN, chain); - return FizzPluginFilterChain.next(exchange); + return m.flatMap( + nil -> { + eas.put(FizzPluginFilterChain.WEB_FILTER_CHAIN, chain); + return FizzPluginFilterChain.next(exchange); + } + ); } } else if (authRes == ApiConfigService.Access.YES) { afterAuth(exchange, null); - return m.flatMap(func(exchange, chain)); + m = executeFixedPluginFilters(exchange); + return m.defaultIfEmpty(ReactorUtils.NULL).flatMap(func(exchange, chain)); } else { String err = null; if (authRes instanceof ApiConfigService.Access) { @@ -138,4 +144,18 @@ public class PreprocessFilter extends FizzWebFilter { return chain.filter(exchange); }; } + + private Mono executeFixedPluginFilters(ServerWebExchange exchange) { + Mono vm = Mono.empty(); + List fixedPluginFilters = FixedPluginFilter.getPluginFilters(); + for (byte i = 0; i < fixedPluginFilters.size(); i++) { + FixedPluginFilter fpf = fixedPluginFilters.get(i); + vm = vm.defaultIfEmpty(ReactorUtils.NULL).flatMap( + v -> { + return fpf.filter(exchange, null, null); + } + ); + } + return vm; + } } diff --git a/fizz-core/src/main/java/we/plugin/FixedPluginFilter.java b/fizz-core/src/main/java/we/plugin/FixedPluginFilter.java index 02ea426..fd51e70 100644 --- a/fizz-core/src/main/java/we/plugin/FixedPluginFilter.java +++ b/fizz-core/src/main/java/we/plugin/FixedPluginFilter.java @@ -29,6 +29,7 @@ import java.util.*; * @author hongqiaowei */ +@Deprecated public abstract class FixedPluginFilter extends PluginFilter { private static final Logger log = LoggerFactory.getLogger(FixedPluginFilter.class); diff --git a/fizz-plugin/pom.xml b/fizz-plugin/pom.xml index 5a95aec..995f2c8 100644 --- a/fizz-plugin/pom.xml +++ b/fizz-plugin/pom.xml @@ -5,7 +5,7 @@ fizz-gateway-community com.fizzgate - 2.2.0-beta8 + 2.2.0-beta9 ../pom.xml 4.0.0 diff --git a/fizz-spring-boot-starter/pom.xml b/fizz-spring-boot-starter/pom.xml index 4ef3aab..41986b2 100644 --- a/fizz-spring-boot-starter/pom.xml +++ b/fizz-spring-boot-starter/pom.xml @@ -5,7 +5,7 @@ fizz-gateway-community com.fizzgate - 2.2.0-beta8 + 2.2.0-beta9 ../pom.xml 4.0.0 diff --git a/pom.xml b/pom.xml index 213ce5b..be1fb34 100644 --- a/pom.xml +++ b/pom.xml @@ -31,7 +31,7 @@ fizz-gateway-community ${project.artifactId} fizz gateway community - 2.2.0-beta8 + 2.2.0-beta9 pom fizz-common From ea7aac9897a23df39ca01f0c4214002a160f0ee7 Mon Sep 17 00:00:00 2001 From: hongqiaowei Date: Wed, 7 Jul 2021 17:01:15 +0800 Subject: [PATCH 19/28] PluginConfig.FIXED_CONFIG => PluginConfig.CUSTOM_CONFIG --- fizz-core/src/main/java/we/plugin/PluginConfig.java | 4 ++-- fizz-core/src/main/java/we/plugin/PluginFilter.java | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/fizz-core/src/main/java/we/plugin/PluginConfig.java b/fizz-core/src/main/java/we/plugin/PluginConfig.java index 6ad8779..7a7dfea 100644 --- a/fizz-core/src/main/java/we/plugin/PluginConfig.java +++ b/fizz-core/src/main/java/we/plugin/PluginConfig.java @@ -30,7 +30,7 @@ import java.util.Map; public class PluginConfig { - public static final String FIXED_CONFIG = "$fc"; + public static final String CUSTOM_CONFIG = "$fc"; public String plugin; // tb_plugin.eng_name @@ -55,7 +55,7 @@ public class PluginConfig { if (config == Collections.EMPTY_MAP) { config = new HashMap<>(); } - config.put(FIXED_CONFIG, fixedConfig); + config.put(CUSTOM_CONFIG, fixedConfig); } } diff --git a/fizz-core/src/main/java/we/plugin/PluginFilter.java b/fizz-core/src/main/java/we/plugin/PluginFilter.java index 298c95e..bbef439 100644 --- a/fizz-core/src/main/java/we/plugin/PluginFilter.java +++ b/fizz-core/src/main/java/we/plugin/PluginFilter.java @@ -45,7 +45,7 @@ public abstract class PluginFilter implements FizzPluginFilter { @Override public Mono filter(ServerWebExchange exchange, Map config) { - String fixedConfig = (String) config.get(PluginConfig.FIXED_CONFIG); + String fixedConfig = (String) config.get(PluginConfig.CUSTOM_CONFIG); return filter(exchange, config, fixedConfig); } From ea10d6a9522b94e41efe1e23752edafbc9437ff7 Mon Sep 17 00:00:00 2001 From: Francis Dong Date: Thu, 8 Jul 2021 12:13:25 +0800 Subject: [PATCH 20/28] Add peak QPS of time window #240 --- fizz-core/src/main/java/we/stats/ResourceStat.java | 3 +++ .../src/main/java/we/stats/TimeWindowStat.java | 13 +++++++++++++ 2 files changed, 16 insertions(+) diff --git a/fizz-core/src/main/java/we/stats/ResourceStat.java b/fizz-core/src/main/java/we/stats/ResourceStat.java index 92b3652..752ba60 100644 --- a/fizz-core/src/main/java/we/stats/ResourceStat.java +++ b/fizz-core/src/main/java/we/stats/ResourceStat.java @@ -203,6 +203,7 @@ public class ResourceStat { long totalReqs = 0; long totalRt = 0; long peakConcurrences = 0; + long peakRps = 0; long errors = 0; long blockReqs = 0; long totalBlockReqs = 0; @@ -215,6 +216,7 @@ public class ResourceStat { peakConcurrences = timeSlot.getPeakConcurrentRequests() > peakConcurrences ? timeSlot.getPeakConcurrentRequests() : peakConcurrences; + peakRps = timeSlot.getCounter().get() > peakRps ? timeSlot.getCounter().get() : peakRps; totalReqs = totalReqs + timeSlot.getCounter().get(); totalRt = totalRt + timeSlot.getTotalRt().get(); errors = errors + timeSlot.getErrors().get(); @@ -232,6 +234,7 @@ public class ResourceStat { tws.setBlockRequests(blockReqs); tws.setTotalBlockRequests(totalBlockReqs); tws.setCompReqs(compReqs); + tws.setPeakRps(new BigDecimal(peakRps)); if (compReqs > 0) { tws.setAvgRt(totalRt / compReqs); diff --git a/fizz-core/src/main/java/we/stats/TimeWindowStat.java b/fizz-core/src/main/java/we/stats/TimeWindowStat.java index 2204208..50f35b7 100644 --- a/fizz-core/src/main/java/we/stats/TimeWindowStat.java +++ b/fizz-core/src/main/java/we/stats/TimeWindowStat.java @@ -69,6 +69,11 @@ public class TimeWindowStat { * the average RPS(Requests Per Second) of time window */ private BigDecimal rps; + + /** + * the peak RPS(Requests Per Second) of time window + */ + private BigDecimal peakRps; /** * Peak concurrent requests of the time window @@ -181,4 +186,12 @@ public class TimeWindowStat { this.totalBlockRequests = totalBlockRequests; } + public BigDecimal getPeakRps() { + return peakRps; + } + + public void setPeakRps(BigDecimal peakRps) { + this.peakRps = peakRps; + } + } From 4d46ad838dd639ec93e54c994b12d0b559d966d1 Mon Sep 17 00:00:00 2001 From: hongqiaowei Date: Thu, 8 Jul 2021 14:26:54 +0800 Subject: [PATCH 21/28] add peak rps to flow stat --- .../src/main/java/we/config/FlowStatSchedConfig.java | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/fizz-core/src/main/java/we/config/FlowStatSchedConfig.java b/fizz-core/src/main/java/we/config/FlowStatSchedConfig.java index a4034af..7f08db3 100644 --- a/fizz-core/src/main/java/we/config/FlowStatSchedConfig.java +++ b/fizz-core/src/main/java/we/config/FlowStatSchedConfig.java @@ -72,6 +72,7 @@ public class FlowStatSchedConfig extends SchedConfig { private static final String _sourceIp = "\"sourceIp\":"; private static final String _service = "\"service\":"; private static final String _path = "\"path\":"; + private static final String _peakRps = "\"peakRps\":"; private static final String parentResourceList = "$prl"; @@ -183,12 +184,18 @@ public class FlowStatSchedConfig extends SchedConfig { StringBuilder b = ThreadContext.getStringBuilder(); long timeWin = w.getStartTime(); BigDecimal rps = w.getRps(); - double qps; + BigDecimal peakRps = w.getPeakRps(); + double qps, pRps; if (rps == null) { qps = 0.00; } else { qps = rps.doubleValue(); } + if (peakRps == null) { + pRps = 0.00; + } else { + pRps = peakRps.doubleValue(); + } // AtomicLong totalBlockRequests = resourceTimeWindow2totalBlockRequestsMap.get(resource + timeWin); // long tbrs = (totalBlockRequests == null ? w.getBlockRequests() : w.getBlockRequests() + totalBlockRequests.longValue()); @@ -231,6 +238,7 @@ public class FlowStatSchedConfig extends SchedConfig { b.append(_completeReqs); b.append(w.getCompReqs()); b.append(Constants.Symbol.COMMA); b.append(_peakConcurrents); b.append(w.getPeakConcurrentReqeusts()); b.append(Constants.Symbol.COMMA); b.append(_reqPerSec); b.append(qps); b.append(Constants.Symbol.COMMA); + b.append(_peakRps); b.append(pRps); b.append(Constants.Symbol.COMMA); b.append(_blockReqs); b.append(w.getBlockRequests()); b.append(Constants.Symbol.COMMA); b.append(_totalBlockReqs); b.append(tbrs); b.append(Constants.Symbol.COMMA); b.append(_errors); b.append(w.getErrors()); b.append(Constants.Symbol.COMMA); From f92eaff79261d13a9150d6459658d88fbf14eace Mon Sep 17 00:00:00 2001 From: Francis Dong Date: Mon, 5 Jul 2021 15:30:18 +0800 Subject: [PATCH 22/28] Support process control in aggregation #215 --- fizz-core/src/main/java/we/fizz/Pipeline.java | 26 +- fizz-core/src/main/java/we/fizz/Step.java | 48 ++- .../src/main/java/we/fizz/StepContext.java | 159 +++++++++ .../src/main/java/we/fizz/StepResponse.java | 33 ++ .../we/fizz/component/ComponentHelper.java | 159 +++++++++ .../we/fizz/component/ComponentTypeEnum.java | 50 +++ .../we/fizz/component/FixedDataTypeEnum.java | 44 +++ .../java/we/fizz/component/IComponent.java | 34 ++ .../java/we/fizz/component/OperatorEnum.java | 38 ++ .../we/fizz/component/RefDataTypeEnum.java | 43 +++ .../fizz/component/StepContextPosition.java | 47 +++ .../java/we/fizz/component/ValueTypeEnum.java | 41 +++ .../java/we/fizz/component/circle/Circle.java | 280 +++++++++++++++ .../we/fizz/component/circle/CircleItem.java | 37 ++ .../fizz/component/condition/Condition.java | 262 ++++++++++++++ .../component/condition/ConditionValue.java | 58 ++++ .../fizz/exception/FizzRuntimeException.java | 10 +- .../main/java/we/fizz/input/InputConfig.java | 14 +- .../main/java/we/fizz/input/InputFactory.java | 3 + .../main/java/we/fizz/input/PathMapping.java | 1 + .../input/extension/dubbo/DubboInput.java | 2 +- .../fizz/input/extension/grpc/GrpcInput.java | 2 +- .../input/extension/request/RequestInput.java | 2 +- .../java/we/fizz/component/CircleTests.java | 170 +++++++++ .../we/fizz/component/ConditionTests.java | 327 ++++++++++++++++++ .../java/we/fizz/input/PathMappingTests.java | 27 ++ 26 files changed, 1900 insertions(+), 17 deletions(-) create mode 100644 fizz-core/src/main/java/we/fizz/component/ComponentHelper.java create mode 100644 fizz-core/src/main/java/we/fizz/component/ComponentTypeEnum.java create mode 100644 fizz-core/src/main/java/we/fizz/component/FixedDataTypeEnum.java create mode 100644 fizz-core/src/main/java/we/fizz/component/IComponent.java create mode 100644 fizz-core/src/main/java/we/fizz/component/OperatorEnum.java create mode 100644 fizz-core/src/main/java/we/fizz/component/RefDataTypeEnum.java create mode 100644 fizz-core/src/main/java/we/fizz/component/StepContextPosition.java create mode 100644 fizz-core/src/main/java/we/fizz/component/ValueTypeEnum.java create mode 100644 fizz-core/src/main/java/we/fizz/component/circle/Circle.java create mode 100644 fizz-core/src/main/java/we/fizz/component/circle/CircleItem.java create mode 100644 fizz-core/src/main/java/we/fizz/component/condition/Condition.java create mode 100644 fizz-core/src/main/java/we/fizz/component/condition/ConditionValue.java create mode 100644 fizz-core/src/test/java/we/fizz/component/CircleTests.java create mode 100644 fizz-core/src/test/java/we/fizz/component/ConditionTests.java diff --git a/fizz-core/src/main/java/we/fizz/Pipeline.java b/fizz-core/src/main/java/we/fizz/Pipeline.java index 274a2e5..db99759 100644 --- a/fizz-core/src/main/java/we/fizz/Pipeline.java +++ b/fizz-core/src/main/java/we/fizz/Pipeline.java @@ -43,6 +43,9 @@ import reactor.core.publisher.Flux; import reactor.core.publisher.Mono; import we.constants.CommonConstants; import we.exception.ExecuteScriptException; +import we.fizz.component.ComponentHelper; +import we.fizz.component.IComponent; +import we.fizz.component.StepContextPosition; import we.fizz.input.ClientInputConfig; import we.fizz.input.Input; import we.fizz.input.InputConfig; @@ -116,14 +119,12 @@ public class Pipeline { }else { LinkedList opSteps = (LinkedList) steps.clone(); Step step1 = opSteps.removeFirst(); - step1.beforeRun(stepContext, null); - Mono> result = createStep(step1).expand(response -> { + Mono> result = runStep(step1, null).expand(response -> { if (opSteps.isEmpty() || response.isStop()) { return Mono.empty(); } Step step = opSteps.pop(); - step.beforeRun(stepContext, response); - return createStep(step); + return runStep(step, response); }).flatMap(response -> Flux.just(response)).collectList(); return result.flatMap(clientResponse -> { return handleOutput(input); @@ -131,6 +132,23 @@ public class Pipeline { } } + private Mono runStep(Step step, StepResponse response){ + List components = step.getComponents(); + if (components != null && components.size() > 0) { + StepContextPosition stepCtxPos = new StepContextPosition(step.getName()); + return ComponentHelper.run(components, stepContext, stepCtxPos, (ctx, pos) -> { + step.beforeRun(stepContext, null); + return createStep(step).flatMap(r -> { + ctx.addStepCircleResult(pos.getStepName()); + return Mono.just(r); + }); + }).flatMap(sr -> Mono.just((StepResponse)sr)); + } else { + step.beforeRun(stepContext, null); + return createStep(step); + } + } + private Mono handleOutput(Input input){ // 数据转换 long t3 = System.currentTimeMillis(); diff --git a/fizz-core/src/main/java/we/fizz/Step.java b/fizz-core/src/main/java/we/fizz/Step.java index d589ba1..2a7e9e0 100644 --- a/fizz-core/src/main/java/we/fizz/Step.java +++ b/fizz-core/src/main/java/we/fizz/Step.java @@ -22,7 +22,11 @@ import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.Map; +import java.util.function.Function; +import java.util.stream.Collector; +import java.util.stream.Collectors; +import org.noear.snack.ONode; import org.springframework.context.ConfigurableApplicationContext; import org.springframework.http.HttpMethod; import org.springframework.http.MediaType; @@ -34,6 +38,12 @@ import org.springframework.web.reactive.function.client.WebClient; import com.alibaba.fastjson.JSON; import reactor.core.publisher.Mono; +import we.fizz.component.ComponentHelper; +import we.fizz.component.ComponentTypeEnum; +import we.fizz.component.IComponent; +import we.fizz.component.StepContextPosition; +import we.fizz.component.circle.Circle; +import we.fizz.component.condition.Condition; import we.fizz.input.Input; import we.fizz.input.InputConfig; import we.fizz.input.InputContext; @@ -56,6 +66,16 @@ public class Step { private Map dataMapping; private Map requestConfigs = new HashMap(); + + private List components; + + public List getComponents() { + return components; + } + + public void setComponents(List components) { + this.components = components; + } public SoftReference getWeakPipeline() { return weakPipeline; @@ -78,6 +98,7 @@ public class Step { InputConfig inputConfig = InputFactory.createInputConfig(requestConfig); step.addRequestConfig((String)requestConfig.get("name"), inputConfig); } + step.setComponents(ComponentHelper.buildComponents((List>) config.get("components"))); return step; } } @@ -112,15 +133,32 @@ public class Step { public List run() { List monos = new ArrayList(); - for(String name :inputs.keySet()) { - Input input = inputs.get(name); - if (input.needRun(stepContext)) { - Mono singleMono = input.run(); - monos.add(singleMono); + for(String requestName :inputs.keySet()) { + Input input = inputs.get(requestName); + List components = input.getConfig().getComponents(); + if (components != null && components.size() > 0) { + StepContextPosition stepCtxPos = new StepContextPosition(name, requestName); + Mono result = ComponentHelper.run(components, stepContext, stepCtxPos, (ctx, pos) -> { + if (input.needRun(ctx)) { + return input.run().flatMap(r -> { + ctx.addRequestCircleResult(pos.getStepName(), pos.getRequestName()); + return Mono.just(r); + }); + } + return Mono.just(new HashMap()); + }); + monos.add(result); + } else { + if (input.needRun(stepContext)) { + Mono singleMono = input.run(); + monos.add(singleMono); + } } } return monos; } + + public void afeterRun() { diff --git a/fizz-core/src/main/java/we/fizz/StepContext.java b/fizz-core/src/main/java/we/fizz/StepContext.java index 4684985..6e6bf84 100644 --- a/fizz-core/src/main/java/we/fizz/StepContext.java +++ b/fizz-core/src/main/java/we/fizz/StepContext.java @@ -26,6 +26,8 @@ import java.util.concurrent.ConcurrentHashMap; import org.springframework.context.ConfigurableApplicationContext; import org.springframework.http.codec.multipart.FilePart; +import com.alibaba.fastjson.JSON; + import we.constants.CommonConstants; /** @@ -146,6 +148,8 @@ public class StepContext extends ConcurrentHashMap { requests = new HashMap<>(); stepResponse.setRequests(requests); requests.put(requestName, new HashMap()); + }else if(!requests.containsKey(requestName)) { + requests.put(requestName, new HashMap()); } return (Map) requests.get(requestName); } @@ -681,6 +685,161 @@ public class StepContext extends ConcurrentHashMap { } return request.get(key); } + + /** + * 设置Step的循环对象
+ * Set the current circle item of step
+ *
+ * + * @param stepName + * @param item + * @param index + */ + public void setStepCircleItem(String stepName, Object item, Integer index) { + StepResponse stepResponse = (StepResponse) this.get(stepName); + if (stepResponse == null) { + return; + } + stepResponse.setItem(item); + stepResponse.setIndex(index); + } + + /** + * 添加Step的循环结果
+ * Add the result of current circle item
+ *
+ * + * @param stepName + * @param key + * @param value + */ + public void addStepCircleResult(String stepName) { + StepResponse stepResponse = (StepResponse) this.get(stepName); + if (stepResponse == null) { + return; + } + List> circle = (List>) stepResponse.getCircle(); + if (circle == null) { + circle = new ArrayList<>(); + stepResponse.setCircle(circle); + } + Map circleResult = new HashMap<>(); + circleResult.put("requests", deepCopy(stepResponse.getRequests())); + circleResult.put("result", deepCopy(stepResponse.getResult())); + circleResult.put("item", deepCopy(stepResponse.getItem())); + circleResult.put("index", stepResponse.getIndex()); + circle.add(circleResult); + } + + /** + * 获取Step的循环对象
+ * Returns current circle item
+ * + * @param stepName + */ + public Object getStepItem(String stepName) { + StepResponse stepResponse = (StepResponse) this.get(stepName); + if (stepResponse == null) { + return null; + } + return stepResponse.getItem(); + } + + /** + * 获取Step的循环结果
+ * Returns circle result list of step
+ * + * @param stepName + */ + public List> getStepCircle(String stepName) { + StepResponse stepResponse = (StepResponse) this.get(stepName); + if (stepResponse == null) { + return null; + } + return stepResponse.getCircle(); + } + + /** + * 设置请求的循环对象
+ * Set current circle item of request
+ * + * @param stepName + * @param requestName + * @param item + */ + public void setRequestCircleItem(String stepName, String requestName, Object item, Integer index) { + Map request = getStepRequest(stepName, requestName); + if (request == null) { + return; + } + request.put("item", item); + request.put("index", index); + } + + /** + * 设置请求的循环结果
+ * Set current circle result of request
+ * + * @param stepName + * @param requestName + */ + public void addRequestCircleResult(String stepName, String requestName) { + Map request = getStepRequest(stepName, requestName); + if (request == null) { + return; + } + List> circle = (List>) request.get("circle"); + if (circle == null) { + circle = new ArrayList<>(); + request.put("circle", circle); + } + Map circleResult = new HashMap<>(); + circleResult.put("request", deepCopy(request.get("request"))); + circleResult.put("response", deepCopy(request.get("response"))); + circleResult.put("item", deepCopy(request.get("item"))); + circleResult.put("index", request.get("index")); + circle.add(circleResult); + } + + /** + * 获取请求的循环对象
+ * Returns the current circle item of request
+ * + * @param stepName + * @param requestName + */ + public List> getRequestCircleItem(String stepName, String requestName) { + Map request = getStepRequest(stepName, requestName); + if (request == null) { + return null; + } + return (List>) request.get("circle"); + } + + /** + * 获取请求的循环结果
+ * Returns circle result list of request
+ * + * @param stepName + * @param requestName + */ + public Object getRequestCircle(String stepName, String requestName) { + Map request = getStepRequest(stepName, requestName); + if (request == null) { + return null; + } + return request.get("item"); + } + + private Object deepCopy(Object obj) { + if(obj == null) { + return obj; + } + if(obj.getClass().isPrimitive()) { + return obj; + } + return JSON.parse(JSON.toJSONString(obj)); + } public ConfigurableApplicationContext getApplicationContext(){ return this.applicationContext; diff --git a/fizz-core/src/main/java/we/fizz/StepResponse.java b/fizz-core/src/main/java/we/fizz/StepResponse.java index 70e2230..01dc264 100644 --- a/fizz-core/src/main/java/we/fizz/StepResponse.java +++ b/fizz-core/src/main/java/we/fizz/StepResponse.java @@ -18,6 +18,7 @@ package we.fizz; import java.util.HashMap; +import java.util.List; import java.util.Map; /** @@ -28,6 +29,12 @@ public class StepResponse { private Map> requests; private Map result; private boolean stop; + // circle item + private Object item; + // index of circle item + private Integer index; + // circle results + private List> circle; public StepResponse(Step aStep, HashMap item, Map> requests) { setStepName(aStep.getName()); @@ -39,6 +46,14 @@ public class StepResponse { setResult(item); } + public void addRequest(String requestName, Map requestObj) { + if (this.requests.containsKey(requestName)) { + this.requests.get(requestName).putAll(requestObj); + } else { + this.requests.put(requestName, requestObj); + } + } + public boolean isStop() { return stop; } @@ -63,5 +78,23 @@ public class StepResponse { public void setResult(Map result) { this.result = result; } + public Object getItem() { + return item; + } + public void setItem(Object item) { + this.item = item; + } + public List> getCircle() { + return circle; + } + public void setCircle(List> circle) { + this.circle = circle; + } + public Integer getIndex() { + return index; + } + public void setIndex(Integer index) { + this.index = index; + } } diff --git a/fizz-core/src/main/java/we/fizz/component/ComponentHelper.java b/fizz-core/src/main/java/we/fizz/component/ComponentHelper.java new file mode 100644 index 0000000..72f1eb6 --- /dev/null +++ b/fizz-core/src/main/java/we/fizz/component/ComponentHelper.java @@ -0,0 +1,159 @@ +/* + * Copyright (C) 2021 the original author or authors. + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +package we.fizz.component; + +import java.util.ArrayList; +import java.util.List; +import java.util.Map; +import java.util.function.BiFunction; + +import org.noear.snack.ONode; + +import com.alibaba.fastjson.JSON; + +import reactor.core.publisher.Mono; +import we.fizz.StepContext; +import we.fizz.component.circle.Circle; +import we.fizz.component.condition.Condition; + +/** + * Condition component + * + * @author Francis Dong + * + */ +public class ComponentHelper { + + /** + * Converts step context to ONode + * + * @param stepContext context + * @return + */ + public static ONode toONode(StepContext stepContext) { + ONode o = null; + synchronized (stepContext) { + o = ONode.loadObj(stepContext); + } + return o; + } + + public static List buildComponents(List> componentConfig) { + List components = new ArrayList<>(); + + if (componentConfig != null && componentConfig.size() > 0) { + for (Map m : componentConfig) { + // condition + if (ComponentTypeEnum.CONDITION.getCode().equals(m.get("type"))) { + Condition c = JSON.parseObject(JSON.toJSONString(m), Condition.class); + components.add(c); + } + + // circle + if (ComponentTypeEnum.CIRCLE.getCode().equals(m.get("type"))) { + Circle c = JSON.parseObject(JSON.toJSONString(m), Circle.class); + components.add(c); + } + } + } + + return components; + } + + /** + * + * @param components + * @param stepContext + * @param f + */ + public static Mono run(List components, StepContext stepContext, + StepContextPosition stepCtxPos, BiFunction f) { + if (components != null && components.size() > 0) { + // conditions before circle component + List conditions = new ArrayList<>(); + Circle circle = null; + for (IComponent component : components) { + if (ComponentTypeEnum.CIRCLE == component.getType()) { + circle = (Circle) component; + } + if (circle == null && ComponentTypeEnum.CONDITION == component.getType()) { + conditions.add((Condition) component); + } + } + + if (conditions != null && conditions.size() > 0) { + ONode ctxNode = toONode(stepContext); + for (Condition c : conditions) { + if (!c.exec(ctxNode)) { + return null; + } + } + } + + if (circle != null) { + return circle.exec(stepContext, stepCtxPos, f); + } +// // conditions before circle component +// List conditions1 = new ArrayList<>(); +// // conditions after circle component +// List conditions2 = new ArrayList<>(); +// Circle circle = null; +// for (IComponent component : components) { +// if (ComponentTypeEnum.CIRCLE == component.getType()) { +// circle = (Circle) component; +// } +// if (circle == null && ComponentTypeEnum.CONDITION == component.getType()) { +// conditions1.add((Condition) component); +// } +// if (circle != null && ComponentTypeEnum.CONDITION == component.getType()) { +// conditions2.add((Condition) component); +// } +// } +// +// if (conditions1 != null && conditions1.size() > 0) { +// ONode ctxNode = toONode(stepContext); +// for (Condition c : conditions1) { +// if (!c.exec(ctxNode)) { +// return null; +// } +// } +// } +// +// if (circle != null) { +// return circle.exec(stepContext, (ctx) -> { +// boolean canRun = true; +// if (conditions2 != null && conditions2.size() > 0) { +// ONode ctxNode = toONode(ctx); +// for (Condition c : conditions2) { +// if (!c.exec(ctxNode)) { +// canRun = false; +// } +// } +// } +// if (canRun) { +// return f.apply(ctx); +// } else { +// return Mono.empty(); +// } +// +// }); +// } + } + return Mono.empty(); + } + +} diff --git a/fizz-core/src/main/java/we/fizz/component/ComponentTypeEnum.java b/fizz-core/src/main/java/we/fizz/component/ComponentTypeEnum.java new file mode 100644 index 0000000..5f47e20 --- /dev/null +++ b/fizz-core/src/main/java/we/fizz/component/ComponentTypeEnum.java @@ -0,0 +1,50 @@ +/* + * Copyright (C) 2021 the original author or authors. + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +package we.fizz.component; + +/** + * Component Type + * + * @author Francis Dong + * + */ +public enum ComponentTypeEnum { + + CONDITION("condition"), CIRCLE("circle"); + + private String code; + + private ComponentTypeEnum(String code) { + this.code = code; + } + + public static ComponentTypeEnum getEnumByCode(String code) { + for (ComponentTypeEnum item : ComponentTypeEnum.values()) { + if (item.getCode().equals(code)) { + return item; + } + } + + return null; + } + + public String getCode() { + return code; + } + +} diff --git a/fizz-core/src/main/java/we/fizz/component/FixedDataTypeEnum.java b/fizz-core/src/main/java/we/fizz/component/FixedDataTypeEnum.java new file mode 100644 index 0000000..cf881c7 --- /dev/null +++ b/fizz-core/src/main/java/we/fizz/component/FixedDataTypeEnum.java @@ -0,0 +1,44 @@ +/* + * Copyright (C) 2021 the original author or authors. + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +package we.fizz.component; + +/** + * Data type of fixed value + * + * @author Francis Dong + * + */ +public enum FixedDataTypeEnum{ + + NUMBER("number"), STRING("string"), BOOLEAN("boolean"); + + private String code; + + private FixedDataTypeEnum(String code) { + this.code = code; + } + + public String getCode() { + return this.code; + } + + public void setCode(String code) { + this.code = code; + } + +} diff --git a/fizz-core/src/main/java/we/fizz/component/IComponent.java b/fizz-core/src/main/java/we/fizz/component/IComponent.java new file mode 100644 index 0000000..65e40cb --- /dev/null +++ b/fizz-core/src/main/java/we/fizz/component/IComponent.java @@ -0,0 +1,34 @@ +/* + * Copyright (C) 2021 the original author or authors. + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +package we.fizz.component; + +/** + * Component interface + * + * @author Francis Dong + * + */ +public interface IComponent { + + /** + * Returns component type + * @return + */ + public ComponentTypeEnum getType(); + + +} diff --git a/fizz-core/src/main/java/we/fizz/component/OperatorEnum.java b/fizz-core/src/main/java/we/fizz/component/OperatorEnum.java new file mode 100644 index 0000000..2cfce8c --- /dev/null +++ b/fizz-core/src/main/java/we/fizz/component/OperatorEnum.java @@ -0,0 +1,38 @@ +/* + * Copyright (C) 2021 the original author or authors. + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +package we.fizz.component; + +/** + * Operator + * + * @author Francis Dong + * + */ +public enum OperatorEnum { + + EQ("eq"), NE("ne"), GT("gt"), GE("ge"), LT("lt"), LE("le"), CONTAINS("contains"), NOT_CONTAIN("notContain"), CONTAINS_ANY("containsAny"), + IS_NULL("isNull"), IS_NOT_NULL("isNotNull"), IS_BLANK("isBlank"), IS_NOT_BLANK("isNotBlank"), IS_EMPTY("isEmpty"), + IS_NOT_EMPTY("isNotEmpty"); + + private String code; + + private OperatorEnum(String code) { + this.code = code; + } + +} diff --git a/fizz-core/src/main/java/we/fizz/component/RefDataTypeEnum.java b/fizz-core/src/main/java/we/fizz/component/RefDataTypeEnum.java new file mode 100644 index 0000000..d212a82 --- /dev/null +++ b/fizz-core/src/main/java/we/fizz/component/RefDataTypeEnum.java @@ -0,0 +1,43 @@ +/* + * Copyright (C) 2021 the original author or authors. + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +package we.fizz.component; + +/** + * Data type of reference value + * + * @author Francis Dong + * + */ +public enum RefDataTypeEnum { + + INT("int"), LONG("long"), FLOAT("float"), DOUBLE("double"), STRING("string"), BOOLEAN("boolean"), ARRAY("array"); + + private String code; + + private RefDataTypeEnum(String code) { + this.code = code; + } + + public String getCode() { + return this.code; + } + + public void setCode(String code) { + this.code = code; + } +} diff --git a/fizz-core/src/main/java/we/fizz/component/StepContextPosition.java b/fizz-core/src/main/java/we/fizz/component/StepContextPosition.java new file mode 100644 index 0000000..9afe709 --- /dev/null +++ b/fizz-core/src/main/java/we/fizz/component/StepContextPosition.java @@ -0,0 +1,47 @@ +/* Copyright (C) 2021 the original author or authors. + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +package we.fizz.component; + +import lombok.Data; + +/** + * + * @author Francis Dong + * + */ +@Data +public class StepContextPosition { + + private String stepName; + private String requestName; + + public StepContextPosition(String stepName) { + this.stepName = stepName; + } + + public StepContextPosition(String stepName, String requestName) { + this.stepName = stepName; + this.requestName = requestName; + } + + public String getPath() { + if (this.requestName == null) { + return this.stepName; + } + return this.stepName + ".requests." + this.requestName; + } + +} diff --git a/fizz-core/src/main/java/we/fizz/component/ValueTypeEnum.java b/fizz-core/src/main/java/we/fizz/component/ValueTypeEnum.java new file mode 100644 index 0000000..9bb64ac --- /dev/null +++ b/fizz-core/src/main/java/we/fizz/component/ValueTypeEnum.java @@ -0,0 +1,41 @@ +/* + * Copyright (C) 2021 the original author or authors. + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +package we.fizz.component; + + +/** + * Value Type + * + * @author Francis Dong + * + */ +public enum ValueTypeEnum { + + FIXED("fixed"), REF("ref"); + + private String code; + + private ValueTypeEnum(String code) { + this.code = code; + } + + public String getCode() { + return code; + } + +} diff --git a/fizz-core/src/main/java/we/fizz/component/circle/Circle.java b/fizz-core/src/main/java/we/fizz/component/circle/Circle.java new file mode 100644 index 0000000..85e3e3b --- /dev/null +++ b/fizz-core/src/main/java/we/fizz/component/circle/Circle.java @@ -0,0 +1,280 @@ +/* + * Copyright (C) 2021 the original author or authors. + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +package we.fizz.component.circle; + +import java.util.Collection; +import java.util.Collections; +import java.util.List; +import java.util.function.BiFunction; +import java.util.function.Function; + +import org.noear.snack.ONode; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import lombok.Data; +import reactor.core.publisher.Flux; +import reactor.core.publisher.Mono; +import we.fizz.StepContext; +import we.fizz.component.ComponentHelper; +import we.fizz.component.ComponentTypeEnum; +import we.fizz.component.IComponent; +import we.fizz.component.StepContextPosition; +import we.fizz.component.ValueTypeEnum; +import we.fizz.component.condition.Condition; +import we.fizz.exception.FizzRuntimeException; +import we.fizz.input.PathMapping; +import we.fizz.input.RPCInput; + +/** + * Circle component + * + * @author Francis Dong + * + */ +public class Circle implements IComponent { + + private static final String type = ComponentTypeEnum.CIRCLE.getCode(); + + private String desc; + + private ValueTypeEnum dataSourceType; + + private Object dataSource; + + private List execConditions; + + private List breakConditions; + + @Override + public ComponentTypeEnum getType() { + return ComponentTypeEnum.getEnumByCode(type); + } + + /** + * + * @param desc [optional] description + * @param dataSourceType [required] type of data source + * @param dataSource [required] data source + * @param execConditions [optional] conditions to execute current circle loop + * item + * @param breakConditions [optional] conditions to break circle + */ + public Circle(String desc, ValueTypeEnum dataSourceType, Object dataSource, List execConditions, + List breakConditions) { + this.desc = desc; + this.dataSourceType = dataSourceType; + this.dataSource = dataSource; + this.execConditions = execConditions; + this.breakConditions = breakConditions; + } + + /** + * Current item + */ + private Object currentItem; + + /** + * Index of current item + */ + private Integer index; + + /** + * Fixed value of dataSource + */ + private Integer fixedValue; + + /** + * Reference value of dataSource + */ + private List refValue; + + private boolean refReadFlag; + + private Integer getFixedValue(ONode ctxNode) { + if (fixedValue != null) { + return fixedValue; + } + if (dataSource == null) { + return fixedValue; + } + if (dataSource instanceof Integer || dataSource instanceof Long) { + fixedValue = Integer.valueOf(dataSource.toString()); + if (fixedValue.intValue() < 1) { + throw new FizzRuntimeException("invalid data source, fixed data source must be a positive integer"); + } + return fixedValue; + } else { + throw new FizzRuntimeException("invalid data source, fixed data source must be a positive integer"); + } + } + + @SuppressWarnings("unchecked") + private List getRefValue(ONode ctxNode) { + if (refReadFlag) { + return refValue; + } + Object value = PathMapping.getValueByPath(ctxNode, (String) dataSource); + if (value == null) { + return null; + } + if (value instanceof Collection) { + refValue = (List) value; + return refValue; + } else { + throw new FizzRuntimeException("invalid data source, referenced data source must be a array"); + } + } + + /** + * Returns next circle item, returns null if no item left or dataSource is null + * + * @return + */ + public CircleItem next(ONode ctxNode) { + if (ValueTypeEnum.FIXED.equals(dataSourceType)) { + Integer total = this.getFixedValue(ctxNode); + if (index == null) { + index = 0; + currentItem = index; + return new CircleItem(currentItem, index); + } else if (index.intValue() < total.intValue() - 1) { + index = index + 1; + currentItem = index; + return new CircleItem(currentItem, index); + } else { + return null; + } + } else if (ValueTypeEnum.REF.equals(dataSourceType)) { + List list = this.getRefValue(ctxNode); + if (index == null) { + index = 0; + currentItem = list.get(index); + return new CircleItem(currentItem, index); + } else if (index.intValue() < list.size() - 1) { + index = index + 1; + currentItem = list.get(index); + return new CircleItem(currentItem, index); + } else { + return null; + } + } + return null; + } + + /** + * Returns true if execConditions are all true, false otherwise + * + * @param ctxNode + * @return + */ + public boolean canExec(ONode ctxNode) { + if (this.execConditions != null && this.execConditions.size() > 0) { + try { + for (Condition condition : execConditions) { + if (!condition.exec(ctxNode)) { + return false; + } + } + } catch (FizzRuntimeException e) { + throw new FizzRuntimeException(type + " " + e.getMessage(), e.getCause()); + } + } + return true; + } + + /** + * Returns true if breakConditions are all true, false otherwise + * + * @param ctxNode + * @return + */ + public boolean breakCircle(ONode ctxNode) { + if (this.breakConditions != null && this.breakConditions.size() > 0) { + try { + for (Condition condition : breakConditions) { + if (condition.exec(ctxNode)) { + return true; + } + } + } catch (FizzRuntimeException e) { + throw new FizzRuntimeException(type + " " + e.getMessage(), e.getCause()); + } + } + return false; + } + + @SuppressWarnings("unchecked") + public Mono exec(StepContext stepContext, StepContextPosition stepCtxPos, + BiFunction f) { + ONode ctxNode = ComponentHelper.toONode(stepContext); + CircleItem nextItem = this.next(ctxNode); + if (nextItem != null) { + return Mono.just(new CircleItemResult(nextItem, null)).expand(circleItemResult -> { + // put nextItem to step context and ctxNode for further JSON path mapping + CircleItem cItem = circleItemResult.nextItem; + if (stepCtxPos.getRequestName() != null) { + stepContext.setRequestCircleItem(stepCtxPos.getStepName(), stepCtxPos.getRequestName(), + cItem.getItem(), cItem.getIndex()); + } else { + stepContext.setStepCircleItem(stepCtxPos.getStepName(), cItem.getItem(), cItem.getIndex()); + } + PathMapping.setByPath(ctxNode, stepCtxPos.getPath() + ".item", cItem.getItem(), true); + PathMapping.setByPath(ctxNode, stepCtxPos.getPath() + ".index", cItem.getIndex(), true); + + if (!this.canExec(ctxNode)) { + return Mono.just(new CircleItemResult(this.next(ctxNode), null)); + } + if (this.breakCircle(ctxNode)) { + return Mono.empty(); + } + return f.apply(stepContext, stepCtxPos).flatMap(r -> { + CircleItem nextItem2 = this.next(ctxNode); + if (nextItem2 == null) { + return Mono.empty(); + } + return Mono.just(new CircleItemResult(nextItem2, r)); + }); + }).flatMap(circleItemResult -> Flux.just(circleItemResult)).collectList().flatMap(list -> { + if (list != null && list.size() > 0) { + Collections.reverse(list); + for (int i = 0; i < list.size(); i++) { + if (list.get(i).result != null) { + return Mono.just(list.get(i).result); + } + } + } + return Mono.empty(); + }); + } else { + return Mono.empty(); + } + } + + @Data + class CircleItemResult { + private CircleItem nextItem; + private Object result; + + public CircleItemResult(CircleItem nextItem, Object result) { + this.nextItem = nextItem; + this.result = result; + } + } + +} diff --git a/fizz-core/src/main/java/we/fizz/component/circle/CircleItem.java b/fizz-core/src/main/java/we/fizz/component/circle/CircleItem.java new file mode 100644 index 0000000..34b6cc0 --- /dev/null +++ b/fizz-core/src/main/java/we/fizz/component/circle/CircleItem.java @@ -0,0 +1,37 @@ +/* + * Copyright (C) 2021 the original author or authors. + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +package we.fizz.component.circle; + +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.NoArgsConstructor; + +/** + * + * @author Francis Dong + * + */ +@Data +@AllArgsConstructor +@NoArgsConstructor +public class CircleItem { + + private Object item; + + private Integer index; + +} diff --git a/fizz-core/src/main/java/we/fizz/component/condition/Condition.java b/fizz-core/src/main/java/we/fizz/component/condition/Condition.java new file mode 100644 index 0000000..a7e62b7 --- /dev/null +++ b/fizz-core/src/main/java/we/fizz/component/condition/Condition.java @@ -0,0 +1,262 @@ +/* + * Copyright (C) 2021 the original author or authors. + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +package we.fizz.component.condition; + +import java.util.Collection; +import java.util.Map; + +import org.apache.commons.lang3.StringUtils; +import org.noear.snack.ONode; +import org.springframework.util.CollectionUtils; + +import com.alibaba.fastjson.JSON; + +import lombok.AllArgsConstructor; +import lombok.Data; +import we.fizz.component.ComponentTypeEnum; +import we.fizz.component.IComponent; +import we.fizz.component.OperatorEnum; +import we.fizz.component.RefDataTypeEnum; +import we.fizz.component.ValueTypeEnum; +import we.fizz.exception.FizzRuntimeException; +import we.fizz.input.PathMapping; + +/** + * Condition component + * + * @author Francis Dong + * + */ +@Data +@AllArgsConstructor +public class Condition implements IComponent { + + private static final String type = ComponentTypeEnum.CONDITION.getCode(); + + private String desc; + + private ConditionValue value1; + + private OperatorEnum operator; + + private ConditionValue value2; + + @Override + public ComponentTypeEnum getType() { + return ComponentTypeEnum.getEnumByCode(type); + } + + /** + * Execute condition + * + * @return + */ + @SuppressWarnings({ "rawtypes" }) + public boolean exec(ONode ctxNode) { + if (value1 == null || operator == null) { + return false; + } + + boolean rs = false; + try { + Object v1 = null; + if (ValueTypeEnum.FIXED.equals(value1.getType())) { + v1 = value1.getValue(); + } else { + v1 = PathMapping.getValueByPath(ctxNode, (String) value1.getValue()); + v1 = this.cast(value1.getRefDataType(), v1); + } + + Object v2 = null; + if (value2 != null && value2.getType() != null) { + if (ValueTypeEnum.FIXED.equals(value2.getType())) { + v2 = value2.getValue(); + } else { + v2 = PathMapping.getValueByPath(ctxNode, (String) value2.getValue()); + v2 = this.cast(value2.getRefDataType(), v2); + } + } + + switch (operator) { + case EQ: + if (v1 == null && v2 == null) { + rs = true; + } else if (v1 != null && v2 != null) { + rs = this.compare(v1, v2) == 0; + } + break; + case NE: + if (v1 == null && v2 == null) { + rs = false; + } else if ((v1 == null && v2 != null) || (v1 != null && v2 == null)) { + rs = true; + } else if (v1 != null && v2 != null) { + rs = this.compare(v1, v2) != 0; + } + break; + case GT: + rs = this.compare(v1, v2) > 0; + break; + case GE: + rs = this.compare(v1, v2) >= 0; + break; + case LT: + rs = this.compare(v1, v2) < 0; + break; + case LE: + rs = this.compare(v1, v2) <= 0; + break; + case CONTAINS: + if (v1 == null) { + rs = false; + } + if (v1 instanceof Collection && !(v2 instanceof Collection)) { + Collection coll1 = (Collection) v1; + Object el = v2; + if (v2 instanceof Integer || v2 instanceof Long) { + el = Long.valueOf(v2.toString()); + } else if (v2 instanceof Float || v2 instanceof Double) { + el = Double.valueOf(v2.toString()); + } + rs = CollectionUtils.contains(coll1.iterator(), el); + } else if (!(v1 instanceof Collection)) { + throw new FizzRuntimeException("value1 must be a collection"); + } else if (v2 instanceof Collection) { + throw new FizzRuntimeException("value2 can not be a collection"); + } + break; + case NOT_CONTAIN: + if (v1 == null) { + rs = true; + } + if (v1 instanceof Collection && !(v2 instanceof Collection)) { + Collection coll1 = (Collection) v1; + Object el = v2; + if (v2 instanceof Integer || v2 instanceof Long) { + el = Long.valueOf(v2.toString()); + } else if (v2 instanceof Float || v2 instanceof Double) { + el = Double.valueOf(v2.toString()); + } + rs = !CollectionUtils.contains(coll1.iterator(), el); + } else if (!(v1 instanceof Collection)) { + throw new FizzRuntimeException("value1 must be a collection"); + } else if (v2 instanceof Collection) { + throw new FizzRuntimeException("value2 can not be a collection"); + } + break; + case CONTAINS_ANY: + if (v1 == null || v2 == null) { + rs = false; + } + if (v1 instanceof Collection && v2 instanceof Collection) { + Collection coll1 = (Collection) v1; + Collection coll2 = (Collection) v2; + rs = CollectionUtils.containsAny(coll1, coll2); + } else if (!(v1 instanceof Collection)) { + throw new FizzRuntimeException("value1 must be a collection"); + } else if (!(v2 instanceof Collection)) { + throw new FizzRuntimeException("value2 must be a collection"); + } + break; + case IS_NULL: + rs = v1 == null; + break; + case IS_NOT_NULL: + rs = v1 != null; + break; + case IS_BLANK: + rs = v1 == null || StringUtils.isBlank(v1.toString()); + break; + case IS_NOT_BLANK: + rs = v1 != null && StringUtils.isNotBlank(v1.toString()); + break; + case IS_EMPTY: + rs = v1 == null || (v1 instanceof Collection && ((Collection) v1).isEmpty()) + || (v1 instanceof Map && ((Map) v1).isEmpty()); + break; + case IS_NOT_EMPTY: + if (v1 != null) { + if (v1 instanceof Collection) { + rs = !((Collection) v1).isEmpty(); + } else if (v1 instanceof Map) { + rs = !((Map) v1).isEmpty(); + } + } + break; + default: + break; + } + } catch (FizzRuntimeException e) { + String message = type + ": " + e.getMessage() + ", data=" + JSON.toJSONString(this); + throw new FizzRuntimeException(message, e.getCause()); + } + + return rs; + } + + @SuppressWarnings("rawtypes") + private int compare(Object v1, Object v2) { + if (v1 == null || v2 == null) { + throw new FizzRuntimeException("value1 and value2 can not be null"); + } + if (v1 instanceof Boolean && v2 instanceof Boolean) { + Boolean n1 = (Boolean) v1; + Boolean n2 = (Boolean) v2; + return n1.compareTo(n2); + } else if ((v1 instanceof Integer || v1 instanceof Long || v1 instanceof Float || v1 instanceof Double) + && (v2 instanceof Integer || v2 instanceof Long || v2 instanceof Float || v2 instanceof Double)) { + // compare value if both are numbers + Double n1 = Double.valueOf(v1.toString()); + Double n2 = Double.valueOf(v2.toString()); + return n1.compareTo(n2); + } else if (v1 instanceof String && v2 instanceof String) { + String s1 = v1.toString(); + String s2 = v2.toString(); + return s1.compareTo(s2); + } else { + throw new FizzRuntimeException( + "types of value1 and value2 are not consistent or not supported for comparision"); + } + } + + private Object cast(RefDataTypeEnum type, Object val) { + if (type != null) { + switch (type) { + case INT: + val = Integer.valueOf(val.toString()); + break; + case LONG: + val = Long.valueOf(val.toString()); + break; + case FLOAT: + val = Float.valueOf(val.toString()); + break; + case DOUBLE: + val = Double.valueOf(val.toString()); + break; + case BOOLEAN: + val = Boolean.valueOf(val.toString()); + break; + case STRING: + val = val.toString(); + break; + } + } + return val; + } +} diff --git a/fizz-core/src/main/java/we/fizz/component/condition/ConditionValue.java b/fizz-core/src/main/java/we/fizz/component/condition/ConditionValue.java new file mode 100644 index 0000000..ad4cfdb --- /dev/null +++ b/fizz-core/src/main/java/we/fizz/component/condition/ConditionValue.java @@ -0,0 +1,58 @@ +/* + * Copyright (C) 2021 the original author or authors. + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +package we.fizz.component.condition; + +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.NoArgsConstructor; +import we.fizz.component.FixedDataTypeEnum; +import we.fizz.component.RefDataTypeEnum; +import we.fizz.component.ValueTypeEnum; + +/** + * Condition value + * + * @author Francis Dong + * + */ +@Data +@AllArgsConstructor +@NoArgsConstructor +public class ConditionValue { + + private ValueTypeEnum type; + + private FixedDataTypeEnum fixedDataType; + + private RefDataTypeEnum refDataType; + + private Object value; + + public ConditionValue(ValueTypeEnum type, FixedDataTypeEnum fixedDataType, Object value) { + this.type = type; + this.fixedDataType = fixedDataType; + this.value = value; + } + + public ConditionValue(ValueTypeEnum type, RefDataTypeEnum refDataType, Object value) { + this.type = type; + this.refDataType = refDataType; + this.value = value; + } + +} diff --git a/fizz-core/src/main/java/we/fizz/exception/FizzRuntimeException.java b/fizz-core/src/main/java/we/fizz/exception/FizzRuntimeException.java index 9205f0b..92643f8 100644 --- a/fizz-core/src/main/java/we/fizz/exception/FizzRuntimeException.java +++ b/fizz-core/src/main/java/we/fizz/exception/FizzRuntimeException.java @@ -1,7 +1,11 @@ package we.fizz.exception; public class FizzRuntimeException extends RuntimeException { - public FizzRuntimeException (String message){ - super(message); - } + public FizzRuntimeException(String message) { + super(message); + } + + public FizzRuntimeException(String message, Throwable cause) { + super(message, cause); + } } diff --git a/fizz-core/src/main/java/we/fizz/input/InputConfig.java b/fizz-core/src/main/java/we/fizz/input/InputConfig.java index 8ce6f91..3e40741 100644 --- a/fizz-core/src/main/java/we/fizz/input/InputConfig.java +++ b/fizz-core/src/main/java/we/fizz/input/InputConfig.java @@ -18,8 +18,11 @@ package we.fizz.input; import java.util.HashMap; +import java.util.List; import java.util.Map; +import we.fizz.component.IComponent; + /** * * @author linwaiwai @@ -30,9 +33,8 @@ public class InputConfig { private InputType type; protected Map dataMapping; protected Map configMap; - - private Map condition; + private List components; public Map getCondition() { return condition; @@ -72,6 +74,14 @@ public class InputConfig { this.fallback = fallback; } + public List getComponents() { + return components; + } + + public void setComponents(List components) { + this.components = components; + } + public void parse(){ } diff --git a/fizz-core/src/main/java/we/fizz/input/InputFactory.java b/fizz-core/src/main/java/we/fizz/input/InputFactory.java index 5a335b7..c0b611b 100644 --- a/fizz-core/src/main/java/we/fizz/input/InputFactory.java +++ b/fizz-core/src/main/java/we/fizz/input/InputFactory.java @@ -17,11 +17,13 @@ package we.fizz.input; +import we.fizz.component.ComponentHelper; import we.fizz.exception.FizzRuntimeException; import java.lang.reflect.Constructor; import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; import java.util.HashMap; +import java.util.List; import java.util.Map; /** @@ -56,6 +58,7 @@ public class InputFactory { } inputConfig.setType(typeEnum); inputConfig.setDataMapping((Map) config.get("dataMapping")); + inputConfig.setComponents(ComponentHelper.buildComponents((List>) config.get("components"))); inputConfig.parse(); return inputConfig; } diff --git a/fizz-core/src/main/java/we/fizz/input/PathMapping.java b/fizz-core/src/main/java/we/fizz/input/PathMapping.java index 6f9d46d..2b0c6f8 100644 --- a/fizz-core/src/main/java/we/fizz/input/PathMapping.java +++ b/fizz-core/src/main/java/we/fizz/input/PathMapping.java @@ -309,6 +309,7 @@ public class PathMapping { break; } } + // upper case header name if (list.size() > 5 && "headers".equals(list.get(4))) { String headerName = list.get(5).toUpperCase(); diff --git a/fizz-core/src/main/java/we/fizz/input/extension/dubbo/DubboInput.java b/fizz-core/src/main/java/we/fizz/input/extension/dubbo/DubboInput.java index a5ed012..f34ccef 100644 --- a/fizz-core/src/main/java/we/fizz/input/extension/dubbo/DubboInput.java +++ b/fizz-core/src/main/java/we/fizz/input/extension/dubbo/DubboInput.java @@ -97,7 +97,7 @@ public class DubboInput extends RPCInput { Map group = new HashMap<>(); group.put("request", request); group.put("response", response); - this.stepResponse.getRequests().put(name, group); + this.stepResponse.addRequest(name, group); request.put("serviceName", config.getServiceName()); request.put("version", config.getVersion()); diff --git a/fizz-core/src/main/java/we/fizz/input/extension/grpc/GrpcInput.java b/fizz-core/src/main/java/we/fizz/input/extension/grpc/GrpcInput.java index 0acf716..4829d0d 100644 --- a/fizz-core/src/main/java/we/fizz/input/extension/grpc/GrpcInput.java +++ b/fizz-core/src/main/java/we/fizz/input/extension/grpc/GrpcInput.java @@ -91,7 +91,7 @@ public class GrpcInput extends RPCInput implements IInput { Map group = new HashMap<>(); group.put("request", request); group.put("response", response); - this.stepResponse.getRequests().put(name, group); + this.stepResponse.addRequest(name, group); request.put("serviceName", config.getServiceName()); request.put("method", config.getMethod()); diff --git a/fizz-core/src/main/java/we/fizz/input/extension/request/RequestInput.java b/fizz-core/src/main/java/we/fizz/input/extension/request/RequestInput.java index e0c32f4..d848fd7 100644 --- a/fizz-core/src/main/java/we/fizz/input/extension/request/RequestInput.java +++ b/fizz-core/src/main/java/we/fizz/input/extension/request/RequestInput.java @@ -121,7 +121,7 @@ public class RequestInput extends RPCInput implements IInput{ Map group = new HashMap<>(); group.put("request", request); group.put("response", response); - this.stepResponse.getRequests().put(name, group); + this.stepResponse.addRequest(name, group); HttpMethod method = HttpMethod.valueOf(config.getMethod().toUpperCase()); request.put("method", method); diff --git a/fizz-core/src/test/java/we/fizz/component/CircleTests.java b/fizz-core/src/test/java/we/fizz/component/CircleTests.java new file mode 100644 index 0000000..4e2ee52 --- /dev/null +++ b/fizz-core/src/test/java/we/fizz/component/CircleTests.java @@ -0,0 +1,170 @@ +/* + * Copyright (C) 2021 the original author or authors. + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +package we.fizz.component; + +import static org.junit.jupiter.api.Assertions.assertEquals; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; + +import org.junit.jupiter.api.Test; +import org.noear.snack.ONode; + +import we.fizz.component.circle.Circle; +import we.fizz.component.circle.CircleItem; +import we.fizz.component.condition.Condition; +import we.fizz.component.condition.ConditionValue; +/** + * + * @author Francis Dong + * + */ +import we.fizz.input.PathMapping; + +class CircleTests { + @Test + void contextLoads() { + } + + + @SuppressWarnings("rawtypes") + @Test + void testNextFixedDataSource() { + ONode ctxNode = ONode.load(new HashMap()); + + // FIXED data source + Circle c = new Circle(null, ValueTypeEnum.FIXED, 3, null, null); + CircleItem circleItem = c.next(ctxNode); + assertEquals(0, (Integer) circleItem.getItem()); + + circleItem = c.next(ctxNode); + assertEquals(1, (Integer) circleItem.getItem()); + + circleItem = c.next(ctxNode); + assertEquals(2, (Integer) circleItem.getItem()); + + circleItem = c.next(ctxNode); + assertEquals(null, circleItem); + + } + + @Test + void testNextRefDataSource() { + ONode ctxNode = ONode.load(new HashMap()); + + List list1 = new ArrayList<>(); + list1.add("1"); + list1.add("2"); + list1.add("3"); + PathMapping.setByPath(ctxNode, "data.list1", list1, true); + + // REF data source + Circle c = new Circle(null, ValueTypeEnum.REF, "data.list1", null, null); + CircleItem circleItem = c.next(ctxNode); + assertEquals("1", (String) circleItem.getItem()); + + circleItem = c.next(ctxNode); + assertEquals("2", (String) circleItem.getItem()); + + circleItem = c.next(ctxNode); + assertEquals("3", (String) circleItem.getItem()); + + circleItem = c.next(ctxNode); + assertEquals(null, circleItem); + + } + + @Test + void testExecCondition() { + ONode ctxNode = ONode.load(new HashMap()); + + List list1 = new ArrayList<>(); + list1.add("0"); + list1.add("1"); + list1.add("2"); + list1.add("3"); + list1.add("4"); + + PathMapping.setByPath(ctxNode, "data.list1", list1, true); + + ConditionValue bValue1 = new ConditionValue(ValueTypeEnum.FIXED, FixedDataTypeEnum.STRING, "3"); + ConditionValue bValue2 = new ConditionValue(ValueTypeEnum.REF, RefDataTypeEnum.STRING, "item"); + Condition c1 = new Condition(null, bValue1, OperatorEnum.NE, bValue2); + + List execConditions = new ArrayList<>(); + execConditions.add(c1); + + Circle circle = new Circle(null, ValueTypeEnum.REF, "data.list1", execConditions, null); + + for (int i = 0; i < 5; i++) { + CircleItem circleItem = circle.next(ctxNode); + PathMapping.setByPath(ctxNode, "item", circleItem.getItem(), true); + PathMapping.setByPath(ctxNode, "index", circleItem.getIndex(), true); + boolean rs = circle.canExec(ctxNode); + assertEquals(i, circleItem.getIndex()); + if (i < 3) { + assertEquals(true, rs); + } + if (i == 3) { + assertEquals(false, rs); + break; + } + } + + } + + @Test + void testBreakCondition() { + ONode ctxNode = ONode.load(new HashMap()); + + List list1 = new ArrayList<>(); + list1.add("0"); + list1.add("1"); + list1.add("2"); + list1.add("3"); + list1.add("4"); + + PathMapping.setByPath(ctxNode, "data.list1", list1, true); + + ConditionValue bValue1 = new ConditionValue(ValueTypeEnum.FIXED, FixedDataTypeEnum.STRING, "3"); + ConditionValue bValue2 = new ConditionValue(ValueTypeEnum.REF, RefDataTypeEnum.STRING, "item"); + Condition c1 = new Condition(null, bValue1, OperatorEnum.EQ, bValue2); + + List breakConditions = new ArrayList<>(); + breakConditions.add(c1); + + Circle circle = new Circle(null, ValueTypeEnum.REF, "data.list1", null, breakConditions); + + for (int i = 0; i < 5; i++) { + CircleItem circleItem = circle.next(ctxNode); + PathMapping.setByPath(ctxNode, "item", circleItem.getItem(), true); + PathMapping.setByPath(ctxNode, "index", circleItem.getIndex(), true); + boolean rs = circle.breakCircle(ctxNode); + assertEquals(i, circleItem.getIndex()); + if (i < 3) { + assertEquals(false, rs); + } + if (i == 3) { + assertEquals(true, rs); + break; + } + } + + } + +} \ No newline at end of file diff --git a/fizz-core/src/test/java/we/fizz/component/ConditionTests.java b/fizz-core/src/test/java/we/fizz/component/ConditionTests.java new file mode 100644 index 0000000..8c478d6 --- /dev/null +++ b/fizz-core/src/test/java/we/fizz/component/ConditionTests.java @@ -0,0 +1,327 @@ +/* + * Copyright (C) 2021 the original author or authors. + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +package we.fizz.component; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertTrue; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.LinkedHashMap; +import java.util.List; +import java.util.Map; +import java.util.Map.Entry; + +import javax.validation.constraints.AssertTrue; + +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.Test; +import org.noear.snack.ONode; + +import we.fizz.component.condition.Condition; +import we.fizz.component.condition.ConditionValue; +import we.fizz.input.PathMapping; + +/** + * + * @author Francis Dong + * + */ +class ConditionTests { + @Test + void contextLoads() { + } + + private static final Boolean TRUE = true; + private static final Boolean FALSE = false; + + @Test + void testExec() { + ONode ctxNode = ONode.load(new HashMap()); + + Map m = new HashMap<>(); + m.put("int", 1); + m.put("long", 2); + m.put("float", 3.1); + m.put("double", 4.21); + m.put("string_abcd", "abcd"); + m.put("string_1", "1"); + m.put("string_8", "8"); + m.put("string_blank", ""); + m.put("bool_true", true); + m.put("bool_false", false); + + List list1 = new ArrayList<>(); + list1.add("0"); + list1.add("1"); + list1.add("2"); + list1.add("3"); + list1.add("4"); + + List list2 = new ArrayList<>(); + list2.add("1"); + list2.add("3"); + list2.add("223"); + + List intList = new ArrayList<>(); + intList.add(0); + intList.add(1); + intList.add(2); + intList.add(3); + intList.add(4); + + List floatList = new ArrayList<>(); + floatList.add(0f); + floatList.add(1f); + floatList.add(2f); + floatList.add(3f); + floatList.add(4f); + + PathMapping.setByPath(ctxNode, "data.m", m, true); + PathMapping.setByPath(ctxNode, "data.list1", list1, true); + PathMapping.setByPath(ctxNode, "data.list2", list2, true); + PathMapping.setByPath(ctxNode, "data.intList", intList, true); + PathMapping.setByPath(ctxNode, "data.floatList", floatList, true); + PathMapping.setByPath(ctxNode, "data.emptyList", new ArrayList<>(), true); + + // boolean + this.run(ctxNode, new Object[] { ValueTypeEnum.FIXED, FixedDataTypeEnum.BOOLEAN, TRUE, ValueTypeEnum.FIXED, + FixedDataTypeEnum.BOOLEAN, TRUE, OperatorEnum.EQ, TRUE }); + this.run(ctxNode, new Object[] { ValueTypeEnum.FIXED, FixedDataTypeEnum.BOOLEAN, FALSE, ValueTypeEnum.FIXED, + FixedDataTypeEnum.BOOLEAN, FALSE, OperatorEnum.EQ, TRUE }); + this.run(ctxNode, new Object[] { ValueTypeEnum.FIXED, FixedDataTypeEnum.BOOLEAN, TRUE, ValueTypeEnum.FIXED, + FixedDataTypeEnum.BOOLEAN, FALSE, OperatorEnum.EQ, FALSE }); + + this.run(ctxNode, new Object[] { ValueTypeEnum.FIXED, FixedDataTypeEnum.BOOLEAN, FALSE, ValueTypeEnum.REF, + RefDataTypeEnum.BOOLEAN, "data.m.bool_true", OperatorEnum.EQ, FALSE }); + this.run(ctxNode, new Object[] { ValueTypeEnum.FIXED, FixedDataTypeEnum.BOOLEAN, FALSE, ValueTypeEnum.REF, + RefDataTypeEnum.BOOLEAN, "data.m.bool_false", OperatorEnum.EQ, TRUE }); + this.run(ctxNode, new Object[] { ValueTypeEnum.FIXED, FixedDataTypeEnum.BOOLEAN, TRUE, ValueTypeEnum.REF, + RefDataTypeEnum.BOOLEAN, "data.m.bool_true", OperatorEnum.EQ, TRUE }); + this.run(ctxNode, new Object[] { ValueTypeEnum.FIXED, FixedDataTypeEnum.BOOLEAN, FALSE, ValueTypeEnum.REF, null, + "data.m.a", OperatorEnum.EQ, FALSE }); + + this.run(ctxNode, new Object[] { ValueTypeEnum.FIXED, FixedDataTypeEnum.BOOLEAN, TRUE, ValueTypeEnum.FIXED, + FixedDataTypeEnum.BOOLEAN, FALSE, OperatorEnum.GT, TRUE }); + this.run(ctxNode, new Object[] { ValueTypeEnum.FIXED, FixedDataTypeEnum.BOOLEAN, TRUE, ValueTypeEnum.FIXED, + FixedDataTypeEnum.BOOLEAN, FALSE, OperatorEnum.GE, TRUE }); + this.run(ctxNode, new Object[] { ValueTypeEnum.FIXED, FixedDataTypeEnum.BOOLEAN, TRUE, ValueTypeEnum.FIXED, + FixedDataTypeEnum.BOOLEAN, TRUE, OperatorEnum.GE, TRUE }); + this.run(ctxNode, new Object[] { ValueTypeEnum.FIXED, FixedDataTypeEnum.BOOLEAN, FALSE, ValueTypeEnum.FIXED, + FixedDataTypeEnum.BOOLEAN, TRUE, OperatorEnum.LT, TRUE }); + this.run(ctxNode, new Object[] { ValueTypeEnum.FIXED, FixedDataTypeEnum.BOOLEAN, FALSE, ValueTypeEnum.FIXED, + FixedDataTypeEnum.BOOLEAN, FALSE, OperatorEnum.LE, TRUE }); + + // number + this.run(ctxNode, new Object[] { ValueTypeEnum.FIXED, FixedDataTypeEnum.NUMBER, 1, ValueTypeEnum.FIXED, + FixedDataTypeEnum.NUMBER, 1, OperatorEnum.EQ, TRUE }); + this.run(ctxNode, new Object[] { ValueTypeEnum.FIXED, FixedDataTypeEnum.NUMBER, 1, ValueTypeEnum.FIXED, + FixedDataTypeEnum.NUMBER, 2, OperatorEnum.EQ, FALSE }); + this.run(ctxNode, new Object[] { ValueTypeEnum.FIXED, FixedDataTypeEnum.NUMBER, 1, ValueTypeEnum.FIXED, + FixedDataTypeEnum.NUMBER, 1.000, OperatorEnum.EQ, TRUE }); + this.run(ctxNode, new Object[] { ValueTypeEnum.FIXED, FixedDataTypeEnum.NUMBER, 1, ValueTypeEnum.FIXED, + FixedDataTypeEnum.NUMBER, 2.1, OperatorEnum.EQ, FALSE }); + this.run(ctxNode, new Object[] { ValueTypeEnum.FIXED, FixedDataTypeEnum.NUMBER, 1.0, ValueTypeEnum.FIXED, + FixedDataTypeEnum.NUMBER, 1.000, OperatorEnum.EQ, TRUE }); + this.run(ctxNode, new Object[] { ValueTypeEnum.FIXED, FixedDataTypeEnum.NUMBER, 1.1, ValueTypeEnum.FIXED, + FixedDataTypeEnum.NUMBER, 2.1, OperatorEnum.EQ, FALSE }); + + this.run(ctxNode, new Object[] { ValueTypeEnum.FIXED, FixedDataTypeEnum.NUMBER, 1.1, ValueTypeEnum.FIXED, + FixedDataTypeEnum.NUMBER, 2.1, OperatorEnum.GT, FALSE }); + this.run(ctxNode, new Object[] { ValueTypeEnum.FIXED, FixedDataTypeEnum.NUMBER, 1.1, ValueTypeEnum.FIXED, + FixedDataTypeEnum.NUMBER, 0.1, OperatorEnum.GE, TRUE }); + this.run(ctxNode, new Object[] { ValueTypeEnum.FIXED, FixedDataTypeEnum.NUMBER, 1.1, ValueTypeEnum.FIXED, + FixedDataTypeEnum.NUMBER, 0.1, OperatorEnum.LT, FALSE }); + this.run(ctxNode, new Object[] { ValueTypeEnum.FIXED, FixedDataTypeEnum.NUMBER, 1.1, ValueTypeEnum.FIXED, + FixedDataTypeEnum.NUMBER, 4, OperatorEnum.LT, TRUE }); + + // collection + this.run(ctxNode, new Object[] { ValueTypeEnum.REF, RefDataTypeEnum.ARRAY, "data.list1", ValueTypeEnum.FIXED, + FixedDataTypeEnum.STRING, "2", OperatorEnum.CONTAINS, TRUE }); + this.run(ctxNode, new Object[] { ValueTypeEnum.REF, RefDataTypeEnum.ARRAY, "data.list1", ValueTypeEnum.REF, + RefDataTypeEnum.STRING, "data.m.string_1", OperatorEnum.CONTAINS, TRUE }); + this.run(ctxNode, new Object[] { ValueTypeEnum.REF, RefDataTypeEnum.ARRAY, "data.list1", ValueTypeEnum.REF, + RefDataTypeEnum.STRING, "data.m.string_8", OperatorEnum.CONTAINS, FALSE }); + + this.run(ctxNode, new Object[] { ValueTypeEnum.REF, RefDataTypeEnum.ARRAY, "data.list1", ValueTypeEnum.FIXED, + FixedDataTypeEnum.STRING, "2", OperatorEnum.NOT_CONTAIN, FALSE }); + this.run(ctxNode, new Object[] { ValueTypeEnum.REF, RefDataTypeEnum.ARRAY, "data.list1", ValueTypeEnum.REF, + RefDataTypeEnum.STRING, "data.m.string_1", OperatorEnum.NOT_CONTAIN, FALSE }); + this.run(ctxNode, new Object[] { ValueTypeEnum.REF, RefDataTypeEnum.ARRAY, "data.list1", ValueTypeEnum.REF, + RefDataTypeEnum.STRING, "data.m.string_8", OperatorEnum.NOT_CONTAIN, TRUE }); + + // collection contains any + this.run(ctxNode, new Object[] { ValueTypeEnum.REF, RefDataTypeEnum.ARRAY, "data.list1", ValueTypeEnum.REF, + RefDataTypeEnum.ARRAY, "data.list2", OperatorEnum.CONTAINS_ANY, TRUE }); + this.run(ctxNode, new Object[] { ValueTypeEnum.REF, RefDataTypeEnum.ARRAY, "data.list1", ValueTypeEnum.REF, + RefDataTypeEnum.ARRAY, "data.intList", OperatorEnum.CONTAINS_ANY, FALSE }); + + // Collection + this.run(ctxNode, new Object[] { ValueTypeEnum.REF, RefDataTypeEnum.ARRAY, "data.intList", ValueTypeEnum.FIXED, + FixedDataTypeEnum.STRING, "2", OperatorEnum.CONTAINS, FALSE }); + this.run(ctxNode, new Object[] { ValueTypeEnum.REF, RefDataTypeEnum.ARRAY, "data.intList", ValueTypeEnum.REF, + RefDataTypeEnum.INT, "data.m.int", OperatorEnum.CONTAINS, TRUE }); + this.run(ctxNode, new Object[] { ValueTypeEnum.REF, RefDataTypeEnum.ARRAY, "data.intList", ValueTypeEnum.FIXED, + RefDataTypeEnum.INT, 2, OperatorEnum.CONTAINS, TRUE }); + this.run(ctxNode, new Object[] { ValueTypeEnum.REF, RefDataTypeEnum.ARRAY, "data.intList", ValueTypeEnum.FIXED, + RefDataTypeEnum.INT, 9, OperatorEnum.CONTAINS, FALSE }); + + this.run(ctxNode, new Object[] { ValueTypeEnum.REF, RefDataTypeEnum.ARRAY, "data.intList", ValueTypeEnum.FIXED, + FixedDataTypeEnum.STRING, "2", OperatorEnum.NOT_CONTAIN, TRUE }); + this.run(ctxNode, new Object[] { ValueTypeEnum.REF, RefDataTypeEnum.ARRAY, "data.intList", ValueTypeEnum.REF, + RefDataTypeEnum.INT, "data.m.int", OperatorEnum.NOT_CONTAIN, FALSE }); + this.run(ctxNode, new Object[] { ValueTypeEnum.REF, RefDataTypeEnum.ARRAY, "data.intList", ValueTypeEnum.FIXED, + RefDataTypeEnum.INT, 2, OperatorEnum.NOT_CONTAIN, FALSE }); + this.run(ctxNode, new Object[] { ValueTypeEnum.REF, RefDataTypeEnum.ARRAY, "data.intList", ValueTypeEnum.FIXED, + RefDataTypeEnum.INT, 9, OperatorEnum.NOT_CONTAIN, TRUE }); + + // Collection + this.run(ctxNode, new Object[] { ValueTypeEnum.REF, RefDataTypeEnum.ARRAY, "data.floatList", + ValueTypeEnum.FIXED, FixedDataTypeEnum.STRING, "2", OperatorEnum.CONTAINS, FALSE }); + this.run(ctxNode, new Object[] { ValueTypeEnum.REF, RefDataTypeEnum.ARRAY, "data.floatList", ValueTypeEnum.REF, + RefDataTypeEnum.INT, "data.m.int", OperatorEnum.CONTAINS, FALSE }); + this.run(ctxNode, new Object[] { ValueTypeEnum.REF, RefDataTypeEnum.ARRAY, "data.floatList", + ValueTypeEnum.FIXED, FixedDataTypeEnum.NUMBER, 2, OperatorEnum.CONTAINS, FALSE }); + this.run(ctxNode, new Object[] { ValueTypeEnum.REF, RefDataTypeEnum.ARRAY, "data.floatList", + ValueTypeEnum.FIXED, FixedDataTypeEnum.NUMBER, 2.0, OperatorEnum.CONTAINS, TRUE }); + + // String + this.run(ctxNode, new Object[] { ValueTypeEnum.FIXED, FixedDataTypeEnum.STRING, null, ValueTypeEnum.FIXED, + FixedDataTypeEnum.STRING, null, OperatorEnum.EQ, TRUE }); + this.run(ctxNode, new Object[] { ValueTypeEnum.FIXED, FixedDataTypeEnum.STRING, null, ValueTypeEnum.FIXED, + FixedDataTypeEnum.STRING, null, OperatorEnum.EQ, TRUE }); + this.run(ctxNode, new Object[] { ValueTypeEnum.FIXED, FixedDataTypeEnum.STRING, null, ValueTypeEnum.FIXED, + FixedDataTypeEnum.STRING, "1", OperatorEnum.EQ, FALSE }); + this.run(ctxNode, new Object[] { ValueTypeEnum.FIXED, FixedDataTypeEnum.STRING, "1", ValueTypeEnum.FIXED, + FixedDataTypeEnum.STRING, "1", OperatorEnum.EQ, TRUE }); + this.run(ctxNode, new Object[] { ValueTypeEnum.FIXED, FixedDataTypeEnum.STRING, "1", ValueTypeEnum.FIXED, + FixedDataTypeEnum.STRING, "21", OperatorEnum.EQ, FALSE }); + + this.run(ctxNode, new Object[] { ValueTypeEnum.FIXED, FixedDataTypeEnum.STRING, null, ValueTypeEnum.FIXED, + FixedDataTypeEnum.STRING, null, OperatorEnum.NE, FALSE }); + this.run(ctxNode, new Object[] { ValueTypeEnum.FIXED, FixedDataTypeEnum.STRING, null, ValueTypeEnum.FIXED, + FixedDataTypeEnum.STRING, null, OperatorEnum.NE, FALSE }); + this.run(ctxNode, new Object[] { ValueTypeEnum.FIXED, FixedDataTypeEnum.STRING, null, ValueTypeEnum.FIXED, + FixedDataTypeEnum.STRING, "1", OperatorEnum.NE, TRUE }); + this.run(ctxNode, new Object[] { ValueTypeEnum.FIXED, FixedDataTypeEnum.STRING, "1", ValueTypeEnum.FIXED, + FixedDataTypeEnum.STRING, "1", OperatorEnum.NE, FALSE }); + this.run(ctxNode, new Object[] { ValueTypeEnum.FIXED, FixedDataTypeEnum.STRING, "1", ValueTypeEnum.FIXED, + FixedDataTypeEnum.STRING, "21", OperatorEnum.NE, TRUE }); + + this.run(ctxNode, new Object[] { ValueTypeEnum.FIXED, FixedDataTypeEnum.STRING, "1", ValueTypeEnum.FIXED, + FixedDataTypeEnum.STRING, "21", OperatorEnum.GT, FALSE }); + this.run(ctxNode, new Object[] { ValueTypeEnum.FIXED, FixedDataTypeEnum.STRING, "11", ValueTypeEnum.FIXED, + FixedDataTypeEnum.STRING, "21", OperatorEnum.GT, FALSE }); + this.run(ctxNode, new Object[] { ValueTypeEnum.FIXED, FixedDataTypeEnum.STRING, "11", ValueTypeEnum.FIXED, + FixedDataTypeEnum.STRING, "21", OperatorEnum.GE, FALSE }); + this.run(ctxNode, new Object[] { ValueTypeEnum.FIXED, FixedDataTypeEnum.STRING, "11", ValueTypeEnum.FIXED, + FixedDataTypeEnum.STRING, "21", OperatorEnum.LT, TRUE }); + this.run(ctxNode, new Object[] { ValueTypeEnum.FIXED, FixedDataTypeEnum.STRING, "11", ValueTypeEnum.FIXED, + FixedDataTypeEnum.STRING, "21", OperatorEnum.LE, TRUE }); + + // Is null + this.run(ctxNode, new Object[] { ValueTypeEnum.REF, RefDataTypeEnum.ARRAY, "data.list11111", ValueTypeEnum.REF, + RefDataTypeEnum.STRING, "data.m.string_8", OperatorEnum.IS_NULL, TRUE }); + this.run(ctxNode, new Object[] { ValueTypeEnum.REF, RefDataTypeEnum.STRING, "data.m.string_8", + ValueTypeEnum.REF, RefDataTypeEnum.STRING, "data.m.string_8", OperatorEnum.IS_NULL, FALSE }); + this.run(ctxNode, new Object[] { ValueTypeEnum.REF, RefDataTypeEnum.ARRAY, "data.list11111", null, null, null, + OperatorEnum.IS_NULL, TRUE }); + this.run(ctxNode, new Object[] { ValueTypeEnum.REF, RefDataTypeEnum.STRING, "data.m.string_8", null, null, null, + OperatorEnum.IS_NULL, FALSE }); + + // Is not null + this.run(ctxNode, new Object[] { ValueTypeEnum.REF, RefDataTypeEnum.ARRAY, "data.list11111", ValueTypeEnum.REF, + RefDataTypeEnum.STRING, "data.m.string_8", OperatorEnum.IS_NOT_NULL, FALSE }); + this.run(ctxNode, new Object[] { ValueTypeEnum.REF, RefDataTypeEnum.STRING, "data.m.string_8", + ValueTypeEnum.REF, RefDataTypeEnum.STRING, "data.m.string_8", OperatorEnum.IS_NOT_NULL, TRUE }); + this.run(ctxNode, new Object[] { ValueTypeEnum.REF, RefDataTypeEnum.ARRAY, "data.list11111", null, null, null, + OperatorEnum.IS_NOT_NULL, FALSE }); + this.run(ctxNode, new Object[] { ValueTypeEnum.REF, RefDataTypeEnum.STRING, "data.m.string_8", null, null, null, + OperatorEnum.IS_NOT_NULL, TRUE }); + + // Is Blank + this.run(ctxNode, new Object[] { ValueTypeEnum.REF, RefDataTypeEnum.ARRAY, "data.list11111", ValueTypeEnum.REF, + RefDataTypeEnum.STRING, "data.m.string_8", OperatorEnum.IS_BLANK, TRUE }); + this.run(ctxNode, new Object[] { ValueTypeEnum.REF, RefDataTypeEnum.STRING, "data.m.string_8", + ValueTypeEnum.REF, RefDataTypeEnum.STRING, "data.m.string_8", OperatorEnum.IS_BLANK, FALSE }); + this.run(ctxNode, new Object[] { ValueTypeEnum.REF, RefDataTypeEnum.ARRAY, "data.list11111", null, null, null, + OperatorEnum.IS_BLANK, TRUE }); + this.run(ctxNode, new Object[] { ValueTypeEnum.REF, RefDataTypeEnum.STRING, "data.m.string_8", null, null, null, + OperatorEnum.IS_BLANK, FALSE }); + this.run(ctxNode, new Object[] { ValueTypeEnum.REF, RefDataTypeEnum.STRING, "data.m.string_blank", null, null, + null, OperatorEnum.IS_BLANK, TRUE }); + + // Is not Blank + this.run(ctxNode, new Object[] { ValueTypeEnum.REF, RefDataTypeEnum.ARRAY, "data.list11111", ValueTypeEnum.REF, + RefDataTypeEnum.STRING, "data.m.string_8", OperatorEnum.IS_NOT_BLANK, FALSE }); + this.run(ctxNode, new Object[] { ValueTypeEnum.REF, RefDataTypeEnum.STRING, "data.m.string_8", + ValueTypeEnum.REF, RefDataTypeEnum.STRING, "data.m.string_8", OperatorEnum.IS_NOT_BLANK, TRUE }); + this.run(ctxNode, new Object[] { ValueTypeEnum.REF, RefDataTypeEnum.ARRAY, "data.list11111", null, null, null, + OperatorEnum.IS_NOT_BLANK, FALSE }); + this.run(ctxNode, new Object[] { ValueTypeEnum.REF, RefDataTypeEnum.STRING, "data.m.string_8", null, null, null, + OperatorEnum.IS_NOT_BLANK, TRUE }); + this.run(ctxNode, new Object[] { ValueTypeEnum.REF, RefDataTypeEnum.STRING, "data.m.string_blank", null, null, + null, OperatorEnum.IS_NOT_BLANK, FALSE }); + + // Is empty + this.run(ctxNode, new Object[] { ValueTypeEnum.REF, RefDataTypeEnum.ARRAY, "data.list11111", ValueTypeEnum.REF, + RefDataTypeEnum.STRING, "data.m.string_8", OperatorEnum.IS_EMPTY, TRUE }); + this.run(ctxNode, new Object[] { ValueTypeEnum.REF, RefDataTypeEnum.ARRAY, "data.list1", ValueTypeEnum.REF, + RefDataTypeEnum.STRING, "data.m.string_8", OperatorEnum.IS_EMPTY, FALSE }); + this.run(ctxNode, new Object[] { ValueTypeEnum.REF, RefDataTypeEnum.ARRAY, "data.list11111", null, null, null, + OperatorEnum.IS_EMPTY, TRUE }); + this.run(ctxNode, new Object[] { ValueTypeEnum.REF, RefDataTypeEnum.ARRAY, "data.list1", null, null, null, + OperatorEnum.IS_EMPTY, FALSE }); + this.run(ctxNode, new Object[] { ValueTypeEnum.REF, RefDataTypeEnum.ARRAY, "data.emptyList", null, null, null, + OperatorEnum.IS_EMPTY, TRUE }); + + // Is not empty + this.run(ctxNode, new Object[] { ValueTypeEnum.REF, RefDataTypeEnum.ARRAY, "data.list11111", ValueTypeEnum.REF, + RefDataTypeEnum.STRING, "data.m.string_8", OperatorEnum.IS_NOT_EMPTY, FALSE }); + this.run(ctxNode, new Object[] { ValueTypeEnum.REF, RefDataTypeEnum.ARRAY, "data.list1", ValueTypeEnum.REF, + RefDataTypeEnum.STRING, "data.m.string_8", OperatorEnum.IS_NOT_EMPTY, TRUE }); + this.run(ctxNode, new Object[] { ValueTypeEnum.REF, RefDataTypeEnum.ARRAY, "data.list11111", null, null, null, + OperatorEnum.IS_NOT_EMPTY, FALSE }); + this.run(ctxNode, new Object[] { ValueTypeEnum.REF, RefDataTypeEnum.ARRAY, "data.list1", null, null, null, + OperatorEnum.IS_NOT_EMPTY, TRUE }); + this.run(ctxNode, new Object[] { ValueTypeEnum.REF, RefDataTypeEnum.ARRAY, "data.emptyList", null, null, null, + OperatorEnum.IS_NOT_EMPTY, FALSE }); + + } + + private void run(ONode ctxNode, Object[] item) { + ConditionValue bValue1 = null; + if (item[1] instanceof FixedDataTypeEnum) { + bValue1 = new ConditionValue((ValueTypeEnum) item[0], (FixedDataTypeEnum) item[1], item[2]); + } else { + bValue1 = new ConditionValue((ValueTypeEnum) item[0], (RefDataTypeEnum) item[1], item[2]); + } + ConditionValue bValue2 = null; + if (item[3] != null) { + if (item[4] instanceof FixedDataTypeEnum) { + bValue2 = new ConditionValue((ValueTypeEnum) item[3], (FixedDataTypeEnum) item[4], item[5]); + } else { + bValue2 = new ConditionValue((ValueTypeEnum) item[3], (RefDataTypeEnum) item[4], item[5]); + } + } + Condition c = new Condition(null, bValue1, (OperatorEnum) item[6], bValue2); + boolean rs = c.exec(ctxNode); + boolean expected = (boolean) item[7]; + assertEquals(expected, rs); + } + +} \ No newline at end of file diff --git a/fizz-core/src/test/java/we/fizz/input/PathMappingTests.java b/fizz-core/src/test/java/we/fizz/input/PathMappingTests.java index 770ba26..4fd6475 100644 --- a/fizz-core/src/test/java/we/fizz/input/PathMappingTests.java +++ b/fizz-core/src/test/java/we/fizz/input/PathMappingTests.java @@ -163,4 +163,31 @@ class PathMappingTests { } + @Test + void testArray() { + ONode ctxNode = ONode.load(new HashMap()); + + Map m = new HashMap<>(); + m.put("a", "1"); + m.put("b", "1"); + + List list = new ArrayList<>(); + list.add("0"); + list.add("1"); + list.add("2"); + list.add("3"); + list.add("4"); + + PathMapping.setByPath(ctxNode, "data.m", m, true); + + PathMapping.setByPath(ctxNode, "data.arr", list, true); + + Object abcVal1 = PathMapping.getValueByPath(ctxNode, "data.arr[0]"); + assertEquals("0", (String)abcVal1); + Object abcVal2 = PathMapping.getValueByPath(ctxNode, "data.arr[-1]"); + assertEquals("4", (String)abcVal2); + System.out.println(abcVal1); + System.out.println(abcVal2); + } + } \ No newline at end of file From 9541ccfae479dcf89af3e554ac1dec99284d3cbf Mon Sep 17 00:00:00 2001 From: Francis Dong Date: Thu, 8 Jul 2021 12:01:27 +0800 Subject: [PATCH 23/28] Support default value in jsonpath mapping #216 --- .../main/java/we/fizz/input/PathMapping.java | 56 +++++++++++++++---- .../java/we/fizz/input/PathMappingTests.java | 4 +- 2 files changed, 48 insertions(+), 12 deletions(-) diff --git a/fizz-core/src/main/java/we/fizz/input/PathMapping.java b/fizz-core/src/main/java/we/fizz/input/PathMapping.java index 2b0c6f8..91b1a92 100644 --- a/fizz-core/src/main/java/we/fizz/input/PathMapping.java +++ b/fizz-core/src/main/java/we/fizz/input/PathMapping.java @@ -135,39 +135,73 @@ public class PathMapping { String starEntryKey = null; for (Entry entry : rs.entrySet()) { - String path = handlePath(entry.getValue()); - ONode val = select(ctxNode, path); - Object obj = val; - if (val != null && types.containsKey(entry.getKey())) { + String path = entry.getValue(); + String p = path; + String defaultValue = null; + if (path.indexOf("|") != -1) { + p = path.substring(0, path.indexOf("|")); + defaultValue = path.substring(path.indexOf("|") + 1); + } + ONode val = select(ctxNode, handlePath(p)); + + Object obj = null; + if (val != null && !val.isNull()) { + obj = val; + } else { + obj = defaultValue; + } + if (obj != null && types.containsKey(entry.getKey())) { switch (types.get(entry.getKey())) { case "Integer": case "int": { - obj = val.val().isNull() ? null : val.val().getInt(); + if (obj instanceof ONode) { + obj = ((ONode) obj).val().getInt(); + } else { + obj = Integer.valueOf(obj.toString()); + } break; } case "Boolean": case "boolean": { - obj = val.val().isNull() ? null : val.val().getBoolean(); + if (obj instanceof ONode) { + obj = ((ONode) obj).val().getBoolean(); + } else { + obj = Boolean.valueOf(obj.toString()); + } break; } case "Float": case "float": { - obj = val.val().isNull() ? null : val.val().getFloat(); + if (obj instanceof ONode) { + obj = ((ONode) obj).val().getFloat(); + } else { + obj = Float.valueOf(obj.toString()); + } break; } case "Double": case "double": { - obj = val.val().isNull() ? null : val.val().getDouble(); + if (obj instanceof ONode) { + obj = ((ONode) obj).val().getDouble(); + } else { + obj = Double.valueOf(obj.toString()); + } break; } case "String": case "string": { - obj = val.val().isNull() ? null : val.val().getString(); + if (obj instanceof ONode) { + obj = ((ONode) obj).val().getString(); + } break; } case "Long": case "long": { - obj = val.val().isNull() ? null : val.val().getLong(); + if (obj instanceof ONode) { + obj = ((ONode) obj).val().getLong(); + } else { + obj = Long.valueOf(obj.toString()); + } break; } } @@ -175,7 +209,7 @@ public class PathMapping { if (CommonConstants.WILDCARD_STAR.equals(entry.getKey())) { starValObj = obj; starEntryKey = entry.getKey(); - }else { + } else { setByPath(target, entry.getKey(), obj, supportMultiLevels); } } diff --git a/fizz-core/src/test/java/we/fizz/input/PathMappingTests.java b/fizz-core/src/test/java/we/fizz/input/PathMappingTests.java index 4fd6475..4936d2b 100644 --- a/fizz-core/src/test/java/we/fizz/input/PathMappingTests.java +++ b/fizz-core/src/test/java/we/fizz/input/PathMappingTests.java @@ -14,6 +14,9 @@ import org.junit.jupiter.api.Assertions; import org.junit.jupiter.api.Test; import org.noear.snack.ONode; +import reactor.core.publisher.Flux; +import reactor.core.publisher.Mono; + class PathMappingTests { @Test @@ -159,7 +162,6 @@ class PathMappingTests { assertEquals("1", (String)abcVal1); assertEquals("123456", (String)abcVal2); - } From 5aa53fec9b5e4b7441a57a4e22d55483a88c7cdd Mon Sep 17 00:00:00 2001 From: hongqiaowei Date: Fri, 16 Jul 2021 15:52:57 +0800 Subject: [PATCH 24/28] Release 2.2.0-beta10 --- fizz-bootstrap/pom.xml | 2 +- fizz-common/pom.xml | 2 +- fizz-core/pom.xml | 2 +- fizz-plugin/pom.xml | 2 +- fizz-spring-boot-starter/pom.xml | 2 +- pom.xml | 2 +- 6 files changed, 6 insertions(+), 6 deletions(-) diff --git a/fizz-bootstrap/pom.xml b/fizz-bootstrap/pom.xml index 8db531c..fd36061 100644 --- a/fizz-bootstrap/pom.xml +++ b/fizz-bootstrap/pom.xml @@ -12,7 +12,7 @@ com.fizzgate fizz-bootstrap - 2.2.0-beta9 + 2.2.0-beta10 1.8 diff --git a/fizz-common/pom.xml b/fizz-common/pom.xml index 6593347..24effa2 100644 --- a/fizz-common/pom.xml +++ b/fizz-common/pom.xml @@ -5,7 +5,7 @@ fizz-gateway-community com.fizzgate - 2.2.0-beta9 + 2.2.0-beta10 ../pom.xml 4.0.0 diff --git a/fizz-core/pom.xml b/fizz-core/pom.xml index c70b2de..fbcde42 100644 --- a/fizz-core/pom.xml +++ b/fizz-core/pom.xml @@ -5,7 +5,7 @@ fizz-gateway-community com.fizzgate - 2.2.0-beta9 + 2.2.0-beta10 ../pom.xml 4.0.0 diff --git a/fizz-plugin/pom.xml b/fizz-plugin/pom.xml index 995f2c8..d9fa6e0 100644 --- a/fizz-plugin/pom.xml +++ b/fizz-plugin/pom.xml @@ -5,7 +5,7 @@ fizz-gateway-community com.fizzgate - 2.2.0-beta9 + 2.2.0-beta10 ../pom.xml 4.0.0 diff --git a/fizz-spring-boot-starter/pom.xml b/fizz-spring-boot-starter/pom.xml index 41986b2..a0285c6 100644 --- a/fizz-spring-boot-starter/pom.xml +++ b/fizz-spring-boot-starter/pom.xml @@ -5,7 +5,7 @@ fizz-gateway-community com.fizzgate - 2.2.0-beta9 + 2.2.0-beta10 ../pom.xml 4.0.0 diff --git a/pom.xml b/pom.xml index be1fb34..b574df1 100644 --- a/pom.xml +++ b/pom.xml @@ -31,7 +31,7 @@ fizz-gateway-community ${project.artifactId} fizz gateway community - 2.2.0-beta9 + 2.2.0-beta10 pom fizz-common From 60f2122b1414fd2eb192465c3766254fc950a313 Mon Sep 17 00:00:00 2001 From: Francis Dong Date: Fri, 16 Jul 2021 17:13:06 +0800 Subject: [PATCH 25/28] Support configuring multiple values in http header/query parameter/form-data #246 --- .../src/main/java/we/util/MapUtil.java | 152 ++++++++--- .../filter/FilterExceptionHandlerConfig.java | 14 + .../fizz/exception/FizzRuntimeException.java | 26 ++ .../main/java/we/fizz/input/PathMapping.java | 254 +++++++++++------- .../input/extension/request/RequestInput.java | 12 +- 5 files changed, 326 insertions(+), 132 deletions(-) diff --git a/fizz-common/src/main/java/we/util/MapUtil.java b/fizz-common/src/main/java/we/util/MapUtil.java index 5d3ea5b..c25e2f4 100644 --- a/fizz-common/src/main/java/we/util/MapUtil.java +++ b/fizz-common/src/main/java/we/util/MapUtil.java @@ -17,6 +17,7 @@ package we.util; import java.util.ArrayList; +import java.util.Collection; import java.util.HashMap; import java.util.List; import java.util.Map; @@ -36,6 +37,10 @@ import org.springframework.util.MultiValueMap; */ public class MapUtil { + private static final String KEY = "key"; + + private static final String VALUE = "value"; + public static HttpHeaders toHttpHeaders(Map params) { HttpHeaders headers = new HttpHeaders(); @@ -65,7 +70,6 @@ public class MapUtil { return headers; } - public static MultiValueMap toMultiValueMap(Map params) { MultiValueMap mvmap = new LinkedMultiValueMap<>(); @@ -96,7 +100,7 @@ public class MapUtil { return mvmap; } - + public static MultiValueMap toMultipartDataMap(Map params) { MultiValueMap mvmap = new LinkedMultiValueMap<>(); if (params == null || params.isEmpty()) { @@ -124,15 +128,16 @@ public class MapUtil { return mvmap; } - /** * Extract form data from multipart map exclude file + * * @param params * @param fileKeyPrefix - * @param filePartMap Map + * @param filePartMap Map * @return */ - public static Map extractFormData(MultiValueMap params, String fileKeyPrefix, Map filePartMap) { + public static Map extractFormData(MultiValueMap params, String fileKeyPrefix, + Map filePartMap) { HashMap m = new HashMap<>(); if (params == null || params.isEmpty()) { return m; @@ -148,7 +153,7 @@ public class MapUtil { formFieldValues.add(p.value()); } else if (part instanceof FilePart) { FilePart fp = (FilePart) part; - String k = fileKeyPrefix + UUIDUtil.getUUID() + "-" + fp.filename(); + String k = fileKeyPrefix + UUIDUtil.getUUID() + "-" + fp.filename(); formFieldValues.add(k); filePartMap.put(k, fp); } @@ -171,26 +176,28 @@ public class MapUtil { } return m; } - + /** * Replace file field with FilePart object + * * @param params * @param fileKeyPrefix * @param filePartMap */ - public static void replaceWithFilePart(MultiValueMap params, String fileKeyPrefix, Map filePartMap) { + public static void replaceWithFilePart(MultiValueMap params, String fileKeyPrefix, + Map filePartMap) { if (params == null || params.isEmpty() || filePartMap == null || filePartMap.isEmpty()) { return; } - + for (Entry> entry : params.entrySet()) { List list = entry.getValue(); if (list != null && list.size() > 0) { - List newlist = new ArrayList<>(); + List newlist = new ArrayList<>(); for (int i = 0; i < list.size(); i++) { if (list.get(i).toString().startsWith(fileKeyPrefix)) { newlist.add(filePartMap.get(list.get(i).toString())); - }else { + } else { newlist.add(list.get(i)); } } @@ -198,7 +205,7 @@ public class MapUtil { } } } - + public static Map toHashMap(MultiValueMap params) { HashMap m = new HashMap<>(); @@ -219,7 +226,7 @@ public class MapUtil { return m; } - + public static Map headerToHashMap(HttpHeaders headers) { HashMap m = new HashMap<>(); @@ -240,7 +247,7 @@ public class MapUtil { return m; } - + public static Map upperCaseKey(Map m) { HashMap rs = new HashMap<>(); @@ -254,79 +261,96 @@ public class MapUtil { return rs; } + + public static MultiValueMap upperCaseKey(MultiValueMap m) { + MultiValueMap rs = new LinkedMultiValueMap<>(); + + if (m == null || m.isEmpty()) { + return rs; + } + + for (Entry> entry : m.entrySet()) { + rs.put(entry.getKey().toUpperCase(), entry.getValue()); + } + + return rs; + } /** * Set value by path,support multiple levels,eg:a.b.c
* Do NOT use this method if field name contains a dot
- * @param data + * + * @param data * @param path * @param value */ @SuppressWarnings("unchecked") public static void set(Map data, String path, Object value) { String[] fields = path.split("\\."); - if(fields.length < 2) { + if (fields.length < 2) { data.put(path, value); - }else { + } else { Map next = data; for (int i = 0; i < fields.length - 1; i++) { Map val = (Map) next.get(fields[i]); - if(val == null) { + if (val == null) { val = new HashMap<>(); next.put(fields[i], val); } - if(i == fields.length - 2) { - val.put(fields[i+1], value); + if (i == fields.length - 2) { + val.put(fields[i + 1], value); break; } next = val; } } } - + /** * Get value by path, support multiple levels,eg:a.b.c
* Do NOT use this method if field name contains a dot
+ * * @param data * @param path * @return */ public static Object get(Map data, String path) { String[] fields = path.split("\\."); - if(fields.length < 2) { + if (fields.length < 2) { return data.get(path); - }else { + } else { Map next = data; for (int i = 0; i < fields.length - 1; i++) { - if(!(next.get(fields[i]) instanceof Map)) { + if (!(next.get(fields[i]) instanceof Map)) { return null; } Map val = (Map) next.get(fields[i]); - if(val == null) { + if (val == null) { return null; } - if(i == fields.length - 2) { - return val.get(fields[i+1]); + if (i == fields.length - 2) { + return val.get(fields[i + 1]); } next = val; } } return null; } - + /** * Merge maps, merge src to target + * * @param target * @param src * @return */ @SuppressWarnings("unchecked") public static Map merge(Map target, Map src) { - if(src == null || src.isEmpty()) { + if (src == null || src.isEmpty()) { return target; } src.forEach((key, value) -> { - if(value != null) { + if (value != null) { target.merge(key, value, (oldValue, newValue) -> { if (oldValue instanceof Map && newValue instanceof Map) { oldValue = merge((Map) oldValue, (Map) newValue); @@ -338,5 +362,71 @@ public class MapUtil { }); return target; } - + + /** + * Convert list to map and merge multiple values
+ * Example:
+ * List as:
+ * [{"key": "abc", "value": "aaa"},{"key": "abc", "value": "xyz"},{"key": + * "a123", "value": 666}]
+ * Merge Result:
+ * {"abc": ["aaa","xyz"], "a123": 666}
+ * + * @param obj + * @return + */ + @SuppressWarnings("unchecked") + public static Map list2Map(Object obj) { + // Compatible with older version configuration + if (obj instanceof Map) { + return (Map) obj; + } + if (obj instanceof List) { + Map rs = new HashMap<>(); + List> list = (List>) obj; + if (list == null || list.size() == 0) { + return rs; + } + for (Map m : list) { + String k = m.get(KEY).toString(); + Object v = m.get(VALUE); + if (rs.containsKey(k)) { + List vals = null; + if (rs.get(k) instanceof List) { + vals = (List) rs.get(k); + } else { + vals = new ArrayList<>(); + vals.add(rs.get(k)); + } + vals.add(v); + rs.put(k, vals); + } else { + rs.put(k, v); + } + } + return rs; + } + return null; + } + + /** + * Convert list to MultiValueMap
+ * List format example:
+ * [{"key": "abc", "value": "aaa"},{"key": "abc", "value": "xyz"},,{"key": + * "a123", "value": 666}]
+ * + * @param list + * @return + */ + public static MultiValueMap listToMultiValueMap(List> list) { + MultiValueMap mvmap = new LinkedMultiValueMap<>(); + if (list == null || list.size() == 0) { + return mvmap; + } + for (Map m : list) { + mvmap.add(m.get(KEY).toString(), m.get(VALUE)); + } + return mvmap; + } + } diff --git a/fizz-core/src/main/java/we/filter/FilterExceptionHandlerConfig.java b/fizz-core/src/main/java/we/filter/FilterExceptionHandlerConfig.java index aa48502..71d9d10 100644 --- a/fizz-core/src/main/java/we/filter/FilterExceptionHandlerConfig.java +++ b/fizz-core/src/main/java/we/filter/FilterExceptionHandlerConfig.java @@ -32,6 +32,7 @@ import reactor.core.publisher.Mono; import we.exception.ExecuteScriptException; import we.exception.RedirectException; import we.exception.StopAndResponseException; +import we.fizz.exception.FizzRuntimeException; import we.flume.clients.log4j2appender.LogService; import we.legacy.RespEntity; import we.util.JacksonUtils; @@ -81,6 +82,19 @@ public class FilterExceptionHandlerConfig { return resp.writeWith(Mono.just(resp.bufferFactory().wrap(rs.toString().getBytes()))); } } + if (t instanceof FizzRuntimeException) { + FizzRuntimeException ex = (FizzRuntimeException) t; + resp.getHeaders().add(HttpHeaders.CONTENT_TYPE, MediaType.APPLICATION_JSON_VALUE); + RespEntity rs = null; + String reqId = exchange.getRequest().getId(); + if (ex.getStepContext() != null && ex.getStepContext().returnContext()) { + rs = new RespEntity(HttpStatus.INTERNAL_SERVER_ERROR.value(), t.getMessage(), reqId, ex.getStepContext()); + return resp.writeWith(Mono.just(resp.bufferFactory().wrap(JacksonUtils.writeValueAsString(rs).getBytes()))); + } else { + rs = new RespEntity(HttpStatus.INTERNAL_SERVER_ERROR.value(), t.getMessage(), reqId); + return resp.writeWith(Mono.just(resp.bufferFactory().wrap(rs.toString().getBytes()))); + } + } Mono vm; Object fc = exchange.getAttributes().get(WebUtils.FILTER_CONTEXT); if (fc == null) { // t came from flow control filter diff --git a/fizz-core/src/main/java/we/fizz/exception/FizzRuntimeException.java b/fizz-core/src/main/java/we/fizz/exception/FizzRuntimeException.java index 92643f8..929fe1c 100644 --- a/fizz-core/src/main/java/we/fizz/exception/FizzRuntimeException.java +++ b/fizz-core/src/main/java/we/fizz/exception/FizzRuntimeException.java @@ -1,11 +1,37 @@ package we.fizz.exception; +import we.fizz.StepContext; + public class FizzRuntimeException extends RuntimeException { + + private StepContext stepContext; + public FizzRuntimeException(String message) { super(message); } public FizzRuntimeException(String message, Throwable cause) { super(message, cause); + this.setStackTrace(cause.getStackTrace()); } + + public FizzRuntimeException(String message, StepContext stepContext) { + super(message); + this.stepContext = stepContext; + } + + public FizzRuntimeException(String message, Throwable cause, StepContext stepContext) { + super(message, cause); + this.setStackTrace(cause.getStackTrace()); + this.stepContext = stepContext; + } + + public StepContext getStepContext() { + return stepContext; + } + + public void setStepContext(StepContext stepContext) { + this.stepContext = stepContext; + } + } diff --git a/fizz-core/src/main/java/we/fizz/input/PathMapping.java b/fizz-core/src/main/java/we/fizz/input/PathMapping.java index 91b1a92..a1d22ce 100644 --- a/fizz-core/src/main/java/we/fizz/input/PathMapping.java +++ b/fizz-core/src/main/java/we/fizz/input/PathMapping.java @@ -19,13 +19,13 @@ package we.fizz.input; import java.util.*; import java.util.Map.Entry; -import java.util.Optional; import java.util.stream.Collectors; import org.noear.snack.ONode; import we.constants.CommonConstants; import we.fizz.StepContext; +import we.fizz.exception.FizzRuntimeException; import we.util.MapUtil; /** @@ -105,14 +105,15 @@ public class PathMapping { return target.toObject(Map.class); } + @SuppressWarnings("unchecked") public static ONode transform(ONode ctxNode, Map rules, boolean supportMultiLevels) { ONode target = ONode.load(new HashMap()); if (rules.isEmpty()) { return target; } - Map rs = new HashMap<>(); - Map types = new HashMap<>(); + Map rs = new HashMap<>(); + Map types = new HashMap<>(); for (Entry entry : rules.entrySet()) { if (entry.getValue() instanceof String) { String val = (String) entry.getValue(); @@ -123,6 +124,25 @@ public class PathMapping { } else { rs.put(entry.getKey(), val); } + } else if (entry.getValue() instanceof List) { + List values = (List) entry.getValue(); + List vList = new ArrayList<>(); + List tList = new ArrayList<>(); + for (Object v : values) { + if (v instanceof String) { + String val = (String) v; + Optional optType = typeList.stream().filter(s -> val.startsWith(s + " ")).findFirst(); + if (optType.isPresent()) { + vList.add(val.substring(optType.get().length() + 1)); + tList.add(optType.get()); + } else { + vList.add(val); + tList.add(null); + } + } + } + rs.put(entry.getKey(), vList); + types.put(entry.getKey(), tList); } } @@ -134,8 +154,46 @@ public class PathMapping { Object starValObj = null; String starEntryKey = null; - for (Entry entry : rs.entrySet()) { - String path = entry.getValue(); + for (Entry entry : rs.entrySet()) { + if (entry.getValue() instanceof String) { + String path = (String) entry.getValue(); + String type = (String) types.get(entry.getKey()); + Object obj = getRefValue(ctxNode, type, path); + if (CommonConstants.WILDCARD_STAR.equals(entry.getKey())) { + starValObj = obj; + starEntryKey = entry.getKey(); + } else { + setByPath(target, entry.getKey(), obj, supportMultiLevels); + } + } else if (entry.getValue() instanceof List) { + List refs = (List) entry.getValue(); + List tList = (List) types.get(entry.getKey()); + List refValList = new ArrayList<>(); + for (int i = 0; i < refs.size(); i++) { + String path = refs.get(i); + String type = tList.get(i); + Object obj = getRefValue(ctxNode, type, path); + // Only header form-data and query Parameter support multiple values, merge result into + // one a list + if (obj instanceof List) { + refValList.addAll((List) obj); + } else { + refValList.add(obj); + } + } + setByPath(target, entry.getKey(), refValList, supportMultiLevels); + } + } + + if(starEntryKey != null) { + setByPath(target, starEntryKey, starValObj, supportMultiLevels); + } + return target; + } + + private static Object getRefValue(ONode ctxNode, String type, String path) { + Object obj = null; + try { String p = path; String defaultValue = null; if (path.indexOf("|") != -1) { @@ -143,82 +201,77 @@ public class PathMapping { defaultValue = path.substring(path.indexOf("|") + 1); } ONode val = select(ctxNode, handlePath(p)); - - Object obj = null; if (val != null && !val.isNull()) { obj = val; } else { obj = defaultValue; } - if (obj != null && types.containsKey(entry.getKey())) { - switch (types.get(entry.getKey())) { - case "Integer": - case "int": { - if (obj instanceof ONode) { - obj = ((ONode) obj).val().getInt(); - } else { - obj = Integer.valueOf(obj.toString()); - } - break; - } - case "Boolean": - case "boolean": { - if (obj instanceof ONode) { - obj = ((ONode) obj).val().getBoolean(); - } else { - obj = Boolean.valueOf(obj.toString()); - } - break; - } - case "Float": - case "float": { - if (obj instanceof ONode) { - obj = ((ONode) obj).val().getFloat(); - } else { - obj = Float.valueOf(obj.toString()); - } - break; - } - case "Double": - case "double": { - if (obj instanceof ONode) { - obj = ((ONode) obj).val().getDouble(); - } else { - obj = Double.valueOf(obj.toString()); - } - break; - } - case "String": - case "string": { - if (obj instanceof ONode) { - obj = ((ONode) obj).val().getString(); - } - break; - } - case "Long": - case "long": { - if (obj instanceof ONode) { - obj = ((ONode) obj).val().getLong(); - } else { - obj = Long.valueOf(obj.toString()); - } - break; - } - } + if (obj != null && type != null) { + obj = cast(obj, type); } - if (CommonConstants.WILDCARD_STAR.equals(entry.getKey())) { - starValObj = obj; - starEntryKey = entry.getKey(); + } catch (Exception e) { + e.printStackTrace(); + throw new FizzRuntimeException(String.format("path mapping errer: %s , path mapping data: %s %s", e.getMessage(), type, path), e); + } + return obj; + } + + private static Object cast(Object obj, String type) { + switch (type) { + case "Integer": + case "int": { + if (obj instanceof ONode) { + obj = ((ONode) obj).val().getInt(); } else { - setByPath(target, entry.getKey(), obj, supportMultiLevels); + obj = Integer.valueOf(obj.toString()); } + break; } - - if(starEntryKey != null) { - setByPath(target, starEntryKey, starValObj, supportMultiLevels); + case "Boolean": + case "boolean": { + if (obj instanceof ONode) { + obj = ((ONode) obj).val().getBoolean(); + } else { + obj = Boolean.valueOf(obj.toString()); + } + break; } - - return target; + case "Float": + case "float": { + if (obj instanceof ONode) { + obj = ((ONode) obj).val().getFloat(); + } else { + obj = Float.valueOf(obj.toString()); + } + break; + } + case "Double": + case "double": { + if (obj instanceof ONode) { + obj = ((ONode) obj).val().getDouble(); + } else { + obj = Double.valueOf(obj.toString()); + } + break; + } + case "String": + case "string": { + if (obj instanceof ONode) { + obj = ((ONode) obj).val().getString(); + } + break; + } + case "Long": + case "long": { + if (obj instanceof ONode) { + obj = ((ONode) obj).val().getLong(); + } else { + obj = Long.valueOf(obj.toString()); + } + break; + } + } + return obj; } public static ONode select(ONode ctxNode, String path) { @@ -270,7 +323,14 @@ public class PathMapping { } Map rs = new HashMap<>(); for (Entry entry : rules.entrySet()) { - if (!(entry.getValue() instanceof String)) { + if (entry.getValue() instanceof List) { + List values = (List) entry.getValue(); + for (Object v : values) { + if (!(v instanceof String)) { + rs.put(entry.getKey(), v); + } + } + } else if (!(entry.getValue() instanceof String) && entry.getValue() instanceof Map) { rs.put(entry.getKey(), entry.getValue()); } } @@ -418,31 +478,35 @@ public class PathMapping { */ public static Map transform(ONode ctxNode, StepContext stepContext, Map fixed, Map mappingRules, boolean supportMultiLevels) { - if (fixed != null && fixed.containsKey(CommonConstants.WILDCARD_TILDE)) { - Object val = fixed.get(CommonConstants.WILDCARD_TILDE); - fixed = new HashMap<>(); - fixed.put(CommonConstants.WILDCARD_TILDE, val); - } - if (mappingRules != null && mappingRules.containsKey(CommonConstants.WILDCARD_TILDE)) { - Object val = mappingRules.get(CommonConstants.WILDCARD_TILDE); - mappingRules = new HashMap<>(); - mappingRules.put(CommonConstants.WILDCARD_TILDE, val); - } - Map result = new HashMap<>(); - if (fixed != null) { - result.putAll((Map) convertPath(fixed, supportMultiLevels)); - } - if (mappingRules != null) { - // 路径映射 - ONode target = PathMapping.transform(ctxNode, mappingRules, supportMultiLevels); - // 脚本转换 - Map scriptRules = PathMapping.getScriptRules(mappingRules); - Map scriptResult = ScriptHelper.executeScripts(target, scriptRules, ctxNode, stepContext, supportMultiLevels); - if (scriptResult != null && !scriptResult.isEmpty()) { - result = MapUtil.merge(result, scriptResult); + try { + if (fixed != null && fixed.containsKey(CommonConstants.WILDCARD_TILDE)) { + Object val = fixed.get(CommonConstants.WILDCARD_TILDE); + fixed = new HashMap<>(); + fixed.put(CommonConstants.WILDCARD_TILDE, val); } + if (mappingRules != null && mappingRules.containsKey(CommonConstants.WILDCARD_TILDE)) { + Object val = mappingRules.get(CommonConstants.WILDCARD_TILDE); + mappingRules = new HashMap<>(); + mappingRules.put(CommonConstants.WILDCARD_TILDE, val); + } + Map result = new HashMap<>(); + if (fixed != null) { + result.putAll((Map) convertPath(fixed, supportMultiLevels)); + } + if (mappingRules != null) { + // 路径映射 + ONode target = transform(ctxNode, mappingRules, supportMultiLevels); + // 脚本转换 + Map scriptRules = getScriptRules(mappingRules); + Map scriptResult = ScriptHelper.executeScripts(target, scriptRules, ctxNode, stepContext, supportMultiLevels); + if (scriptResult != null && !scriptResult.isEmpty()) { + result = MapUtil.merge(result, scriptResult); + } + } + return result; + }catch(FizzRuntimeException e) { + throw new FizzRuntimeException(e.getMessage(), e, stepContext); } - return result; } public static Map convertPath(Map fixed, boolean supportMultiLevels) { diff --git a/fizz-core/src/main/java/we/fizz/input/extension/request/RequestInput.java b/fizz-core/src/main/java/we/fizz/input/extension/request/RequestInput.java index d848fd7..762714b 100644 --- a/fizz-core/src/main/java/we/fizz/input/extension/request/RequestInput.java +++ b/fizz-core/src/main/java/we/fizz/input/extension/request/RequestInput.java @@ -143,8 +143,8 @@ public class RequestInput extends RPCInput implements IInput{ // headers Map headers = PathMapping.transform(ctxNode, stepContext, - MapUtil.upperCaseKey((Map) requestMapping.get("fixedHeaders")), - MapUtil.upperCaseKey((Map) requestMapping.get("headers")), false); + MapUtil.upperCaseKey(MapUtil.list2Map(requestMapping.get("fixedHeaders"))), + MapUtil.upperCaseKey(MapUtil.list2Map(requestMapping.get("headers"))), false); if (headers.containsKey(CommonConstants.WILDCARD_TILDE) && headers.get(CommonConstants.WILDCARD_TILDE) instanceof Map) { request.put("headers", headers.get(CommonConstants.WILDCARD_TILDE)); @@ -154,8 +154,8 @@ public class RequestInput extends RPCInput implements IInput{ // params params.putAll(PathMapping.transform(ctxNode, stepContext, - (Map) requestMapping.get("fixedParams"), - (Map) requestMapping.get("params"), false)); + MapUtil.list2Map(requestMapping.get("fixedParams")), + MapUtil.list2Map(requestMapping.get("params")), false)); if (params.containsKey(CommonConstants.WILDCARD_TILDE) && params.get(CommonConstants.WILDCARD_TILDE) instanceof Map) { request.put("params", params.get(CommonConstants.WILDCARD_TILDE)); @@ -170,8 +170,8 @@ public class RequestInput extends RPCInput implements IInput{ supportMultiLevels = false; } Map body = PathMapping.transform(ctxNode, stepContext, - (Map) requestMapping.get("fixedBody"), - (Map) requestMapping.get("body"), supportMultiLevels); + MapUtil.list2Map(requestMapping.get("fixedBody")), + MapUtil.list2Map(requestMapping.get("body")), supportMultiLevels); if (body.containsKey(CommonConstants.WILDCARD_TILDE)) { request.put("body", body.get(CommonConstants.WILDCARD_TILDE)); } else { From 9c9cd323dc41488e7bc4ed957e22b2cea630e44a Mon Sep 17 00:00:00 2001 From: Francis Dong Date: Fri, 16 Jul 2021 17:24:51 +0800 Subject: [PATCH 26/28] Support process control in aggregation #215 --- fizz-bootstrap/js/common.js | 30 ++++ fizz-bootstrap/js/context.js | 74 +++++++++- .../src/main/resources/js/common.js | 30 ++++ fizz-core/src/main/java/we/fizz/Pipeline.java | 10 +- fizz-core/src/main/java/we/fizz/Step.java | 3 +- .../src/main/java/we/fizz/StepContext.java | 50 ++++++- .../src/main/java/we/fizz/StepResponse.java | 8 ++ .../we/fizz/component/ComponentHelper.java | 54 +------ .../java/we/fizz/component/circle/Circle.java | 132 ++++++++++++------ .../fizz/component/condition/Condition.java | 5 +- .../java/we/fizz/component/CircleTests.java | 17 ++- 11 files changed, 301 insertions(+), 112 deletions(-) diff --git a/fizz-bootstrap/js/common.js b/fizz-bootstrap/js/common.js index 9e52cb2..cccb334 100644 --- a/fizz-bootstrap/js/common.js +++ b/fizz-bootstrap/js/common.js @@ -190,6 +190,36 @@ var common = { } var result = ctx[stepName]['result'] || {}; return field ? result[field] : result; + }, + + /** + * 获取步骤循环结果 + * @param {*} ctx 上下文 【必填】 + * @param {*} stepName 步骤名【必填】 + */ + getStepCircle: function (ctx, stepName){ + if(!ctx || !stepName || !ctx[stepName]){ + return null; + } + // 返回循环结果数组 + return ctx[stepName]['circle']; + }, + + /** + * 获取请求的循环结果 + * @param {*} ctx 上下文 【必填】 + * @param {*} stepName 步骤名【必填】 + */ + getRequestCircle: function (ctx, stepName, requestName){ + if(!ctx || !stepName || !requestName){ + return null; + } + if(!ctx[stepName] || !ctx[stepName]['requests'] || !ctx[stepName]['requests'][requestName] || + !ctx[stepName]['requests'][requestName]['request']){ + return null; + } + // 返回循环结果数组 + return ctx[stepName]['requests'][requestName]['circle']; } /* *********** step request end ************ */ diff --git a/fizz-bootstrap/js/context.js b/fizz-bootstrap/js/context.js index 0a31511..42cadf7 100644 --- a/fizz-bootstrap/js/context.js +++ b/fizz-bootstrap/js/context.js @@ -46,7 +46,34 @@ var context = { response: { headers: {}, body: {} - } + }, + // 请求循环组件当前循环对象 + item: null, + // 请求循环组件当前循环对象的下标 + index: null, + // 请求循环的结果 + circle: [{ + // 循环对象 + item: null, + // 循环对象的下标 + index: null, + // 请求相关参数 + request:{ + url: "", + method: "GET/POST", + headers: {}, + body: {} + }, + // 根据转换规则转换后的接口响应 + response: { + headers: {}, + body: {} + } + }], + // 条件组件的执行结果 + conditionResults: [ + {'我的条件1': true} + ] }, // 接口2 request2: { @@ -59,13 +86,52 @@ var context = { response: { headers: {}, body: {} - } + }, + // 请求循环组件当前循环对象 + item: null, + // 请求循环组件当前循环对象的下标 + index: null, + // 请求循环的结果 + circle: [{ + // 循环对象 + item: null, + // 循环对象的下标 + index: null, + // 请求相关参数 + request:{ + url: "", + method: "GET/POST", + headers: {}, + body: {} + }, + // 根据转换规则转换后的接口响应 + response: { + headers: {}, + body: {} + } + }], + // 条件组件的执行结果 + conditionResults: [ + {'我的条件1': true} + ] } //... }, // 步骤结果 - result: {} - + result: {}, + // 步骤循环组件当前循环对象 + item: null, + // 步骤循环组件当前循环对象的下标 + index: null, + // 步骤循环的结果 + circle:[{ + // 循环对象 + item: null, + // 循环对象的下标 + index: null, + // 步骤结果 + result: {} + }] } } \ No newline at end of file diff --git a/fizz-bootstrap/src/main/resources/js/common.js b/fizz-bootstrap/src/main/resources/js/common.js index 9e52cb2..cccb334 100644 --- a/fizz-bootstrap/src/main/resources/js/common.js +++ b/fizz-bootstrap/src/main/resources/js/common.js @@ -190,6 +190,36 @@ var common = { } var result = ctx[stepName]['result'] || {}; return field ? result[field] : result; + }, + + /** + * 获取步骤循环结果 + * @param {*} ctx 上下文 【必填】 + * @param {*} stepName 步骤名【必填】 + */ + getStepCircle: function (ctx, stepName){ + if(!ctx || !stepName || !ctx[stepName]){ + return null; + } + // 返回循环结果数组 + return ctx[stepName]['circle']; + }, + + /** + * 获取请求的循环结果 + * @param {*} ctx 上下文 【必填】 + * @param {*} stepName 步骤名【必填】 + */ + getRequestCircle: function (ctx, stepName, requestName){ + if(!ctx || !stepName || !requestName){ + return null; + } + if(!ctx[stepName] || !ctx[stepName]['requests'] || !ctx[stepName]['requests'][requestName] || + !ctx[stepName]['requests'][requestName]['request']){ + return null; + } + // 返回循环结果数组 + return ctx[stepName]['requests'][requestName]['circle']; } /* *********** step request end ************ */ diff --git a/fizz-core/src/main/java/we/fizz/Pipeline.java b/fizz-core/src/main/java/we/fizz/Pipeline.java index db99759..0b2caf0 100644 --- a/fizz-core/src/main/java/we/fizz/Pipeline.java +++ b/fizz-core/src/main/java/we/fizz/Pipeline.java @@ -119,12 +119,12 @@ public class Pipeline { }else { LinkedList opSteps = (LinkedList) steps.clone(); Step step1 = opSteps.removeFirst(); - Mono> result = runStep(step1, null).expand(response -> { - if (opSteps.isEmpty() || response.isStop()) { + Mono> result = runStep(step1, null).expand(lastStepResponse -> { + if (opSteps.isEmpty() || lastStepResponse.isStop()) { return Mono.empty(); } Step step = opSteps.pop(); - return runStep(step, response); + return runStep(step, lastStepResponse); }).flatMap(response -> Flux.just(response)).collectList(); return result.flatMap(clientResponse -> { return handleOutput(input); @@ -132,7 +132,9 @@ public class Pipeline { } } - private Mono runStep(Step step, StepResponse response){ + private Mono runStep(Step step, StepResponse lastStepResponse){ + StepResponse stepResponse = new StepResponse(step, null, new HashMap>()); + stepContext.put(step.getName(), stepResponse); List components = step.getComponents(); if (components != null && components.size() > 0) { StepContextPosition stepCtxPos = new StepContextPosition(step.getName()); diff --git a/fizz-core/src/main/java/we/fizz/Step.java b/fizz-core/src/main/java/we/fizz/Step.java index 2a7e9e0..5ccaafa 100644 --- a/fizz-core/src/main/java/we/fizz/Step.java +++ b/fizz-core/src/main/java/we/fizz/Step.java @@ -114,8 +114,7 @@ public class Step { public void beforeRun(StepContext stepContext2, StepResponse response ) { stepContext = stepContext2; lastStepResponse = response; - StepResponse stepResponse = new StepResponse(this, null, new HashMap>()); - stepContext.put(name, stepResponse); + StepResponse stepResponse = (StepResponse) stepContext.get(this.name); Map configs = this.getRequestConfigs(); for(String configName :configs.keySet()) { InputConfig inputConfig = configs.get(configName); diff --git a/fizz-core/src/main/java/we/fizz/StepContext.java b/fizz-core/src/main/java/we/fizz/StepContext.java index 6e6bf84..974cf92 100644 --- a/fizz-core/src/main/java/we/fizz/StepContext.java +++ b/fizz-core/src/main/java/we/fizz/StepContext.java @@ -801,6 +801,48 @@ public class StepContext extends ConcurrentHashMap { circle.add(circleResult); } + /** + * 设置判断条件组件结果
+ * Set result of condition components
+ * + * @param stepName step name + * @param requestName request name + * @param conditionDesc condition description, such as:
+ * circle[0]-execCondition:my condition 1
+ * circle[1]-breakCondition:my condition 2
+ * condition:my condition 3
+ * @param rs result of condition component + */ + public void addConditionResult(String stepName, String requestName, String conditionDesc, boolean rs) { + if (requestName == null) { + StepResponse stepResponse = (StepResponse) this.get(stepName); + if (stepResponse == null) { + return; + } + List> results = (List>) stepResponse.getConditionResults(); + if (results == null) { + results = new ArrayList<>(); + stepResponse.setConditionResults(results); + } + Map result = new HashMap<>(); + result.put(conditionDesc, rs); + results.add(result); + } else { + Map request = getStepRequest(stepName, requestName); + if (request == null) { + return; + } + List> results = (List>) request.get("conditionResults"); + if (results == null) { + results = new ArrayList<>(); + request.put("conditionResults", results); + } + Map result = new HashMap<>(); + result.put(conditionDesc, rs); + results.add(result); + } + } + /** * 获取请求的循环对象
* Returns the current circle item of request
@@ -808,12 +850,12 @@ public class StepContext extends ConcurrentHashMap { * @param stepName * @param requestName */ - public List> getRequestCircleItem(String stepName, String requestName) { + public Object getRequestCircleItem(String stepName, String requestName) { Map request = getStepRequest(stepName, requestName); if (request == null) { return null; } - return (List>) request.get("circle"); + return request.get("item"); } /** @@ -823,12 +865,12 @@ public class StepContext extends ConcurrentHashMap { * @param stepName * @param requestName */ - public Object getRequestCircle(String stepName, String requestName) { + public List> getRequestCircle(String stepName, String requestName) { Map request = getStepRequest(stepName, requestName); if (request == null) { return null; } - return request.get("item"); + return (List>) request.get("circle"); } private Object deepCopy(Object obj) { diff --git a/fizz-core/src/main/java/we/fizz/StepResponse.java b/fizz-core/src/main/java/we/fizz/StepResponse.java index 01dc264..31caf1c 100644 --- a/fizz-core/src/main/java/we/fizz/StepResponse.java +++ b/fizz-core/src/main/java/we/fizz/StepResponse.java @@ -35,6 +35,8 @@ public class StepResponse { private Integer index; // circle results private List> circle; + // result of condition components + private List> conditionResults; public StepResponse(Step aStep, HashMap item, Map> requests) { setStepName(aStep.getName()); @@ -96,5 +98,11 @@ public class StepResponse { public void setIndex(Integer index) { this.index = index; } + public List> getConditionResults() { + return conditionResults; + } + public void setConditionResults(List> conditionResults) { + this.conditionResults = conditionResults; + } } diff --git a/fizz-core/src/main/java/we/fizz/component/ComponentHelper.java b/fizz-core/src/main/java/we/fizz/component/ComponentHelper.java index 72f1eb6..1a03875 100644 --- a/fizz-core/src/main/java/we/fizz/component/ComponentHelper.java +++ b/fizz-core/src/main/java/we/fizz/component/ComponentHelper.java @@ -98,60 +98,20 @@ public class ComponentHelper { if (conditions != null && conditions.size() > 0) { ONode ctxNode = toONode(stepContext); for (Condition c : conditions) { - if (!c.exec(ctxNode)) { - return null; + boolean rs = c.exec(ctxNode); + stepContext.addConditionResult(stepCtxPos.getStepName(), stepCtxPos.getRequestName(), c.getDesc(), + rs); + if (!rs) { + return Mono.empty(); } } } if (circle != null) { return circle.exec(stepContext, stepCtxPos, f); + } else { + return f.apply(stepContext, stepCtxPos); } -// // conditions before circle component -// List conditions1 = new ArrayList<>(); -// // conditions after circle component -// List conditions2 = new ArrayList<>(); -// Circle circle = null; -// for (IComponent component : components) { -// if (ComponentTypeEnum.CIRCLE == component.getType()) { -// circle = (Circle) component; -// } -// if (circle == null && ComponentTypeEnum.CONDITION == component.getType()) { -// conditions1.add((Condition) component); -// } -// if (circle != null && ComponentTypeEnum.CONDITION == component.getType()) { -// conditions2.add((Condition) component); -// } -// } -// -// if (conditions1 != null && conditions1.size() > 0) { -// ONode ctxNode = toONode(stepContext); -// for (Condition c : conditions1) { -// if (!c.exec(ctxNode)) { -// return null; -// } -// } -// } -// -// if (circle != null) { -// return circle.exec(stepContext, (ctx) -> { -// boolean canRun = true; -// if (conditions2 != null && conditions2.size() > 0) { -// ONode ctxNode = toONode(ctx); -// for (Condition c : conditions2) { -// if (!c.exec(ctxNode)) { -// canRun = false; -// } -// } -// } -// if (canRun) { -// return f.apply(ctx); -// } else { -// return Mono.empty(); -// } -// -// }); -// } } return Mono.empty(); } diff --git a/fizz-core/src/main/java/we/fizz/component/circle/Circle.java b/fizz-core/src/main/java/we/fizz/component/circle/Circle.java index 85e3e3b..db1be11 100644 --- a/fizz-core/src/main/java/we/fizz/component/circle/Circle.java +++ b/fizz-core/src/main/java/we/fizz/component/circle/Circle.java @@ -21,11 +21,8 @@ import java.util.Collection; import java.util.Collections; import java.util.List; import java.util.function.BiFunction; -import java.util.function.Function; import org.noear.snack.ONode; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; import lombok.Data; import reactor.core.publisher.Flux; @@ -39,7 +36,6 @@ import we.fizz.component.ValueTypeEnum; import we.fizz.component.condition.Condition; import we.fizz.exception.FizzRuntimeException; import we.fizz.input.PathMapping; -import we.fizz.input.RPCInput; /** * Circle component @@ -102,7 +98,7 @@ public class Circle implements IComponent { /** * Reference value of dataSource */ - private List refValue; + private Object refValue; private boolean refReadFlag; @@ -113,8 +109,12 @@ public class Circle implements IComponent { if (dataSource == null) { return fixedValue; } - if (dataSource instanceof Integer || dataSource instanceof Long) { - fixedValue = Integer.valueOf(dataSource.toString()); + if (dataSource instanceof Integer || dataSource instanceof Long || dataSource instanceof String) { + try { + fixedValue = Integer.valueOf(dataSource.toString()); + } catch (Exception e) { + throw new FizzRuntimeException("invalid data source, fixed data source must be a positive integer"); + } if (fixedValue.intValue() < 1) { throw new FizzRuntimeException("invalid data source, fixed data source must be a positive integer"); } @@ -125,7 +125,7 @@ public class Circle implements IComponent { } @SuppressWarnings("unchecked") - private List getRefValue(ONode ctxNode) { + private Object getRefValue(ONode ctxNode) { if (refReadFlag) { return refValue; } @@ -136,8 +136,24 @@ public class Circle implements IComponent { if (value instanceof Collection) { refValue = (List) value; return refValue; + } else if (value instanceof Integer || value instanceof Long || value instanceof String) { + try { + Integer times = Integer.valueOf(value.toString()); + if (times.intValue() < 1) { + throw new FizzRuntimeException( + "invalid data source, data source must be a positive integer or an array"); + } + refValue = times; + } catch (FizzRuntimeException e) { + throw e; + } catch (Exception e) { + throw new FizzRuntimeException( + "invalid data source, data source must be a positive integer or an array"); + } + return refValue; } else { - throw new FizzRuntimeException("invalid data source, referenced data source must be a array"); + throw new FizzRuntimeException( + "invalid data source, referenced data source must be a positive integer or an array"); } } @@ -146,32 +162,49 @@ public class Circle implements IComponent { * * @return */ + @SuppressWarnings("unchecked") public CircleItem next(ONode ctxNode) { if (ValueTypeEnum.FIXED.equals(dataSourceType)) { Integer total = this.getFixedValue(ctxNode); if (index == null) { index = 0; - currentItem = index; + currentItem = index + 1; return new CircleItem(currentItem, index); } else if (index.intValue() < total.intValue() - 1) { index = index + 1; - currentItem = index; + currentItem = index + 1; return new CircleItem(currentItem, index); } else { return null; } } else if (ValueTypeEnum.REF.equals(dataSourceType)) { - List list = this.getRefValue(ctxNode); - if (index == null) { - index = 0; - currentItem = list.get(index); - return new CircleItem(currentItem, index); - } else if (index.intValue() < list.size() - 1) { - index = index + 1; - currentItem = list.get(index); - return new CircleItem(currentItem, index); - } else { - return null; + Object refValue = this.getRefValue(ctxNode); + if (refValue instanceof Collection) { + List list = (List) refValue; + if (index == null) { + index = 0; + currentItem = list.get(index); + return new CircleItem(currentItem, index); + } else if (index.intValue() < list.size() - 1) { + index = index + 1; + currentItem = list.get(index); + return new CircleItem(currentItem, index); + } else { + return null; + } + } else if (refValue instanceof Integer) { + Integer total = (Integer) refValue; + if (index == null) { + index = 0; + currentItem = index + 1; + return new CircleItem(currentItem, index); + } else if (index.intValue() < total.intValue() - 1) { + index = index + 1; + currentItem = index + 1; + return new CircleItem(currentItem, index); + } else { + return null; + } } } return null; @@ -183,11 +216,15 @@ public class Circle implements IComponent { * @param ctxNode * @return */ - public boolean canExec(ONode ctxNode) { + public boolean canExec(int index, ONode ctxNode, StepContext stepContext, + StepContextPosition stepCtxPos) { if (this.execConditions != null && this.execConditions.size() > 0) { try { - for (Condition condition : execConditions) { - if (!condition.exec(ctxNode)) { + for (Condition c : execConditions) { + boolean rs = c.exec(ctxNode); + stepContext.addConditionResult(stepCtxPos.getStepName(), stepCtxPos.getRequestName(), + "circle[" + index + "]-execCondition:" + c.getDesc(), rs); + if (!rs) { return false; } } @@ -204,11 +241,15 @@ public class Circle implements IComponent { * @param ctxNode * @return */ - public boolean breakCircle(ONode ctxNode) { + public boolean breakCircle(int index, ONode ctxNode, StepContext stepContext, + StepContextPosition stepCtxPos) { if (this.breakConditions != null && this.breakConditions.size() > 0) { try { - for (Condition condition : breakConditions) { - if (condition.exec(ctxNode)) { + for (Condition c : breakConditions) { + boolean rs = c.exec(ctxNode); + stepContext.addConditionResult(stepCtxPos.getStepName(), stepCtxPos.getRequestName(), + "circle[" + index + "]-breakCondition:" + c.getDesc(), rs); + if (rs) { return true; } } @@ -219,14 +260,14 @@ public class Circle implements IComponent { return false; } - @SuppressWarnings("unchecked") + @SuppressWarnings({ "unchecked", "rawtypes" }) public Mono exec(StepContext stepContext, StepContextPosition stepCtxPos, BiFunction f) { - ONode ctxNode = ComponentHelper.toONode(stepContext); - CircleItem nextItem = this.next(ctxNode); + ONode ctxNode1 = ComponentHelper.toONode(stepContext); + CircleItem nextItem = this.next(ctxNode1); if (nextItem != null) { - return Mono.just(new CircleItemResult(nextItem, null)).expand(circleItemResult -> { - // put nextItem to step context and ctxNode for further JSON path mapping + return Mono.just(new CircleItemResult(ctxNode1, nextItem, null)).expand(circleItemResult -> { + // put nextItem to step context CircleItem cItem = circleItemResult.nextItem; if (stepCtxPos.getRequestName() != null) { stepContext.setRequestCircleItem(stepCtxPos.getStepName(), stepCtxPos.getRequestName(), @@ -234,23 +275,26 @@ public class Circle implements IComponent { } else { stepContext.setStepCircleItem(stepCtxPos.getStepName(), cItem.getItem(), cItem.getIndex()); } + ONode ctxNode = circleItemResult.ctxNode; PathMapping.setByPath(ctxNode, stepCtxPos.getPath() + ".item", cItem.getItem(), true); PathMapping.setByPath(ctxNode, stepCtxPos.getPath() + ".index", cItem.getIndex(), true); - - if (!this.canExec(ctxNode)) { - return Mono.just(new CircleItemResult(this.next(ctxNode), null)); - } - if (this.breakCircle(ctxNode)) { - return Mono.empty(); + + if (!this.canExec(cItem.getIndex(), ctxNode, stepContext, stepCtxPos)) { + return Mono.just(new CircleItemResult(ctxNode, this.next(ctxNode), null)); } return f.apply(stepContext, stepCtxPos).flatMap(r -> { - CircleItem nextItem2 = this.next(ctxNode); + ONode ctxNode2 = ComponentHelper.toONode(stepContext); + if (this.breakCircle(cItem.getIndex(), ctxNode, stepContext, stepCtxPos)) { + return Mono.empty(); + } + CircleItem nextItem2 = this.next(ctxNode2); if (nextItem2 == null) { return Mono.empty(); } - return Mono.just(new CircleItemResult(nextItem2, r)); + return Mono.just(new CircleItemResult(ctxNode2, nextItem2, r)); }); - }).flatMap(circleItemResult -> Flux.just(circleItemResult)).collectList().flatMap(list -> { + }).flatMap(circleItemResult -> Flux.just(circleItemResult)).collectList().flatMap(r -> { + List list = (List) r; if (list != null && list.size() > 0) { Collections.reverse(list); for (int i = 0; i < list.size(); i++) { @@ -268,10 +312,12 @@ public class Circle implements IComponent { @Data class CircleItemResult { + private ONode ctxNode; private CircleItem nextItem; private Object result; - public CircleItemResult(CircleItem nextItem, Object result) { + public CircleItemResult(ONode ctxNode, CircleItem nextItem, Object result) { + this.ctxNode = ctxNode; this.nextItem = nextItem; this.result = result; } diff --git a/fizz-core/src/main/java/we/fizz/component/condition/Condition.java b/fizz-core/src/main/java/we/fizz/component/condition/Condition.java index a7e62b7..036749c 100644 --- a/fizz-core/src/main/java/we/fizz/component/condition/Condition.java +++ b/fizz-core/src/main/java/we/fizz/component/condition/Condition.java @@ -124,6 +124,7 @@ public class Condition implements IComponent { case CONTAINS: if (v1 == null) { rs = false; + break; } if (v1 instanceof Collection && !(v2 instanceof Collection)) { Collection coll1 = (Collection) v1; @@ -143,6 +144,7 @@ public class Condition implements IComponent { case NOT_CONTAIN: if (v1 == null) { rs = true; + break; } if (v1 instanceof Collection && !(v2 instanceof Collection)) { Collection coll1 = (Collection) v1; @@ -162,6 +164,7 @@ public class Condition implements IComponent { case CONTAINS_ANY: if (v1 == null || v2 == null) { rs = false; + break; } if (v1 instanceof Collection && v2 instanceof Collection) { Collection coll1 = (Collection) v1; @@ -235,7 +238,7 @@ public class Condition implements IComponent { } private Object cast(RefDataTypeEnum type, Object val) { - if (type != null) { + if (type != null && val != null) { switch (type) { case INT: val = Integer.valueOf(val.toString()); diff --git a/fizz-core/src/test/java/we/fizz/component/CircleTests.java b/fizz-core/src/test/java/we/fizz/component/CircleTests.java index 4e2ee52..ff09c68 100644 --- a/fizz-core/src/test/java/we/fizz/component/CircleTests.java +++ b/fizz-core/src/test/java/we/fizz/component/CircleTests.java @@ -25,6 +25,7 @@ import java.util.List; import org.junit.jupiter.api.Test; import org.noear.snack.ONode; +import we.fizz.StepContext; import we.fizz.component.circle.Circle; import we.fizz.component.circle.CircleItem; import we.fizz.component.condition.Condition; @@ -41,7 +42,6 @@ class CircleTests { void contextLoads() { } - @SuppressWarnings("rawtypes") @Test void testNextFixedDataSource() { @@ -50,14 +50,14 @@ class CircleTests { // FIXED data source Circle c = new Circle(null, ValueTypeEnum.FIXED, 3, null, null); CircleItem circleItem = c.next(ctxNode); - assertEquals(0, (Integer) circleItem.getItem()); - - circleItem = c.next(ctxNode); assertEquals(1, (Integer) circleItem.getItem()); circleItem = c.next(ctxNode); assertEquals(2, (Integer) circleItem.getItem()); + circleItem = c.next(ctxNode); + assertEquals(3, (Integer) circleItem.getItem()); + circleItem = c.next(ctxNode); assertEquals(null, circleItem); @@ -115,7 +115,8 @@ class CircleTests { CircleItem circleItem = circle.next(ctxNode); PathMapping.setByPath(ctxNode, "item", circleItem.getItem(), true); PathMapping.setByPath(ctxNode, "index", circleItem.getIndex(), true); - boolean rs = circle.canExec(ctxNode); + boolean rs = circle.canExec(circleItem.getIndex(), ctxNode, new StepContext(), + new StepContextPosition("step1", null)); assertEquals(i, circleItem.getIndex()); if (i < 3) { assertEquals(true, rs); @@ -127,7 +128,7 @@ class CircleTests { } } - + @Test void testBreakCondition() { ONode ctxNode = ONode.load(new HashMap()); @@ -154,7 +155,9 @@ class CircleTests { CircleItem circleItem = circle.next(ctxNode); PathMapping.setByPath(ctxNode, "item", circleItem.getItem(), true); PathMapping.setByPath(ctxNode, "index", circleItem.getIndex(), true); - boolean rs = circle.breakCircle(ctxNode); + + boolean rs = circle.breakCircle(circleItem.getIndex(), ctxNode, new StepContext(), + new StepContextPosition("step1", null)); assertEquals(i, circleItem.getIndex()); if (i < 3) { assertEquals(false, rs); From fce76c3c834429efafb2068e99f3db4ef01238ca Mon Sep 17 00:00:00 2001 From: Francis Dong Date: Mon, 19 Jul 2021 15:32:51 +0800 Subject: [PATCH 27/28] Fix the issue that operator can not be deserialized #249 --- .../java/we/fizz/component/OperatorEnum.java | 6 +- .../fizz/component/condition/Condition.java | 25 ++++--- .../main/java/we/fizz/input/PathMapping.java | 4 + .../we/fizz/component/ConditionTests.java | 74 +++++++++---------- 4 files changed, 60 insertions(+), 49 deletions(-) diff --git a/fizz-core/src/main/java/we/fizz/component/OperatorEnum.java b/fizz-core/src/main/java/we/fizz/component/OperatorEnum.java index 2cfce8c..73a2eee 100644 --- a/fizz-core/src/main/java/we/fizz/component/OperatorEnum.java +++ b/fizz-core/src/main/java/we/fizz/component/OperatorEnum.java @@ -25,9 +25,9 @@ package we.fizz.component; */ public enum OperatorEnum { - EQ("eq"), NE("ne"), GT("gt"), GE("ge"), LT("lt"), LE("le"), CONTAINS("contains"), NOT_CONTAIN("notContain"), CONTAINS_ANY("containsAny"), - IS_NULL("isNull"), IS_NOT_NULL("isNotNull"), IS_BLANK("isBlank"), IS_NOT_BLANK("isNotBlank"), IS_EMPTY("isEmpty"), - IS_NOT_EMPTY("isNotEmpty"); + EQ("eq"), NE("ne"), GT("gt"), GE("ge"), LT("lt"), LE("le"), CONTAINS("contains"), NOTCONTAIN("notContain"), CONTAINSANY("containsAny"), + ISNULL("isNull"), ISNOTNULL("isNotNull"), ISBLANK("isBlank"), ISNOTBLANK("isNotBlank"), ISEMPTY("isEmpty"), + ISNOTEMPTY("isNotEmpty"); private String code; diff --git a/fizz-core/src/main/java/we/fizz/component/condition/Condition.java b/fizz-core/src/main/java/we/fizz/component/condition/Condition.java index 036749c..2a21f32 100644 --- a/fizz-core/src/main/java/we/fizz/component/condition/Condition.java +++ b/fizz-core/src/main/java/we/fizz/component/condition/Condition.java @@ -28,6 +28,7 @@ import com.alibaba.fastjson.JSON; import lombok.AllArgsConstructor; import lombok.Data; +import lombok.NoArgsConstructor; import we.fizz.component.ComponentTypeEnum; import we.fizz.component.IComponent; import we.fizz.component.OperatorEnum; @@ -43,7 +44,6 @@ import we.fizz.input.PathMapping; * */ @Data -@AllArgsConstructor public class Condition implements IComponent { private static final String type = ComponentTypeEnum.CONDITION.getCode(); @@ -55,6 +55,13 @@ public class Condition implements IComponent { private OperatorEnum operator; private ConditionValue value2; + + public Condition(String desc, ConditionValue value1, OperatorEnum operator, ConditionValue value2) { + this.desc = desc; + this.value1 = value1; + this.operator = operator; + this.value2 = value2; + } @Override public ComponentTypeEnum getType() { @@ -141,7 +148,7 @@ public class Condition implements IComponent { throw new FizzRuntimeException("value2 can not be a collection"); } break; - case NOT_CONTAIN: + case NOTCONTAIN: if (v1 == null) { rs = true; break; @@ -161,7 +168,7 @@ public class Condition implements IComponent { throw new FizzRuntimeException("value2 can not be a collection"); } break; - case CONTAINS_ANY: + case CONTAINSANY: if (v1 == null || v2 == null) { rs = false; break; @@ -176,23 +183,23 @@ public class Condition implements IComponent { throw new FizzRuntimeException("value2 must be a collection"); } break; - case IS_NULL: + case ISNULL: rs = v1 == null; break; - case IS_NOT_NULL: + case ISNOTNULL: rs = v1 != null; break; - case IS_BLANK: + case ISBLANK: rs = v1 == null || StringUtils.isBlank(v1.toString()); break; - case IS_NOT_BLANK: + case ISNOTBLANK: rs = v1 != null && StringUtils.isNotBlank(v1.toString()); break; - case IS_EMPTY: + case ISEMPTY: rs = v1 == null || (v1 instanceof Collection && ((Collection) v1).isEmpty()) || (v1 instanceof Map && ((Map) v1).isEmpty()); break; - case IS_NOT_EMPTY: + case ISNOTEMPTY: if (v1 != null) { if (v1 instanceof Collection) { rs = !((Collection) v1).isEmpty(); diff --git a/fizz-core/src/main/java/we/fizz/input/PathMapping.java b/fizz-core/src/main/java/we/fizz/input/PathMapping.java index a1d22ce..a280c98 100644 --- a/fizz-core/src/main/java/we/fizz/input/PathMapping.java +++ b/fizz-core/src/main/java/we/fizz/input/PathMapping.java @@ -21,6 +21,7 @@ import java.util.*; import java.util.Map.Entry; import java.util.stream.Collectors; +import org.apache.commons.lang3.StringUtils; import org.noear.snack.ONode; import we.constants.CommonConstants; @@ -304,6 +305,9 @@ public class PathMapping { * @return */ public static Object getValueByPath(ONode ctxNode, String path) { + if (StringUtils.isBlank(path)) { + return null; + } String p = path; String defaultValue = null; if (path.indexOf("|") != -1) { diff --git a/fizz-core/src/test/java/we/fizz/component/ConditionTests.java b/fizz-core/src/test/java/we/fizz/component/ConditionTests.java index 8c478d6..0aa7742 100644 --- a/fizz-core/src/test/java/we/fizz/component/ConditionTests.java +++ b/fizz-core/src/test/java/we/fizz/component/ConditionTests.java @@ -158,17 +158,17 @@ class ConditionTests { RefDataTypeEnum.STRING, "data.m.string_8", OperatorEnum.CONTAINS, FALSE }); this.run(ctxNode, new Object[] { ValueTypeEnum.REF, RefDataTypeEnum.ARRAY, "data.list1", ValueTypeEnum.FIXED, - FixedDataTypeEnum.STRING, "2", OperatorEnum.NOT_CONTAIN, FALSE }); + FixedDataTypeEnum.STRING, "2", OperatorEnum.NOTCONTAIN, FALSE }); this.run(ctxNode, new Object[] { ValueTypeEnum.REF, RefDataTypeEnum.ARRAY, "data.list1", ValueTypeEnum.REF, - RefDataTypeEnum.STRING, "data.m.string_1", OperatorEnum.NOT_CONTAIN, FALSE }); + RefDataTypeEnum.STRING, "data.m.string_1", OperatorEnum.NOTCONTAIN, FALSE }); this.run(ctxNode, new Object[] { ValueTypeEnum.REF, RefDataTypeEnum.ARRAY, "data.list1", ValueTypeEnum.REF, - RefDataTypeEnum.STRING, "data.m.string_8", OperatorEnum.NOT_CONTAIN, TRUE }); + RefDataTypeEnum.STRING, "data.m.string_8", OperatorEnum.NOTCONTAIN, TRUE }); // collection contains any this.run(ctxNode, new Object[] { ValueTypeEnum.REF, RefDataTypeEnum.ARRAY, "data.list1", ValueTypeEnum.REF, - RefDataTypeEnum.ARRAY, "data.list2", OperatorEnum.CONTAINS_ANY, TRUE }); + RefDataTypeEnum.ARRAY, "data.list2", OperatorEnum.CONTAINSANY, TRUE }); this.run(ctxNode, new Object[] { ValueTypeEnum.REF, RefDataTypeEnum.ARRAY, "data.list1", ValueTypeEnum.REF, - RefDataTypeEnum.ARRAY, "data.intList", OperatorEnum.CONTAINS_ANY, FALSE }); + RefDataTypeEnum.ARRAY, "data.intList", OperatorEnum.CONTAINSANY, FALSE }); // Collection this.run(ctxNode, new Object[] { ValueTypeEnum.REF, RefDataTypeEnum.ARRAY, "data.intList", ValueTypeEnum.FIXED, @@ -181,13 +181,13 @@ class ConditionTests { RefDataTypeEnum.INT, 9, OperatorEnum.CONTAINS, FALSE }); this.run(ctxNode, new Object[] { ValueTypeEnum.REF, RefDataTypeEnum.ARRAY, "data.intList", ValueTypeEnum.FIXED, - FixedDataTypeEnum.STRING, "2", OperatorEnum.NOT_CONTAIN, TRUE }); + FixedDataTypeEnum.STRING, "2", OperatorEnum.NOTCONTAIN, TRUE }); this.run(ctxNode, new Object[] { ValueTypeEnum.REF, RefDataTypeEnum.ARRAY, "data.intList", ValueTypeEnum.REF, - RefDataTypeEnum.INT, "data.m.int", OperatorEnum.NOT_CONTAIN, FALSE }); + RefDataTypeEnum.INT, "data.m.int", OperatorEnum.NOTCONTAIN, FALSE }); this.run(ctxNode, new Object[] { ValueTypeEnum.REF, RefDataTypeEnum.ARRAY, "data.intList", ValueTypeEnum.FIXED, - RefDataTypeEnum.INT, 2, OperatorEnum.NOT_CONTAIN, FALSE }); + RefDataTypeEnum.INT, 2, OperatorEnum.NOTCONTAIN, FALSE }); this.run(ctxNode, new Object[] { ValueTypeEnum.REF, RefDataTypeEnum.ARRAY, "data.intList", ValueTypeEnum.FIXED, - RefDataTypeEnum.INT, 9, OperatorEnum.NOT_CONTAIN, TRUE }); + RefDataTypeEnum.INT, 9, OperatorEnum.NOTCONTAIN, TRUE }); // Collection this.run(ctxNode, new Object[] { ValueTypeEnum.REF, RefDataTypeEnum.ARRAY, "data.floatList", @@ -235,71 +235,71 @@ class ConditionTests { // Is null this.run(ctxNode, new Object[] { ValueTypeEnum.REF, RefDataTypeEnum.ARRAY, "data.list11111", ValueTypeEnum.REF, - RefDataTypeEnum.STRING, "data.m.string_8", OperatorEnum.IS_NULL, TRUE }); + RefDataTypeEnum.STRING, "data.m.string_8", OperatorEnum.ISNULL, TRUE }); this.run(ctxNode, new Object[] { ValueTypeEnum.REF, RefDataTypeEnum.STRING, "data.m.string_8", - ValueTypeEnum.REF, RefDataTypeEnum.STRING, "data.m.string_8", OperatorEnum.IS_NULL, FALSE }); + ValueTypeEnum.REF, RefDataTypeEnum.STRING, "data.m.string_8", OperatorEnum.ISNULL, FALSE }); this.run(ctxNode, new Object[] { ValueTypeEnum.REF, RefDataTypeEnum.ARRAY, "data.list11111", null, null, null, - OperatorEnum.IS_NULL, TRUE }); + OperatorEnum.ISNULL, TRUE }); this.run(ctxNode, new Object[] { ValueTypeEnum.REF, RefDataTypeEnum.STRING, "data.m.string_8", null, null, null, - OperatorEnum.IS_NULL, FALSE }); + OperatorEnum.ISNULL, FALSE }); // Is not null this.run(ctxNode, new Object[] { ValueTypeEnum.REF, RefDataTypeEnum.ARRAY, "data.list11111", ValueTypeEnum.REF, - RefDataTypeEnum.STRING, "data.m.string_8", OperatorEnum.IS_NOT_NULL, FALSE }); + RefDataTypeEnum.STRING, "data.m.string_8", OperatorEnum.ISNOTNULL, FALSE }); this.run(ctxNode, new Object[] { ValueTypeEnum.REF, RefDataTypeEnum.STRING, "data.m.string_8", - ValueTypeEnum.REF, RefDataTypeEnum.STRING, "data.m.string_8", OperatorEnum.IS_NOT_NULL, TRUE }); + ValueTypeEnum.REF, RefDataTypeEnum.STRING, "data.m.string_8", OperatorEnum.ISNOTNULL, TRUE }); this.run(ctxNode, new Object[] { ValueTypeEnum.REF, RefDataTypeEnum.ARRAY, "data.list11111", null, null, null, - OperatorEnum.IS_NOT_NULL, FALSE }); + OperatorEnum.ISNOTNULL, FALSE }); this.run(ctxNode, new Object[] { ValueTypeEnum.REF, RefDataTypeEnum.STRING, "data.m.string_8", null, null, null, - OperatorEnum.IS_NOT_NULL, TRUE }); + OperatorEnum.ISNOTNULL, TRUE }); // Is Blank this.run(ctxNode, new Object[] { ValueTypeEnum.REF, RefDataTypeEnum.ARRAY, "data.list11111", ValueTypeEnum.REF, - RefDataTypeEnum.STRING, "data.m.string_8", OperatorEnum.IS_BLANK, TRUE }); + RefDataTypeEnum.STRING, "data.m.string_8", OperatorEnum.ISBLANK, TRUE }); this.run(ctxNode, new Object[] { ValueTypeEnum.REF, RefDataTypeEnum.STRING, "data.m.string_8", - ValueTypeEnum.REF, RefDataTypeEnum.STRING, "data.m.string_8", OperatorEnum.IS_BLANK, FALSE }); + ValueTypeEnum.REF, RefDataTypeEnum.STRING, "data.m.string_8", OperatorEnum.ISBLANK, FALSE }); this.run(ctxNode, new Object[] { ValueTypeEnum.REF, RefDataTypeEnum.ARRAY, "data.list11111", null, null, null, - OperatorEnum.IS_BLANK, TRUE }); + OperatorEnum.ISBLANK, TRUE }); this.run(ctxNode, new Object[] { ValueTypeEnum.REF, RefDataTypeEnum.STRING, "data.m.string_8", null, null, null, - OperatorEnum.IS_BLANK, FALSE }); + OperatorEnum.ISBLANK, FALSE }); this.run(ctxNode, new Object[] { ValueTypeEnum.REF, RefDataTypeEnum.STRING, "data.m.string_blank", null, null, - null, OperatorEnum.IS_BLANK, TRUE }); + null, OperatorEnum.ISBLANK, TRUE }); // Is not Blank this.run(ctxNode, new Object[] { ValueTypeEnum.REF, RefDataTypeEnum.ARRAY, "data.list11111", ValueTypeEnum.REF, - RefDataTypeEnum.STRING, "data.m.string_8", OperatorEnum.IS_NOT_BLANK, FALSE }); + RefDataTypeEnum.STRING, "data.m.string_8", OperatorEnum.ISNOTBLANK, FALSE }); this.run(ctxNode, new Object[] { ValueTypeEnum.REF, RefDataTypeEnum.STRING, "data.m.string_8", - ValueTypeEnum.REF, RefDataTypeEnum.STRING, "data.m.string_8", OperatorEnum.IS_NOT_BLANK, TRUE }); + ValueTypeEnum.REF, RefDataTypeEnum.STRING, "data.m.string_8", OperatorEnum.ISNOTBLANK, TRUE }); this.run(ctxNode, new Object[] { ValueTypeEnum.REF, RefDataTypeEnum.ARRAY, "data.list11111", null, null, null, - OperatorEnum.IS_NOT_BLANK, FALSE }); + OperatorEnum.ISNOTBLANK, FALSE }); this.run(ctxNode, new Object[] { ValueTypeEnum.REF, RefDataTypeEnum.STRING, "data.m.string_8", null, null, null, - OperatorEnum.IS_NOT_BLANK, TRUE }); + OperatorEnum.ISNOTBLANK, TRUE }); this.run(ctxNode, new Object[] { ValueTypeEnum.REF, RefDataTypeEnum.STRING, "data.m.string_blank", null, null, - null, OperatorEnum.IS_NOT_BLANK, FALSE }); + null, OperatorEnum.ISNOTBLANK, FALSE }); // Is empty this.run(ctxNode, new Object[] { ValueTypeEnum.REF, RefDataTypeEnum.ARRAY, "data.list11111", ValueTypeEnum.REF, - RefDataTypeEnum.STRING, "data.m.string_8", OperatorEnum.IS_EMPTY, TRUE }); + RefDataTypeEnum.STRING, "data.m.string_8", OperatorEnum.ISEMPTY, TRUE }); this.run(ctxNode, new Object[] { ValueTypeEnum.REF, RefDataTypeEnum.ARRAY, "data.list1", ValueTypeEnum.REF, - RefDataTypeEnum.STRING, "data.m.string_8", OperatorEnum.IS_EMPTY, FALSE }); + RefDataTypeEnum.STRING, "data.m.string_8", OperatorEnum.ISEMPTY, FALSE }); this.run(ctxNode, new Object[] { ValueTypeEnum.REF, RefDataTypeEnum.ARRAY, "data.list11111", null, null, null, - OperatorEnum.IS_EMPTY, TRUE }); + OperatorEnum.ISEMPTY, TRUE }); this.run(ctxNode, new Object[] { ValueTypeEnum.REF, RefDataTypeEnum.ARRAY, "data.list1", null, null, null, - OperatorEnum.IS_EMPTY, FALSE }); + OperatorEnum.ISEMPTY, FALSE }); this.run(ctxNode, new Object[] { ValueTypeEnum.REF, RefDataTypeEnum.ARRAY, "data.emptyList", null, null, null, - OperatorEnum.IS_EMPTY, TRUE }); + OperatorEnum.ISEMPTY, TRUE }); // Is not empty this.run(ctxNode, new Object[] { ValueTypeEnum.REF, RefDataTypeEnum.ARRAY, "data.list11111", ValueTypeEnum.REF, - RefDataTypeEnum.STRING, "data.m.string_8", OperatorEnum.IS_NOT_EMPTY, FALSE }); + RefDataTypeEnum.STRING, "data.m.string_8", OperatorEnum.ISNOTEMPTY, FALSE }); this.run(ctxNode, new Object[] { ValueTypeEnum.REF, RefDataTypeEnum.ARRAY, "data.list1", ValueTypeEnum.REF, - RefDataTypeEnum.STRING, "data.m.string_8", OperatorEnum.IS_NOT_EMPTY, TRUE }); + RefDataTypeEnum.STRING, "data.m.string_8", OperatorEnum.ISNOTEMPTY, TRUE }); this.run(ctxNode, new Object[] { ValueTypeEnum.REF, RefDataTypeEnum.ARRAY, "data.list11111", null, null, null, - OperatorEnum.IS_NOT_EMPTY, FALSE }); + OperatorEnum.ISNOTEMPTY, FALSE }); this.run(ctxNode, new Object[] { ValueTypeEnum.REF, RefDataTypeEnum.ARRAY, "data.list1", null, null, null, - OperatorEnum.IS_NOT_EMPTY, TRUE }); + OperatorEnum.ISNOTEMPTY, TRUE }); this.run(ctxNode, new Object[] { ValueTypeEnum.REF, RefDataTypeEnum.ARRAY, "data.emptyList", null, null, null, - OperatorEnum.IS_NOT_EMPTY, FALSE }); + OperatorEnum.ISNOTEMPTY, FALSE }); } From 003a0551172184af4f16c9a8257f859170245485 Mon Sep 17 00:00:00 2001 From: hongqiaowei Date: Mon, 19 Jul 2021 16:04:53 +0800 Subject: [PATCH 28/28] Release 2.2.0-beta11 --- README.en-us.md | 3 ++- README.md | 3 ++- fizz-bootstrap/pom.xml | 2 +- fizz-common/pom.xml | 2 +- fizz-core/pom.xml | 2 +- fizz-plugin/pom.xml | 2 +- fizz-spring-boot-starter/pom.xml | 2 +- pom.xml | 2 +- 8 files changed, 10 insertions(+), 8 deletions(-) diff --git a/README.en-us.md b/README.en-us.md index 72f2323..37046f5 100644 --- a/README.en-us.md +++ b/README.en-us.md @@ -4,7 +4,7 @@ English | [简体中文](./README.md)

- Version + Version Documentation @@ -104,6 +104,7 @@ Starting from v1.3.0, the frontend and backend of the management backend are mer | v1.5.1 | v1.5.1 | | v2.0.0 | v2.0.0 | | v2.1.0 | v2.1.0 | +| v2.2.0 | v2.2.0 | Please download the corresponding management backend version according to the version of the community version diff --git a/README.md b/README.md index fd2835e..5bcc96a 100644 --- a/README.md +++ b/README.md @@ -3,7 +3,7 @@

- Version + Version Documentation @@ -104,6 +104,7 @@ API地址:http://demo.fizzgate.com/proxy/[服务名]/[API_Path] | v1.5.1 | v1.5.1 | | v2.0.0 | v2.0.0 | | v2.1.0 | v2.1.0 | +| v2.2.0 | v2.2.0 | 请根据社区版的版本下载对应的管理后台版本 diff --git a/fizz-bootstrap/pom.xml b/fizz-bootstrap/pom.xml index fd36061..8cb0309 100644 --- a/fizz-bootstrap/pom.xml +++ b/fizz-bootstrap/pom.xml @@ -12,7 +12,7 @@ com.fizzgate fizz-bootstrap - 2.2.0-beta10 + 2.2.0-beta11 1.8 diff --git a/fizz-common/pom.xml b/fizz-common/pom.xml index 24effa2..62f9819 100644 --- a/fizz-common/pom.xml +++ b/fizz-common/pom.xml @@ -5,7 +5,7 @@ fizz-gateway-community com.fizzgate - 2.2.0-beta10 + 2.2.0-beta11 ../pom.xml 4.0.0 diff --git a/fizz-core/pom.xml b/fizz-core/pom.xml index fbcde42..3bf135c 100644 --- a/fizz-core/pom.xml +++ b/fizz-core/pom.xml @@ -5,7 +5,7 @@ fizz-gateway-community com.fizzgate - 2.2.0-beta10 + 2.2.0-beta11 ../pom.xml 4.0.0 diff --git a/fizz-plugin/pom.xml b/fizz-plugin/pom.xml index d9fa6e0..9d4314c 100644 --- a/fizz-plugin/pom.xml +++ b/fizz-plugin/pom.xml @@ -5,7 +5,7 @@ fizz-gateway-community com.fizzgate - 2.2.0-beta10 + 2.2.0-beta11 ../pom.xml 4.0.0 diff --git a/fizz-spring-boot-starter/pom.xml b/fizz-spring-boot-starter/pom.xml index a0285c6..bd5e6ac 100644 --- a/fizz-spring-boot-starter/pom.xml +++ b/fizz-spring-boot-starter/pom.xml @@ -5,7 +5,7 @@ fizz-gateway-community com.fizzgate - 2.2.0-beta10 + 2.2.0-beta11 ../pom.xml 4.0.0 diff --git a/pom.xml b/pom.xml index b574df1..3aea672 100644 --- a/pom.xml +++ b/pom.xml @@ -31,7 +31,7 @@ fizz-gateway-community ${project.artifactId} fizz gateway community - 2.2.0-beta10 + 2.2.0-beta11 pom fizz-common