1
0
mirror of https://gitee.com/mirrors/Spring-Cloud-Alibaba.git synced 2021-06-26 13:25:11 +08:00

sync sentinel to 1.x branch

This commit is contained in:
fangjian0423
2019-02-18 21:07:14 +08:00
parent 5a5ff5c444
commit b0ed3d8642
40 changed files with 1155 additions and 1258 deletions

View File

@@ -83,13 +83,19 @@
<optional>true</optional>
</dependency>
<dependency>
<groupId>javax.validation</groupId>
<artifactId>validation-api</artifactId>
<version>2.0.1.Final</version>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
</dependencies>
</project>

View File

@@ -1,135 +0,0 @@
/*
* Copyright (C) 2018 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* 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 org.springframework.cloud.alibaba.sentinel.datasource;
import java.util.Properties;
import java.util.concurrent.ArrayBlockingQueue;
import java.util.concurrent.Executor;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;
import com.alibaba.csp.sentinel.concurrent.NamedThreadFactory;
import com.alibaba.csp.sentinel.datasource.AbstractDataSource;
import com.alibaba.csp.sentinel.datasource.Converter;
import com.alibaba.csp.sentinel.datasource.nacos.NacosDataSource;
import com.alibaba.csp.sentinel.log.RecordLog;
import com.alibaba.csp.sentinel.util.StringUtil;
import com.alibaba.nacos.api.NacosFactory;
import com.alibaba.nacos.api.config.ConfigService;
import com.alibaba.nacos.api.config.listener.Listener;
/**
* {@link NacosDataSource} now is not support ak、sknamespace and endpoint. This class may
* be delete when {@link NacosDataSource} support commercialized
*
* @author <a href="mailto:fangjian0423@gmail.com">Jim</a>
*/
public class NacosDataSourceWithAuthorization<T> extends AbstractDataSource<String, T> {
private static final int DEFAULT_TIMEOUT = 3000;
private final ExecutorService pool = new ThreadPoolExecutor(1, 1, 0,
TimeUnit.MILLISECONDS, new ArrayBlockingQueue<Runnable>(1),
new NamedThreadFactory("sentinel-nacos-auth-ds-update"),
new ThreadPoolExecutor.DiscardOldestPolicy());
private final Listener configListener;
private final Properties properties;
private final String dataId;
private final String groupId;
private ConfigService configService = null;
public NacosDataSourceWithAuthorization(final Properties properties,
final String groupId, final String dataId, Converter<String, T> parser) {
super(parser);
if (StringUtil.isBlank(groupId) || StringUtil.isBlank(dataId)) {
throw new IllegalArgumentException(String
.format("Bad argument: groupId=[%s], dataId=[%s]", groupId, dataId));
}
this.groupId = groupId;
this.dataId = dataId;
this.properties = properties;
this.configListener = new Listener() {
@Override
public Executor getExecutor() {
return pool;
}
@Override
public void receiveConfigInfo(final String configInfo) {
RecordLog.info(String.format(
"[NacosDataSourceWithAuthorization] New property value received for %s",
properties.toString()));
T newValue = NacosDataSourceWithAuthorization.this.parser
.convert(configInfo);
// Update the new value to the property.
getProperty().updateValue(newValue);
}
};
initNacosListener();
loadInitialConfig();
}
private void loadInitialConfig() {
try {
T newValue = loadConfig();
if (newValue == null) {
RecordLog.warn(
"[NacosDataSourceWithAuthorization] WARN: initial config is null, you may have to check your data source");
}
getProperty().updateValue(newValue);
}
catch (Exception ex) {
RecordLog.warn(
"[NacosDataSourceWithAuthorization] Error when loading initial config",
ex);
}
}
private void initNacosListener() {
try {
this.configService = NacosFactory.createConfigService(properties);
// Add config listener.
configService.addListener(dataId, groupId, configListener);
}
catch (Exception e) {
RecordLog.warn(
"[NacosDataSourceWithAuthorization] Error occurred when initializing Nacos data source",
e);
e.printStackTrace();
}
}
@Override
public String readSource() throws Exception {
if (configService == null) {
throw new IllegalStateException(
"Nacos config service has not been initialized or error occurred");
}
return configService.getConfig(dataId, groupId, DEFAULT_TIMEOUT);
}
@Override
public void close() {
if (configService != null) {
configService.removeListener(dataId, groupId, configListener);
}
pool.shutdownNow();
}
}

View File

