Update parameter flow rule to adapt to cluster mode and extract rule util class
- Update ParamFlowRule to support cluster mode - Add `ParamFlowClusterConfig` to provide cluster mode items for the rule - Update ParamFlowChecker to support cluster flow mode - Extract ParamFlowRuleUtil class - Change type of `flowId` from Integer to Long Signed-off-by: Eric Zhao <sczyh16@gmail.com>
This commit is contained in:
parent
a6534e5b13
commit
f539b5b827
|
|
@ -33,7 +33,7 @@ public interface TokenService {
|
|||
* @param prioritized whether the request is prioritized
|
||||
* @return result of the token request
|
||||
*/
|
||||
TokenResult requestToken(Integer ruleId, int acquireCount, boolean prioritized);
|
||||
TokenResult requestToken(Long ruleId, int acquireCount, boolean prioritized);
|
||||
|
||||
/**
|
||||
* Request tokens for a specific parameter from remote token server.
|
||||
|
|
@ -43,5 +43,5 @@ public interface TokenService {
|
|||
* @param params parameter list
|
||||
* @return result of the token request
|
||||
*/
|
||||
TokenResult requestParamToken(Integer ruleId, int acquireCount, Collection<Object> params);
|
||||
TokenResult requestParamToken(Long ruleId, int acquireCount, Collection<Object> params);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -28,7 +28,7 @@ public class ClusterFlowConfig {
|
|||
/**
|
||||
* Global unique ID.
|
||||
*/
|
||||
private Integer flowId;
|
||||
private Long flowId;
|
||||
|
||||
/**
|
||||
* Threshold type (average by local value or global value).
|
||||
|
|
@ -41,15 +41,15 @@ public class ClusterFlowConfig {
|
|||
*/
|
||||
private int strategy = ClusterRuleConstant.FLOW_CLUSTER_STRATEGY_NORMAL;
|
||||
|
||||
private Integer refFlowId;
|
||||
private Long refFlowId;
|
||||
private int refSampleCount = 10;
|
||||
private double refRatio = 1d;
|
||||
|
||||
public Integer getFlowId() {
|
||||
public Long getFlowId() {
|
||||
return flowId;
|
||||
}
|
||||
|
||||
public ClusterFlowConfig setFlowId(Integer flowId) {
|
||||
public ClusterFlowConfig setFlowId(Long flowId) {
|
||||
this.flowId = flowId;
|
||||
return this;
|
||||
}
|
||||
|
|
@ -72,11 +72,11 @@ public class ClusterFlowConfig {
|
|||
return this;
|
||||
}
|
||||
|
||||
public Integer getRefFlowId() {
|
||||
public Long getRefFlowId() {
|
||||
return refFlowId;
|
||||
}
|
||||
|
||||
public ClusterFlowConfig setRefFlowId(Integer refFlowId) {
|
||||
public ClusterFlowConfig setRefFlowId(Long refFlowId) {
|
||||
this.refFlowId = refFlowId;
|
||||
return this;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -155,7 +155,7 @@ public final class FlowRuleUtil {
|
|||
* @param id flow ID to check
|
||||
* @return true if valid, otherwise false
|
||||
*/
|
||||
public static boolean validClusterRuleId(Integer id) {
|
||||
public static boolean validClusterRuleId(Long id) {
|
||||
return id != null && id > 0;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -16,14 +16,23 @@
|
|||
package com.alibaba.csp.sentinel.slots.block.flow.param;
|
||||
|
||||
import java.lang.reflect.Array;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
|
||||
import com.alibaba.csp.sentinel.cluster.ClusterTokenClient;
|
||||
import com.alibaba.csp.sentinel.cluster.TokenClientProvider;
|
||||
import com.alibaba.csp.sentinel.cluster.TokenResult;
|
||||
import com.alibaba.csp.sentinel.cluster.TokenResultStatus;
|
||||
import com.alibaba.csp.sentinel.log.RecordLog;
|
||||
import com.alibaba.csp.sentinel.slotchain.ResourceWrapper;
|
||||
import com.alibaba.csp.sentinel.slots.block.RuleConstant;
|
||||
|
||||
/**
|
||||
* Rule checker for parameter flow control.
|
||||
*
|
||||
* @author Eric Zhao
|
||||
* @since 0.2.0
|
||||
*/
|
||||
|
|
@ -40,17 +49,72 @@ final class ParamFlowChecker {
|
|||
return true;
|
||||
}
|
||||
|
||||
// Get parameter value. If value is null, then pass.
|
||||
Object value = args[paramIdx];
|
||||
if (value == null) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if (rule.isClusterMode()) {
|
||||
return passClusterCheck(resourceWrapper, rule, count, value);
|
||||
}
|
||||
|
||||
return passLocalCheck(resourceWrapper, rule, count, value);
|
||||
}
|
||||
|
||||
private static ParameterMetric getHotParameters(ResourceWrapper resourceWrapper) {
|
||||
// Should not be null.
|
||||
return ParamFlowSlot.getParamMetric(resourceWrapper);
|
||||
@SuppressWarnings("unchecked")
|
||||
private static Collection<Object> toCollection(Object value) {
|
||||
if (value instanceof Collection) {
|
||||
return (Collection<Object>)value;
|
||||
} else if (value.getClass().isArray()) {
|
||||
List<Object> params = new ArrayList<Object>();
|
||||
int length = Array.getLength(value);
|
||||
for (int i = 0; i < length; i++) {
|
||||
Object param = Array.get(value, i);
|
||||
params.add(param);
|
||||
}
|
||||
return params;
|
||||
} else {
|
||||
return Collections.singletonList(value);
|
||||
}
|
||||
}
|
||||
|
||||
private static boolean passLocalCheck(ResourceWrapper resourceWrapper, ParamFlowRule rule, int count, Object value) {
|
||||
private static boolean passClusterCheck(ResourceWrapper resourceWrapper, ParamFlowRule rule, int count,
|
||||
Object value) {
|
||||
try {
|
||||
ClusterTokenClient client = TokenClientProvider.getClient();
|
||||
if (client == null) {
|
||||
return true;
|
||||
}
|
||||
Collection<Object> params = toCollection(value);
|
||||
|
||||
TokenResult result = client.requestParamToken(rule.getClusterConfig().getFlowId(), count, params);
|
||||
switch (result.getStatus()) {
|
||||
case TokenResultStatus.OK:
|
||||
return true;
|
||||
case TokenResultStatus.BLOCKED:
|
||||
return false;
|
||||
default:
|
||||
return fallbackToLocalOrPass(resourceWrapper, rule, count, params);
|
||||
}
|
||||
} catch (Throwable ex) {
|
||||
RecordLog.warn("[ParamFlowChecker] Request cluster token for parameter unexpected failed", ex);
|
||||
return fallbackToLocalOrPass(resourceWrapper, rule, count, value);
|
||||
}
|
||||
}
|
||||
|
||||
private static boolean fallbackToLocalOrPass(ResourceWrapper resourceWrapper, ParamFlowRule rule, int count,
|
||||
Object value) {
|
||||
if (rule.getClusterConfig().isFallbackToLocalWhenFail()) {
|
||||
return passLocalCheck(resourceWrapper, rule, count, value);
|
||||
} else {
|
||||
// The rule won't be activated, just pass.
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
private static boolean passLocalCheck(ResourceWrapper resourceWrapper, ParamFlowRule rule, int count,
|
||||
Object value) {
|
||||
try {
|
||||
if (Collection.class.isAssignableFrom(value.getClass())) {
|
||||
for (Object param : ((Collection)value)) {
|
||||
|
|
@ -70,7 +134,7 @@ final class ParamFlowChecker {
|
|||
return passSingleValueCheck(resourceWrapper, rule, count, value);
|
||||
}
|
||||
} catch (Throwable e) {
|
||||
RecordLog.info("[ParamFlowChecker] Unexpected error", e);
|
||||
RecordLog.warn("[ParamFlowChecker] Unexpected error", e);
|
||||
}
|
||||
|
||||
return true;
|
||||
|
|
@ -96,5 +160,10 @@ final class ParamFlowChecker {
|
|||
return true;
|
||||
}
|
||||
|
||||
private static ParameterMetric getHotParameters(ResourceWrapper resourceWrapper) {
|
||||
// Should not be null.
|
||||
return ParamFlowSlot.getParamMetric(resourceWrapper);
|
||||
}
|
||||
|
||||
private ParamFlowChecker() {}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -0,0 +1,94 @@
|
|||
/*
|
||||
* Copyright 1999-2018 Alibaba Group Holding Ltd.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package com.alibaba.csp.sentinel.slots.block.flow.param;
|
||||
|
||||
import com.alibaba.csp.sentinel.slots.block.ClusterRuleConstant;
|
||||
|
||||
/**
|
||||
* Parameter flow rule config in cluster mode.
|
||||
*
|
||||
* @author Eric Zhao
|
||||
* @since 1.4.0
|
||||
*/
|
||||
public class ParamFlowClusterConfig {
|
||||
|
||||
/**
|
||||
* Global unique ID.
|
||||
*/
|
||||
private Long flowId;
|
||||
|
||||
/**
|
||||
* Threshold type (average by local value or global value).
|
||||
*/
|
||||
private int thresholdType = ClusterRuleConstant.FLOW_THRESHOLD_AVG_LOCAL;
|
||||
private boolean fallbackToLocalWhenFail = false;
|
||||
|
||||
public Long getFlowId() {
|
||||
return flowId;
|
||||
}
|
||||
|
||||
public ParamFlowClusterConfig setFlowId(Long flowId) {
|
||||
this.flowId = flowId;
|
||||
return this;
|
||||
}
|
||||
|
||||
public int getThresholdType() {
|
||||
return thresholdType;
|
||||
}
|
||||
|
||||
public ParamFlowClusterConfig setThresholdType(int thresholdType) {
|
||||
this.thresholdType = thresholdType;
|
||||
return this;
|
||||
}
|
||||
|
||||
public boolean isFallbackToLocalWhenFail() {
|
||||
return fallbackToLocalWhenFail;
|
||||
}
|
||||
|
||||
public ParamFlowClusterConfig setFallbackToLocalWhenFail(boolean fallbackToLocalWhenFail) {
|
||||
this.fallbackToLocalWhenFail = fallbackToLocalWhenFail;
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object o) {
|
||||
if (this == o) { return true; }
|
||||
if (o == null || getClass() != o.getClass()) { return false; }
|
||||
|
||||
ParamFlowClusterConfig that = (ParamFlowClusterConfig)o;
|
||||
|
||||
if (thresholdType != that.thresholdType) { return false; }
|
||||
if (fallbackToLocalWhenFail != that.fallbackToLocalWhenFail) { return false; }
|
||||
return flowId != null ? flowId.equals(that.flowId) : that.flowId == null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
int result = flowId != null ? flowId.hashCode() : 0;
|
||||
result = 31 * result + thresholdType;
|
||||
result = 31 * result + (fallbackToLocalWhenFail ? 1 : 0);
|
||||
return result;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "ParamFlowClusterConfig{" +
|
||||
"flowId=" + flowId +
|
||||
", thresholdType=" + thresholdType +
|
||||
", fallbackToLocalWhenFail=" + fallbackToLocalWhenFail +
|
||||
'}';
|
||||
}
|
||||
}
|
||||
|
|
@ -65,6 +65,9 @@ public class ParamFlowRule extends AbstractRule {
|
|||
*/
|
||||
private Map<Object, Integer> hotItems = new HashMap<Object, Integer>();
|
||||
|
||||
private boolean clusterMode = false;
|
||||
private ParamFlowClusterConfig clusterConfig;
|
||||
|
||||
public int getGrade() {
|
||||
return grade;
|
||||
}
|
||||
|
|
@ -110,6 +113,25 @@ public class ParamFlowRule extends AbstractRule {
|
|||
return this;
|
||||
}
|
||||
|
||||
public boolean isClusterMode() {
|
||||
return clusterMode;
|
||||
}
|
||||
|
||||
public ParamFlowRule setClusterMode(boolean clusterMode) {
|
||||
this.clusterMode = clusterMode;
|
||||
return this;
|
||||
}
|
||||
|
||||
public ParamFlowClusterConfig getClusterConfig() {
|
||||
return clusterConfig;
|
||||
}
|
||||
|
||||
public ParamFlowRule setClusterConfig(
|
||||
ParamFlowClusterConfig clusterConfig) {
|
||||
this.clusterConfig = clusterConfig;
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
@Deprecated
|
||||
public boolean passCheck(Context context, DefaultNode node, int count, Object... args) {
|
||||
|
|
@ -126,8 +148,11 @@ public class ParamFlowRule extends AbstractRule {
|
|||
|
||||
if (grade != rule.grade) { return false; }
|
||||
if (Double.compare(rule.count, count) != 0) { return false; }
|
||||
if (clusterMode != rule.clusterMode) { return false; }
|
||||
if (paramIdx != null ? !paramIdx.equals(rule.paramIdx) : rule.paramIdx != null) { return false; }
|
||||
return paramFlowItemList != null ? paramFlowItemList.equals(rule.paramFlowItemList) : rule.paramFlowItemList == null;
|
||||
if (paramFlowItemList != null ? !paramFlowItemList.equals(rule.paramFlowItemList)
|
||||
: rule.paramFlowItemList != null) { return false; }
|
||||
return clusterConfig != null ? clusterConfig.equals(rule.clusterConfig) : rule.clusterConfig == null;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
@ -139,18 +164,20 @@ public class ParamFlowRule extends AbstractRule {
|
|||
temp = Double.doubleToLongBits(count);
|
||||
result = 31 * result + (int)(temp ^ (temp >>> 32));
|
||||
result = 31 * result + (paramFlowItemList != null ? paramFlowItemList.hashCode() : 0);
|
||||
result = 31 * result + (clusterMode ? 1 : 0);
|
||||
result = 31 * result + (clusterConfig != null ? clusterConfig.hashCode() : 0);
|
||||
return result;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "ParamFlowRule{" +
|
||||
"resource=" + getResource() +
|
||||
", limitApp=" + getLimitApp() +
|
||||
", grade=" + grade +
|
||||
"grade=" + grade +
|
||||
", paramIdx=" + paramIdx +
|
||||
", count=" + count +
|
||||
", paramFlowItemList=" + paramFlowItemList +
|
||||
", clusterMode=" + clusterMode +
|
||||
", clusterConfig=" + clusterConfig +
|
||||
'}';
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -99,37 +99,6 @@ public final class ParamFlowRuleManager {
|
|||
return rules;
|
||||
}
|
||||
|
||||
private static Object parseValue(String value, String classType) {
|
||||
if (value == null) {
|
||||
throw new IllegalArgumentException("Null value");
|
||||
}
|
||||
if (StringUtil.isBlank(classType)) {
|
||||
// If the class type is not provided, then treat it as string.
|
||||
return value;
|
||||
}
|
||||
// Handle primitive type.
|
||||
if (int.class.toString().equals(classType) || Integer.class.getName().equals(classType)) {
|
||||
return Integer.parseInt(value);
|
||||
} else if (boolean.class.toString().equals(classType) || Boolean.class.getName().equals(classType)) {
|
||||
return Boolean.parseBoolean(value);
|
||||
} else if (long.class.toString().equals(classType) || Long.class.getName().equals(classType)) {
|
||||
return Long.parseLong(value);
|
||||
} else if (double.class.toString().equals(classType) || Double.class.getName().equals(classType)) {
|
||||
return Double.parseDouble(value);
|
||||
} else if (float.class.toString().equals(classType) || Float.class.getName().equals(classType)) {
|
||||
return Float.parseFloat(value);
|
||||
} else if (byte.class.toString().equals(classType) || Byte.class.getName().equals(classType)) {
|
||||
return Byte.parseByte(value);
|
||||
} else if (short.class.toString().equals(classType) || Short.class.getName().equals(classType)) {
|
||||
return Short.parseShort(value);
|
||||
} else if (char.class.toString().equals(classType)) {
|
||||
char[] array = value.toCharArray();
|
||||
return array.length > 0 ? array[0] : null;
|
||||
}
|
||||
|
||||
return value;
|
||||
}
|
||||
|
||||
static class RulePropertyListener implements PropertyListener<List<ParamFlowRule>> {
|
||||
|
||||
@Override
|
||||
|
|
@ -163,7 +132,7 @@ public final class ParamFlowRuleManager {
|
|||
}
|
||||
|
||||
for (ParamFlowRule rule : list) {
|
||||
if (!isValidRule(rule)) {
|
||||
if (!ParamFlowRuleUtil.isValidRule(rule)) {
|
||||
RecordLog.warn("[ParamFlowRuleManager] Ignoring invalid rule when loading new rules: " + rule);
|
||||
continue;
|
||||
}
|
||||
|
|
@ -172,12 +141,7 @@ public final class ParamFlowRuleManager {
|
|||
rule.setLimitApp(RuleConstant.LIMIT_APP_DEFAULT);
|
||||
}
|
||||
|
||||
if (rule.getParamFlowItemList() == null) {
|
||||
rule.setParamFlowItemList(new ArrayList<ParamFlowItem>());
|
||||
}
|
||||
|
||||
Map<Object, Integer> itemMap = parseHotItems(rule.getParamFlowItemList());
|
||||
rule.setParsedHotItems(itemMap);
|
||||
ParamFlowRuleUtil.fillExceptionFlowItems(rule);
|
||||
|
||||
String resourceName = rule.getResource();
|
||||
List<ParamFlowRule> ruleList = newRuleMap.get(resourceName);
|
||||
|
|
@ -200,34 +164,6 @@ public final class ParamFlowRuleManager {
|
|||
}
|
||||
}
|
||||
|
||||
static Map<Object, Integer> parseHotItems(List<ParamFlowItem> items) {
|
||||
Map<Object, Integer> itemMap = new HashMap<Object, Integer>();
|
||||
if (items == null || items.isEmpty()) {
|
||||
return itemMap;
|
||||
}
|
||||
for (ParamFlowItem item : items) {
|
||||
// Value should not be null.
|
||||
Object value;
|
||||
try {
|
||||
value = parseValue(item.getObject(), item.getClassType());
|
||||
} catch (Exception ex) {
|
||||
RecordLog.warn("[ParamFlowRuleManager] Failed to parse value for item: " + item, ex);
|
||||
continue;
|
||||
}
|
||||
if (item.getCount() == null || item.getCount() < 0 || value == null) {
|
||||
RecordLog.warn("[ParamFlowRuleManager] Ignoring invalid exclusion parameter item: " + item);
|
||||
continue;
|
||||
}
|
||||
itemMap.put(value, item.getCount());
|
||||
}
|
||||
return itemMap;
|
||||
}
|
||||
|
||||
static boolean isValidRule(ParamFlowRule rule) {
|
||||
return rule != null && !StringUtil.isBlank(rule.getResource()) && rule.getCount() >= 0
|
||||
&& rule.getParamIdx() != null && rule.getParamIdx() >= 0;
|
||||
}
|
||||
|
||||
private ParamFlowRuleManager() {}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -0,0 +1,114 @@
|
|||
/*
|
||||
* Copyright 1999-2018 Alibaba Group Holding Ltd.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package com.alibaba.csp.sentinel.slots.block.flow.param;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import com.alibaba.csp.sentinel.log.RecordLog;
|
||||
import com.alibaba.csp.sentinel.util.StringUtil;
|
||||
|
||||
/**
|
||||
* @author Eric Zhao
|
||||
*/
|
||||
public final class ParamFlowRuleUtil {
|
||||
|
||||
public static boolean isValidRule(ParamFlowRule rule) {
|
||||
return rule != null && !StringUtil.isBlank(rule.getResource()) && rule.getCount() >= 0
|
||||
&& rule.getParamIdx() != null && rule.getParamIdx() >= 0 && checkCluster(rule);
|
||||
}
|
||||
|
||||
private static boolean checkCluster(/*@PreChecked*/ ParamFlowRule rule) {
|
||||
if (!rule.isClusterMode()) {
|
||||
return true;
|
||||
}
|
||||
ParamFlowClusterConfig clusterConfig = rule.getClusterConfig();
|
||||
return clusterConfig != null && validClusterRuleId(clusterConfig.getFlowId());
|
||||
}
|
||||
|
||||
public static boolean validClusterRuleId(Long id) {
|
||||
return id != null && id > 0;
|
||||
}
|
||||
|
||||
public static void fillExceptionFlowItems(ParamFlowRule rule) {
|
||||
if (rule != null) {
|
||||
if (rule.getParamFlowItemList() == null) {
|
||||
rule.setParamFlowItemList(new ArrayList<ParamFlowItem>());
|
||||
}
|
||||
|
||||
Map<Object, Integer> itemMap = parseHotItems(rule.getParamFlowItemList());
|
||||
rule.setParsedHotItems(itemMap);
|
||||
}
|
||||
}
|
||||
|
||||
static Map<Object, Integer> parseHotItems(List<ParamFlowItem> items) {
|
||||
Map<Object, Integer> itemMap = new HashMap<Object, Integer>();
|
||||
if (items == null || items.isEmpty()) {
|
||||
return itemMap;
|
||||
}
|
||||
for (ParamFlowItem item : items) {
|
||||
// Value should not be null.
|
||||
Object value;
|
||||
try {
|
||||
value = parseItemValue(item.getObject(), item.getClassType());
|
||||
} catch (Exception ex) {
|
||||
RecordLog.warn("[ParamFlowRuleUtil] Failed to parse value for item: " + item, ex);
|
||||
continue;
|
||||
}
|
||||
if (item.getCount() == null || item.getCount() < 0 || value == null) {
|
||||
RecordLog.warn("[ParamFlowRuleUtil] Ignoring invalid exclusion parameter item: " + item);
|
||||
continue;
|
||||
}
|
||||
itemMap.put(value, item.getCount());
|
||||
}
|
||||
return itemMap;
|
||||
}
|
||||
|
||||
static Object parseItemValue(String value, String classType) {
|
||||
if (value == null) {
|
||||
throw new IllegalArgumentException("Null value");
|
||||
}
|
||||
if (StringUtil.isBlank(classType)) {
|
||||
// If the class type is not provided, then treat it as string.
|
||||
return value;
|
||||
}
|
||||
// Handle primitive type.
|
||||
if (int.class.toString().equals(classType) || Integer.class.getName().equals(classType)) {
|
||||
return Integer.parseInt(value);
|
||||
} else if (boolean.class.toString().equals(classType) || Boolean.class.getName().equals(classType)) {
|
||||
return Boolean.parseBoolean(value);
|
||||
} else if (long.class.toString().equals(classType) || Long.class.getName().equals(classType)) {
|
||||
return Long.parseLong(value);
|
||||
} else if (double.class.toString().equals(classType) || Double.class.getName().equals(classType)) {
|
||||
return Double.parseDouble(value);
|
||||
} else if (float.class.toString().equals(classType) || Float.class.getName().equals(classType)) {
|
||||
return Float.parseFloat(value);
|
||||
} else if (byte.class.toString().equals(classType) || Byte.class.getName().equals(classType)) {
|
||||
return Byte.parseByte(value);
|
||||
} else if (short.class.toString().equals(classType) || Short.class.getName().equals(classType)) {
|
||||
return Short.parseShort(value);
|
||||
} else if (char.class.toString().equals(classType)) {
|
||||
char[] array = value.toCharArray();
|
||||
return array.length > 0 ? array[0] : null;
|
||||
}
|
||||
|
||||
return value;
|
||||
}
|
||||
|
||||
private ParamFlowRuleUtil() {}
|
||||
}
|
||||
|
|
@ -15,11 +15,9 @@
|
|||
*/
|
||||
package com.alibaba.csp.sentinel.slots.block.flow.param;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import com.alibaba.csp.sentinel.EntryType;
|
||||
import com.alibaba.csp.sentinel.slotchain.StringResourceWrapper;
|
||||
|
|
@ -109,84 +107,4 @@ public class ParamFlowRuleManagerTest {
|
|||
assertTrue(allRules.contains(ruleC));
|
||||
assertTrue(allRules.contains(ruleD));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testParseHotParamExceptionItemsFailure() {
|
||||
String valueB = "Sentinel";
|
||||
Integer valueC = 6;
|
||||
char valueD = 6;
|
||||
float valueE = 11.11f;
|
||||
// Null object will not be parsed.
|
||||
ParamFlowItem itemA = new ParamFlowItem(null, 1, double.class.getName());
|
||||
// Hot item with empty class type will be treated as string.
|
||||
ParamFlowItem itemB = new ParamFlowItem(valueB, 3, null);
|
||||
ParamFlowItem itemE = new ParamFlowItem(String.valueOf(valueE), 3, "");
|
||||
// Bad count will not be parsed.
|
||||
ParamFlowItem itemC = ParamFlowItem.newItem(valueC, -5);
|
||||
ParamFlowItem itemD = new ParamFlowItem(String.valueOf(valueD), null, char.class.getName());
|
||||
|
||||
List<ParamFlowItem> badItems = Arrays.asList(itemA, itemB, itemC, itemD, itemE);
|
||||
Map<Object, Integer> parsedItems = ParamFlowRuleManager.parseHotItems(badItems);
|
||||
|
||||
// Value B and E will be parsed, but ignoring the type.
|
||||
assertEquals(2, parsedItems.size());
|
||||
assertEquals(itemB.getCount(), parsedItems.get(valueB));
|
||||
assertFalse(parsedItems.containsKey(valueE));
|
||||
assertEquals(itemE.getCount(), parsedItems.get(String.valueOf(valueE)));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testParseHotParamExceptionItemsSuccess() {
|
||||
// Test for empty list.
|
||||
assertEquals(0, ParamFlowRuleManager.parseHotItems(null).size());
|
||||
assertEquals(0, ParamFlowRuleManager.parseHotItems(new ArrayList<ParamFlowItem>()).size());
|
||||
|
||||
// Test for boxing objects and primitive types.
|
||||
Double valueA = 1.1d;
|
||||
String valueB = "Sentinel";
|
||||
Integer valueC = 6;
|
||||
char valueD = 'c';
|
||||
ParamFlowItem itemA = ParamFlowItem.newItem(valueA, 1);
|
||||
ParamFlowItem itemB = ParamFlowItem.newItem(valueB, 3);
|
||||
ParamFlowItem itemC = ParamFlowItem.newItem(valueC, 5);
|
||||
ParamFlowItem itemD = new ParamFlowItem().setObject(String.valueOf(valueD))
|
||||
.setClassType(char.class.getName())
|
||||
.setCount(7);
|
||||
List<ParamFlowItem> items = Arrays.asList(itemA, itemB, itemC, itemD);
|
||||
Map<Object, Integer> parsedItems = ParamFlowRuleManager.parseHotItems(items);
|
||||
assertEquals(itemA.getCount(), parsedItems.get(valueA));
|
||||
assertEquals(itemB.getCount(), parsedItems.get(valueB));
|
||||
assertEquals(itemC.getCount(), parsedItems.get(valueC));
|
||||
assertEquals(itemD.getCount(), parsedItems.get(valueD));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testCheckValidHotParamRule() {
|
||||
// Null or empty resource;
|
||||
ParamFlowRule rule1 = new ParamFlowRule();
|
||||
ParamFlowRule rule2 = new ParamFlowRule("");
|
||||
assertFalse(ParamFlowRuleManager.isValidRule(null));
|
||||
assertFalse(ParamFlowRuleManager.isValidRule(rule1));
|
||||
assertFalse(ParamFlowRuleManager.isValidRule(rule2));
|
||||
|
||||
// Invalid threshold count.
|
||||
ParamFlowRule rule3 = new ParamFlowRule("abc")
|
||||
.setCount(-1)
|
||||
.setParamIdx(1);
|
||||
assertFalse(ParamFlowRuleManager.isValidRule(rule3));
|
||||
|
||||
// Parameter index not set or invalid.
|
||||
ParamFlowRule rule4 = new ParamFlowRule("abc")
|
||||
.setCount(1);
|
||||
ParamFlowRule rule5 = new ParamFlowRule("abc")
|
||||
.setCount(1)
|
||||
.setParamIdx(-1);
|
||||
assertFalse(ParamFlowRuleManager.isValidRule(rule4));
|
||||
assertFalse(ParamFlowRuleManager.isValidRule(rule5));
|
||||
|
||||
ParamFlowRule goodRule = new ParamFlowRule("abc")
|
||||
.setCount(10)
|
||||
.setParamIdx(1);
|
||||
assertTrue(ParamFlowRuleManager.isValidRule(goodRule));
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,95 @@
|
|||
package com.alibaba.csp.sentinel.slots.block.flow.param;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import org.junit.Test;
|
||||
|
||||
import static org.junit.Assert.*;
|
||||
|
||||
/**
|
||||
* @author Eric Zhao
|
||||
*/
|
||||
public class ParamFlowRuleUtilTest {
|
||||
@Test
|
||||
public void testCheckValidHotParamRule() {
|
||||
// Null or empty resource;
|
||||
ParamFlowRule rule1 = new ParamFlowRule();
|
||||
ParamFlowRule rule2 = new ParamFlowRule("");
|
||||
assertFalse(ParamFlowRuleUtil.isValidRule(null));
|
||||
assertFalse(ParamFlowRuleUtil.isValidRule(rule1));
|
||||
assertFalse(ParamFlowRuleUtil.isValidRule(rule2));
|
||||
|
||||
// Invalid threshold count.
|
||||
ParamFlowRule rule3 = new ParamFlowRule("abc")
|
||||
.setCount(-1)
|
||||
.setParamIdx(1);
|
||||
assertFalse(ParamFlowRuleUtil.isValidRule(rule3));
|
||||
|
||||
// Parameter index not set or invalid.
|
||||
ParamFlowRule rule4 = new ParamFlowRule("abc")
|
||||
.setCount(1);
|
||||
ParamFlowRule rule5 = new ParamFlowRule("abc")
|
||||
.setCount(1)
|
||||
.setParamIdx(-1);
|
||||
assertFalse(ParamFlowRuleUtil.isValidRule(rule4));
|
||||
assertFalse(ParamFlowRuleUtil.isValidRule(rule5));
|
||||
|
||||
ParamFlowRule goodRule = new ParamFlowRule("abc")
|
||||
.setCount(10)
|
||||
.setParamIdx(1);
|
||||
assertTrue(ParamFlowRuleUtil.isValidRule(goodRule));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testParseHotParamExceptionItemsFailure() {
|
||||
String valueB = "Sentinel";
|
||||
Integer valueC = 6;
|
||||
char valueD = 6;
|
||||
float valueE = 11.11f;
|
||||
// Null object will not be parsed.
|
||||
ParamFlowItem itemA = new ParamFlowItem(null, 1, double.class.getName());
|
||||
// Hot item with empty class type will be treated as string.
|
||||
ParamFlowItem itemB = new ParamFlowItem(valueB, 3, null);
|
||||
ParamFlowItem itemE = new ParamFlowItem(String.valueOf(valueE), 3, "");
|
||||
// Bad count will not be parsed.
|
||||
ParamFlowItem itemC = ParamFlowItem.newItem(valueC, -5);
|
||||
ParamFlowItem itemD = new ParamFlowItem(String.valueOf(valueD), null, char.class.getName());
|
||||
|
||||
List<ParamFlowItem> badItems = Arrays.asList(itemA, itemB, itemC, itemD, itemE);
|
||||
Map<Object, Integer> parsedItems = ParamFlowRuleUtil.parseHotItems(badItems);
|
||||
|
||||
// Value B and E will be parsed, but ignoring the type.
|
||||
assertEquals(2, parsedItems.size());
|
||||
assertEquals(itemB.getCount(), parsedItems.get(valueB));
|
||||
assertFalse(parsedItems.containsKey(valueE));
|
||||
assertEquals(itemE.getCount(), parsedItems.get(String.valueOf(valueE)));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testParseHotParamExceptionItemsSuccess() {
|
||||
// Test for empty list.
|
||||
assertEquals(0, ParamFlowRuleUtil.parseHotItems(null).size());
|
||||
assertEquals(0, ParamFlowRuleUtil.parseHotItems(new ArrayList<ParamFlowItem>()).size());
|
||||
|
||||
// Test for boxing objects and primitive types.
|
||||
Double valueA = 1.1d;
|
||||
String valueB = "Sentinel";
|
||||
Integer valueC = 6;
|
||||
char valueD = 'c';
|
||||
ParamFlowItem itemA = ParamFlowItem.newItem(valueA, 1);
|
||||
ParamFlowItem itemB = ParamFlowItem.newItem(valueB, 3);
|
||||
ParamFlowItem itemC = ParamFlowItem.newItem(valueC, 5);
|
||||
ParamFlowItem itemD = new ParamFlowItem().setObject(String.valueOf(valueD))
|
||||
.setClassType(char.class.getName())
|
||||
.setCount(7);
|
||||
List<ParamFlowItem> items = Arrays.asList(itemA, itemB, itemC, itemD);
|
||||
Map<Object, Integer> parsedItems = ParamFlowRuleUtil.parseHotItems(items);
|
||||
assertEquals(itemA.getCount(), parsedItems.get(valueA));
|
||||
assertEquals(itemB.getCount(), parsedItems.get(valueB));
|
||||
assertEquals(itemC.getCount(), parsedItems.get(valueC));
|
||||
assertEquals(itemD.getCount(), parsedItems.get(valueD));
|
||||
}
|
||||
}
|
||||
Loading…
Reference in New Issue