@@ -0,0 +1,102 @@
/*
* Copyright (C) 2018 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* 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 org.springframework.cloud.alibaba.sentinel.datasource;
import org.springframework.cloud.alibaba.sentinel.datasource.config.AbstractDataSourceProperties;
import org.springframework.util.StringUtils;
import com.alibaba.csp.sentinel.slots.block.AbstractRule;
import com.alibaba.csp.sentinel.slots.block.authority.AuthorityRule;
import com.alibaba.csp.sentinel.slots.block.degrade.DegradeRule;
import com.alibaba.csp.sentinel.slots.block.flow.FlowRule;
import com.alibaba.csp.sentinel.slots.block.flow.param.ParamFlowRule;
import com.alibaba.csp.sentinel.slots.system.SystemRule;
/**
* Enum for {@link AbstractRule} class, using in
* {@link AbstractDataSourceProperties#ruleType}
*
* @author <a href="mailto:fangjian0423@gmail.com">Jim</a>
*/
public enum RuleType {
/**
* flow
*/
FLOW("flow", FlowRule.class),
/**
* degrade
*/
DEGRADE("degrade", DegradeRule.class),
/**
* param flow
*/
PARAM_FLOW("param-flow", ParamFlowRule.class),
/**
* system
*/
SYSTEM("system", SystemRule.class),
/**
* authority
*/
AUTHORITY("authority", AuthorityRule.class);
/**
* alias for {@link AbstractRule}
*/
private final String name;
/**
* concrete {@link AbstractRule} class
*/
private final Class clazz;
RuleType(String name, Class clazz) {
this.name = name;
this.clazz = clazz;
}
public String getName() {
return name;
}
public Class getClazz() {
return clazz;
}
public static RuleType getByName(String name) {
if (StringUtils.isEmpty(name)) {
return null;
}
for (RuleType ruleType : RuleType.values()) {
if (name.equals(ruleType.getName())) {
return ruleType;
}
}
return null;
}
public static RuleType getByClass(Class clazz) {
for (RuleType ruleType : RuleType.values()) {
if (clazz.equals(ruleType.getClazz())) {
return ruleType;
}
}
return null;
}
}

View File

@@ -23,14 +23,4 @@ public interface SentinelDataSourceConstants {
String PROPERTY_PREFIX = "spring.cloud.sentinel";
String NACOS_DATASOURCE_AK = PROPERTY_PREFIX + ".nacos.config.access-key";
String NACOS_DATASOURCE_SK = PROPERTY_PREFIX + ".nacos.config.secret-key";
String NACOS_DATASOURCE_NAMESPACE = PROPERTY_PREFIX + ".nacos.config.namespace";
String NACOS_DATASOURCE_ENDPOINT = PROPERTY_PREFIX + ".nacos.config.endpoint";
String PROJECT_NAME = PROPERTY_PREFIX + ".nacos.config.project-name";
}

View File

@@ -1,5 +1,33 @@
/*
* Copyright (C) 2018 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* 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 org.springframework.cloud.alibaba.sentinel.datasource.config;
import javax.validation.constraints.NotEmpty;
import javax.validation.constraints.NotNull;
import org.springframework.cloud.alibaba.sentinel.datasource.RuleType;
import com.alibaba.csp.sentinel.datasource.AbstractDataSource;
import com.alibaba.csp.sentinel.slots.block.authority.AuthorityRuleManager;
import com.alibaba.csp.sentinel.slots.block.degrade.DegradeRuleManager;
import com.alibaba.csp.sentinel.slots.block.flow.FlowRuleManager;
import com.alibaba.csp.sentinel.slots.block.flow.param.ParamFlowRuleManager;
import com.alibaba.csp.sentinel.slots.system.SystemRuleManager;
import com.fasterxml.jackson.annotation.JsonIgnore;
/**
@@ -9,10 +37,13 @@ import com.fasterxml.jackson.annotation.JsonIgnore;
*/
public class AbstractDataSourceProperties {
@NotEmpty
private String dataType = "json";
@NotNull
private RuleType ruleType;
private String converterClass;
@JsonIgnore
protected String factoryBeanName;
private final String factoryBeanName;
public AbstractDataSourceProperties(String factoryBeanName) {
this.factoryBeanName = factoryBeanName;
@@ -26,6 +57,14 @@ public class AbstractDataSourceProperties {
this.dataType = dataType;
}
public RuleType getRuleType() {
return ruleType;
}
public void setRuleType(RuleType ruleType) {
this.ruleType = ruleType;
}
public String getConverterClass() {
return converterClass;
}
@@ -38,12 +77,29 @@ public class AbstractDataSourceProperties {
return factoryBeanName;
}
public void setFactoryBeanName(String factoryBeanName) {
this.factoryBeanName = factoryBeanName;
}
public void preCheck() {
public void preCheck(String dataSourceName) {
}
}
public void postRegister(AbstractDataSource dataSource) {
switch (this.getRuleType()) {
case FLOW:
FlowRuleManager.register2Property(dataSource.getProperty());
break;
case DEGRADE:
DegradeRuleManager.register2Property(dataSource.getProperty());
break;
case PARAM_FLOW:
ParamFlowRuleManager.register2Property(dataSource.getProperty());
break;
case SYSTEM:
SystemRuleManager.register2Property(dataSource.getProperty());
break;
case AUTHORITY:
AuthorityRuleManager.register2Property(dataSource.getProperty());
break;
default:
break;
}
}
}

View File

@@ -1,5 +1,23 @@
/*
* Copyright (C) 2018 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* 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 org.springframework.cloud.alibaba.sentinel.datasource.config;
import javax.validation.constraints.NotEmpty;
import org.springframework.cloud.alibaba.sentinel.datasource.factorybean.ApolloDataSourceFactoryBean;
/**
@@ -10,7 +28,9 @@ import org.springframework.cloud.alibaba.sentinel.datasource.factorybean.ApolloD
*/
public class ApolloDataSourceProperties extends AbstractDataSourceProperties {
@NotEmpty
private String namespaceName;
@NotEmpty
private String flowRulesKey;
private String defaultFlowRuleValue;

View File

@@ -1,7 +1,25 @@
/*
* Copyright (C) 2018 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* 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 org.springframework.cloud.alibaba.sentinel.datasource.config;
import java.io.IOException;
import javax.validation.constraints.NotEmpty;
import org.springframework.cloud.alibaba.sentinel.datasource.factorybean.FileRefreshableDataSourceFactoryBean;
import org.springframework.util.ResourceUtils;
import org.springframework.util.StringUtils;
@@ -14,6 +32,7 @@ import org.springframework.util.StringUtils;
*/
public class FileDataSourceProperties extends AbstractDataSourceProperties {
@NotEmpty
private String file;
private String charset = "utf-8";
private long recommendRefreshMs = 3000L;
@@ -56,16 +75,17 @@ public class FileDataSourceProperties extends AbstractDataSourceProperties {
}
@Override
public void preCheck() {
super.preCheck();
public void preCheck(String dataSourceName) {
super.preCheck(dataSourceName);
try {
this.setFile(
ResourceUtils.getFile(StringUtils.trimAllWhitespace(this.getFile()))
.getAbsolutePath());
}
catch (IOException e) {
throw new RuntimeException("[Sentinel Starter] " + " handle file ["
+ this.getFile() + "] error: " + e.getMessage(), e);
throw new RuntimeException("[Sentinel Starter] DataSource " + dataSourceName
+ " handle file [" + this.getFile() + "] error: " + e.getMessage(),
e);
}
}

View File

@@ -1,8 +1,24 @@
/*
* Copyright (C) 2018 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* 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 org.springframework.cloud.alibaba.sentinel.datasource.config;
import org.springframework.cloud.alibaba.sentinel.datasource.SentinelDataSourceConstants;
import javax.validation.constraints.NotEmpty;
import org.springframework.cloud.alibaba.sentinel.datasource.factorybean.NacosDataSourceFactoryBean;
import org.springframework.cloud.alibaba.sentinel.datasource.factorybean.NacosDataSourceWithAuthorizationFactoryBean;
import org.springframework.util.StringUtils;
/**
@@ -14,10 +30,12 @@ import org.springframework.util.StringUtils;
public class NacosDataSourceProperties extends AbstractDataSourceProperties {
private String serverAddr;
private String groupId;
private String dataId;
// commercialized usage
@NotEmpty
private String groupId = "DEFAULT_GROUP";
@NotEmpty
private String dataId;
private String endpoint;
private String namespace;
@@ -29,20 +47,10 @@ public class NacosDataSourceProperties extends AbstractDataSourceProperties {
}
@Override
public void preCheck() {
if (!StringUtils.isEmpty(System.getProperties()
.getProperty(SentinelDataSourceConstants.NACOS_DATASOURCE_ENDPOINT))) {
this.setServerAddr(null);
this.setFactoryBeanName(
NacosDataSourceWithAuthorizationFactoryBean.class.getName());
this.setEndpoint(System.getProperties()
.getProperty(SentinelDataSourceConstants.NACOS_DATASOURCE_ENDPOINT));
this.setNamespace(System.getProperties()
.getProperty(SentinelDataSourceConstants.NACOS_DATASOURCE_NAMESPACE));
this.setAccessKey(System.getProperties()
.getProperty(SentinelDataSourceConstants.NACOS_DATASOURCE_AK));
this.setSecretKey(System.getProperties()
.getProperty(SentinelDataSourceConstants.NACOS_DATASOURCE_SK));
public void preCheck(String dataSourceName) {
if (StringUtils.isEmpty(serverAddr) && acmPropertiesInvalid()) {
throw new IllegalArgumentException(
"NacosDataSource properties value not correct. serverAddr is empty but there is empty value in accessKey, secretKey, endpoint, namespace property");
}
}
@@ -102,30 +110,9 @@ public class NacosDataSourceProperties extends AbstractDataSourceProperties {
this.secretKey = secretKey;
}
public static NacosDataSourceProperties buildFlowByEDAS() {
return buildByEDAS("flow");
public boolean acmPropertiesInvalid() {
return StringUtils.isEmpty(endpoint) || StringUtils.isEmpty(accessKey)
|| StringUtils.isEmpty(secretKey) || StringUtils.isEmpty(namespace);
}
public static NacosDataSourceProperties buildDegradeByEDAS() {
return buildByEDAS("degrade");
}
public static NacosDataSourceProperties buildByEDAS(String type) {
NacosDataSourceProperties result = new NacosDataSourceProperties();
result.setFactoryBeanName(
NacosDataSourceWithAuthorizationFactoryBean.class.getName());
result.setEndpoint(System.getProperties()
.getProperty(SentinelDataSourceConstants.NACOS_DATASOURCE_ENDPOINT));
result.setNamespace(System.getProperties()
.getProperty(SentinelDataSourceConstants.NACOS_DATASOURCE_NAMESPACE));
result.setAccessKey(System.getProperties()
.getProperty(SentinelDataSourceConstants.NACOS_DATASOURCE_AK));
result.setSecretKey(System.getProperties()
.getProperty(SentinelDataSourceConstants.NACOS_DATASOURCE_SK));
result.setDataType("json");
result.setDataId(System.getProperties()
.getProperty(SentinelDataSourceConstants.PROJECT_NAME) + "-" + type);
result.setGroupId("nacos-sentinel");
return result;
}
}

View File

@@ -1,5 +1,23 @@
/*
* Copyright (C) 2018 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* 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 org.springframework.cloud.alibaba.sentinel.datasource.config;
import javax.validation.constraints.NotEmpty;
import org.springframework.cloud.alibaba.sentinel.datasource.factorybean.ZookeeperDataSourceFactoryBean;
/**
@@ -14,6 +32,7 @@ public class ZookeeperDataSourceProperties extends AbstractDataSourceProperties
super(ZookeeperDataSourceFactoryBean.class.getName());
}
@NotEmpty
private String serverAddr;
private String path;

View File

@@ -1,27 +1,27 @@
/*
* Copyright (C) 2018 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* 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 org.springframework.cloud.alibaba.sentinel.datasource.converter;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.util.ObjectUtils;
import org.springframework.util.StringUtils;
import com.alibaba.csp.sentinel.datasource.Converter;
import com.alibaba.csp.sentinel.slots.block.AbstractRule;
import com.alibaba.csp.sentinel.slots.block.authority.AuthorityRule;
import com.alibaba.csp.sentinel.slots.block.degrade.DegradeRule;
import com.alibaba.csp.sentinel.slots.block.degrade.DegradeRuleManager;
import com.alibaba.csp.sentinel.slots.block.flow.FlowRule;
import com.alibaba.csp.sentinel.slots.block.flow.FlowRuleUtil;
import com.alibaba.csp.sentinel.slots.block.flow.param.ParamFlowRule;
import com.alibaba.csp.sentinel.slots.system.SystemRule;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.core.type.TypeReference;
import com.fasterxml.jackson.databind.ObjectMapper;
/**
@@ -35,138 +35,10 @@ import com.fasterxml.jackson.databind.ObjectMapper;
* @see ParamFlowRule
* @see ObjectMapper
*/
public class JsonConverter implements Converter<String, List<AbstractRule>> {
public class JsonConverter<T> extends SentinelConverter {
private static final Logger logger = LoggerFactory.getLogger(JsonConverter.class);
private final ObjectMapper objectMapper;
public JsonConverter(ObjectMapper objectMapper) {
this.objectMapper = objectMapper;
}
@Override
public List<AbstractRule> convert(String source) {
List<AbstractRule> ruleList = new ArrayList<>();
if (StringUtils.isEmpty(source)) {
logger.warn(
"Sentinel JsonConverter can not convert rules because source is empty");
return ruleList;
}
try {
List jsonArray = objectMapper.readValue(source,
new TypeReference<List<HashMap>>() {
});
for (Object obj : jsonArray) {
String itemJson = null;
try {
itemJson = objectMapper.writeValueAsString(obj);
}
catch (JsonProcessingException e) {
// won't be happen
}
List<AbstractRule> rules = Arrays.asList(convertFlowRule(itemJson),
convertDegradeRule(itemJson), convertSystemRule(itemJson),
convertAuthorityRule(itemJson), convertParamFlowRule(itemJson));
List<AbstractRule> convertRuleList = new ArrayList<>();
for (AbstractRule rule : rules) {
if (!ObjectUtils.isEmpty(rule)) {
convertRuleList.add(rule);
}
}
if (convertRuleList.size() == 0) {
logger.warn(
"Sentinel JsonConverter can not convert {} to any rules, ignore",
itemJson);
}
else if (convertRuleList.size() > 1) {
logger.warn(
"Sentinel JsonConverter convert {} and match multi rules, ignore",
itemJson);
}
else {
ruleList.add(convertRuleList.get(0));
}
}
if (jsonArray.size() != ruleList.size()) {
logger.warn(
"Sentinel JsonConverter Source list size is not equals to Target List, maybe a "
+ "part of json is invalid. Source List: " + jsonArray
+ ", Target List: " + ruleList);
}
}
catch (Exception e) {
logger.error("Sentinel JsonConverter convert error: " + e.getMessage());
throw new RuntimeException(
"Sentinel JsonConverter convert error: " + e.getMessage(), e);
}
return ruleList;
}
private FlowRule convertFlowRule(String json) {
try {
FlowRule rule = objectMapper.readValue(json, FlowRule.class);
if (FlowRuleUtil.isValidRule(rule)) {
return rule;
}
}
catch (Exception e) {
// ignore
}
return null;
}
private DegradeRule convertDegradeRule(String json) {
try {
DegradeRule rule = objectMapper.readValue(json, DegradeRule.class);
if (DegradeRuleManager.isValidRule(rule)) {
return rule;
}
}
catch (Exception e) {
// ignore
}
return null;
}
private SystemRule convertSystemRule(String json) {
SystemRule rule = null;
try {
rule = objectMapper.readValue(json, SystemRule.class);
}
catch (Exception e) {
// ignore
}
return rule;
}
private AuthorityRule convertAuthorityRule(String json) {
AuthorityRule rule = null;
try {
rule = objectMapper.readValue(json, AuthorityRule.class);
}
catch (Exception e) {
// ignore
}
return rule;
}
private ParamFlowRule convertParamFlowRule(String json) {
ParamFlowRule rule = null;
try {
rule = objectMapper.readValue(json, ParamFlowRule.class);
}
catch (Exception e) {
// ignore
}
return rule;
public JsonConverter(ObjectMapper objectMapper, Class<T> ruleClass) {
super(objectMapper, ruleClass);
}
}

View File

@@ -0,0 +1,133 @@
/*
* Copyright (C) 2018 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* 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 org.springframework.cloud.alibaba.sentinel.datasource.converter;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.cloud.alibaba.sentinel.datasource.RuleType;
import org.springframework.util.StringUtils;
import com.alibaba.csp.sentinel.datasource.Converter;
import com.alibaba.csp.sentinel.slots.block.AbstractRule;
import com.alibaba.csp.sentinel.slots.block.authority.AuthorityRule;
import com.alibaba.csp.sentinel.slots.block.degrade.DegradeRule;
import com.alibaba.csp.sentinel.slots.block.degrade.DegradeRuleManager;
import com.alibaba.csp.sentinel.slots.block.flow.FlowRule;
import com.alibaba.csp.sentinel.slots.block.flow.FlowRuleUtil;
import com.alibaba.csp.sentinel.slots.block.flow.param.ParamFlowRule;
import com.alibaba.csp.sentinel.slots.system.SystemRule;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.core.type.TypeReference;
import com.fasterxml.jackson.databind.ObjectMapper;
/**
* Convert sentinel rules for json or xml array Using strict mode to parse json or xml
*
* @author <a href="mailto:fangjian0423@gmail.com">Jim</a>
* @see FlowRule
* @see DegradeRule
* @see SystemRule
* @see AuthorityRule
* @see ParamFlowRule
* @see ObjectMapper
*/
public abstract class SentinelConverter<T extends AbstractRule>
implements Converter<String, List<AbstractRule>> {
private static final Logger logger = LoggerFactory.getLogger(SentinelConverter.class);
private final ObjectMapper objectMapper;
private final Class<T> ruleClass;
public SentinelConverter(ObjectMapper objectMapper, Class<T> ruleClass) {
this.objectMapper = objectMapper;
this.ruleClass = ruleClass;
}
@Override
public List<AbstractRule> convert(String source) {
List<AbstractRule> ruleList = new ArrayList<>();
if (StringUtils.isEmpty(source)) {
logger.warn("converter can not convert rules because source is empty");
return ruleList;
}
try {
List sourceArray = objectMapper.readValue(source,
new TypeReference<List<HashMap>>() {
});
for (Object obj : sourceArray) {
String item = null;
try {
item = objectMapper.writeValueAsString(obj);
}
catch (JsonProcessingException e) {
// won't be happen
}
AbstractRule rule = convertRule(item);
if (rule != null) {
ruleList.add(rule);
}
}
if (ruleList.size() != sourceArray.size()) {
throw new IllegalArgumentException("convert " + ruleList.size()
+ " rules but there are " + sourceArray.size()
+ " rules from datasource. RuleClass: "
+ ruleClass.getSimpleName());
}
}
catch (Exception e) {
throw new RuntimeException("convert error: " + e.getMessage(), e);
}
return ruleList;
}
private AbstractRule convertRule(String ruleStr) {
try {
final AbstractRule rule = objectMapper.readValue(ruleStr, ruleClass);
RuleType ruleType = RuleType.getByClass(ruleClass);
switch (ruleType) {
case FLOW:
if (!FlowRuleUtil.isValidRule((FlowRule) rule)) {
return null;
}
break;
case DEGRADE:
if (!DegradeRuleManager.isValidRule((DegradeRule) rule)) {
return null;
}
default:
break;
}
return rule;
}
catch (Exception e) {
// ignore
}
return null;
}
}

View File

@@ -1,27 +1,28 @@
/*
* Copyright (C) 2018 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* 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 org.springframework.cloud.alibaba.sentinel.datasource.converter;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.util.ObjectUtils;
import org.springframework.util.StringUtils;
import com.alibaba.csp.sentinel.datasource.Converter;
import com.alibaba.csp.sentinel.slots.block.AbstractRule;
import com.alibaba.csp.sentinel.slots.block.authority.AuthorityRule;
import com.alibaba.csp.sentinel.slots.block.degrade.DegradeRule;
import com.alibaba.csp.sentinel.slots.block.degrade.DegradeRuleManager;
import com.alibaba.csp.sentinel.slots.block.flow.FlowRule;
import com.alibaba.csp.sentinel.slots.block.flow.FlowRuleUtil;
import com.alibaba.csp.sentinel.slots.block.flow.param.ParamFlowRule;
import com.alibaba.csp.sentinel.slots.system.SystemRule;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.core.type.TypeReference;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.dataformat.xml.XmlMapper;
/**
@@ -33,139 +34,12 @@ import com.fasterxml.jackson.dataformat.xml.XmlMapper;
* @see SystemRule
* @see AuthorityRule
* @see ParamFlowRule
* @see XmlMapper
* @see ObjectMapper
*/
public class XmlConverter implements Converter<String, List<AbstractRule>> {
public class XmlConverter<T> extends SentinelConverter {
private static final Logger logger = LoggerFactory.getLogger(XmlConverter.class);
private final XmlMapper xmlMapper;
public XmlConverter(XmlMapper xmlMapper) {
this.xmlMapper = xmlMapper;
}
@Override
public List<AbstractRule> convert(String source) {
List<AbstractRule> ruleList = new ArrayList<>();
if (StringUtils.isEmpty(source)) {
logger.warn(
"Sentinel XmlConverter can not convert rules because source is empty");
return ruleList;
}
try {
List xmlArray = xmlMapper.readValue(source,
new TypeReference<List<HashMap>>() {
});
for (Object obj : xmlArray) {
String itemXml = null;
try {
itemXml = xmlMapper.writeValueAsString(obj);
}
catch (JsonProcessingException e) {
// won't be happen
}
List<AbstractRule> rules = Arrays.asList(convertFlowRule(itemXml),
convertDegradeRule(itemXml), convertSystemRule(itemXml),
convertAuthorityRule(itemXml), convertParamFlowRule(itemXml));
List<AbstractRule> convertRuleList = new ArrayList<>();
for (AbstractRule rule : rules) {
if (!ObjectUtils.isEmpty(rule)) {
convertRuleList.add(rule);
}
}
if (convertRuleList.size() == 0) {
logger.warn(
"Sentinel XmlConverter can not convert {} to any rules, ignore",
itemXml);
}
else if (convertRuleList.size() > 1) {
logger.warn(
"Sentinel XmlConverter convert {} and match multi rules, ignore",
itemXml);
}
else {
ruleList.add(convertRuleList.get(0));
}
}
if (xmlArray.size() != ruleList.size()) {
logger.warn(
"Sentinel XmlConverter Source list size is not equals to Target List, maybe a "
+ "part of xml is invalid. Source List: " + xmlArray
+ ", Target List: " + ruleList);
}
}
catch (Exception e) {
logger.error("Sentinel XmlConverter convert error: " + e.getMessage());
throw new RuntimeException(
"Sentinel XmlConverter convert error: " + e.getMessage(), e);
}
return ruleList;
}
private FlowRule convertFlowRule(String xml) {
try {
FlowRule rule = xmlMapper.readValue(xml, FlowRule.class);
if (FlowRuleUtil.isValidRule(rule)) {
return rule;
}
}
catch (Exception e) {
// ignore
}
return null;
}
private DegradeRule convertDegradeRule(String xml) {
try {
DegradeRule rule = xmlMapper.readValue(xml, DegradeRule.class);
if (DegradeRuleManager.isValidRule(rule)) {
return rule;
}
}
catch (Exception e) {
// ignore
}
return null;
}
private SystemRule convertSystemRule(String xml) {
SystemRule rule = null;
try {
rule = xmlMapper.readValue(xml, SystemRule.class);
}
catch (Exception e) {
// ignore
}
return rule;
}
private AuthorityRule convertAuthorityRule(String xml) {
AuthorityRule rule = null;
try {
rule = xmlMapper.readValue(xml, AuthorityRule.class);
}
catch (Exception e) {
// ignore
}
return rule;
}
private ParamFlowRule convertParamFlowRule(String json) {
ParamFlowRule rule = null;
try {
rule = xmlMapper.readValue(json, ParamFlowRule.class);
}
catch (Exception e) {
// ignore
}
return rule;
public XmlConverter(XmlMapper xmlMapper, Class<T> ruleClass) {
super(xmlMapper, ruleClass);
}
}

View File

@@ -1,9 +1,29 @@
/*
* Copyright (C) 2018 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* 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 org.springframework.cloud.alibaba.sentinel.datasource.factorybean;
import java.util.Properties;
import org.springframework.beans.factory.FactoryBean;
import org.springframework.util.StringUtils;
import com.alibaba.csp.sentinel.datasource.Converter;
import com.alibaba.csp.sentinel.datasource.nacos.NacosDataSource;
import org.springframework.beans.factory.FactoryBean;
import com.alibaba.nacos.api.PropertyKeyConst;
/**
* A {@link FactoryBean} for creating {@link NacosDataSource} instance.
@@ -13,55 +33,104 @@ import org.springframework.beans.factory.FactoryBean;
*/
public class NacosDataSourceFactoryBean implements FactoryBean<NacosDataSource> {
private String serverAddr;
private String groupId;
private String dataId;
private Converter converter;
private String serverAddr;
private String groupId;
private String dataId;
private Converter converter;
@Override
public NacosDataSource getObject() throws Exception {
return new NacosDataSource(serverAddr, groupId, dataId, converter);
}
private String endpoint;
private String namespace;
private String accessKey;
private String secretKey;
@Override
public Class<?> getObjectType() {
return NacosDataSource.class;
}
@Override
public NacosDataSource getObject() throws Exception {
Properties properties = new Properties();
if (!StringUtils.isEmpty(this.serverAddr)) {
properties.setProperty(PropertyKeyConst.SERVER_ADDR, this.serverAddr);
}
else {
properties.setProperty(PropertyKeyConst.ACCESS_KEY, this.accessKey);
properties.setProperty(PropertyKeyConst.SECRET_KEY, this.secretKey);
properties.setProperty(PropertyKeyConst.ENDPOINT, this.endpoint);
}
if (!StringUtils.isEmpty(this.namespace)) {
properties.setProperty(PropertyKeyConst.NAMESPACE, this.namespace);
}
return new NacosDataSource(properties, groupId, dataId, converter);
}
@Override
public boolean isSingleton() {
return true;
}
@Override
public boolean isSingleton() {
return true;
}
public String getServerAddr() {
return serverAddr;
}
@Override
public Class<?> getObjectType() {
return NacosDataSource.class;
}
public void setServerAddr(String serverAddr) {
this.serverAddr = serverAddr;
}
public String getServerAddr() {
return serverAddr;
}
public String getGroupId() {
return groupId;
}
public void setServerAddr(String serverAddr) {
this.serverAddr = serverAddr;
}
public void setGroupId(String groupId) {
this.groupId = groupId;
}
public String getGroupId() {
return groupId;
}
public String getDataId() {
return dataId;
}
public void setGroupId(String groupId) {
this.groupId = groupId;
}
public void setDataId(String dataId) {
this.dataId = dataId;
}
public String getDataId() {
return dataId;
}
public Converter getConverter() {
return converter;
}
public void setDataId(String dataId) {
this.dataId = dataId;
}
public void setConverter(Converter converter) {
this.converter = converter;
}
public Converter getConverter() {
return converter;
}
public void setConverter(Converter converter) {
this.converter = converter;
}
public String getEndpoint() {
return endpoint;
}
public void setEndpoint(String endpoint) {
this.endpoint = endpoint;
}
public String getNamespace() {
return namespace;
}
public void setNamespace(String namespace) {
this.namespace = namespace;
}
public String getAccessKey() {
return accessKey;
}
public void setAccessKey(String accessKey) {
this.accessKey = accessKey;
}
public String getSecretKey() {
return secretKey;
}
public void setSecretKey(String secretKey) {
this.secretKey = secretKey;
}
}

View File

@@ -1,106 +0,0 @@
package org.springframework.cloud.alibaba.sentinel.datasource.factorybean;
import java.util.Properties;
import org.springframework.beans.factory.FactoryBean;
import org.springframework.cloud.alibaba.sentinel.datasource.NacosDataSourceWithAuthorization;
import com.alibaba.csp.sentinel.datasource.Converter;
import com.alibaba.csp.sentinel.datasource.nacos.NacosDataSource;
import com.alibaba.nacos.api.PropertyKeyConst;
/**
* A {@link FactoryBean} for creating {@link NacosDataSource} instance.
*
* @author <a href="mailto:fangjian0423@gmail.com">Jim</a>
* @see NacosDataSource
*/
public class NacosDataSourceWithAuthorizationFactoryBean
implements FactoryBean<NacosDataSourceWithAuthorization> {
private String endpoint;
private String namespace;
private String accessKey;
private String secretKey;
private String groupId;
private String dataId;
private Converter converter;
@Override
public NacosDataSourceWithAuthorization getObject() throws Exception {
Properties properties = new Properties();
properties.put(PropertyKeyConst.ACCESS_KEY, accessKey);
properties.put(PropertyKeyConst.SECRET_KEY, secretKey);
properties.put(PropertyKeyConst.NAMESPACE, namespace);
properties.put(PropertyKeyConst.ENDPOINT, endpoint);
return new NacosDataSourceWithAuthorization(properties, groupId, dataId,
converter);
}
@Override
public Class<?> getObjectType() {
return NacosDataSourceWithAuthorization.class;
}
@Override
public boolean isSingleton() {
return true;
}
public String getEndpoint() {
return endpoint;
}
public void setEndpoint(String endpoint) {
this.endpoint = endpoint;
}
public String getNamespace() {
return namespace;
}
public void setNamespace(String namespace) {
this.namespace = namespace;
}
public String getAccessKey() {
return accessKey;
}
public void setAccessKey(String accessKey) {
this.accessKey = accessKey;
}
public String getSecretKey() {
return secretKey;
}
public void setSecretKey(String secretKey) {
this.secretKey = secretKey;
}
public String getGroupId() {
return groupId;
}
public void setGroupId(String groupId) {
this.groupId = groupId;
}
public String getDataId() {
return dataId;
}
public void setDataId(String dataId) {
this.dataId = dataId;
}
public Converter getConverter() {
return converter;
}
public void setConverter(Converter converter) {
this.converter = converter;
}
}