Merge branch '2021.0' into feature/nacos-namespace

pull/1122/head
wenxuan70 2 years ago committed by GitHub
commit a553cc0ea7
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23

@ -28,3 +28,4 @@ fixes #
- [ ] Will pull request to branch of 2020.0. - [ ] Will pull request to branch of 2020.0.
- [ ] Will pull request to branch of 2022.0. - [ ] Will pull request to branch of 2022.0.
- [ ] Will pull request to branch of hoxton.

@ -16,7 +16,7 @@ header:
CONDITIONS OF ANY KIND, either express or implied. See the License for the CONDITIONS OF ANY KIND, either express or implied. See the License for the
specific language governing permissions and limitations under the License. specific language governing permissions and limitations under the License.
paths: paths:
- "**/java/**" - "**/tencent/**"
language: language:
Java: Java:
extensions: extensions:

@ -6,3 +6,11 @@
- [fix: dynamic routing using cookies.](https://github.com/Tencent/spring-cloud-tencent/pull/1097) - [fix: dynamic routing using cookies.](https://github.com/Tencent/spring-cloud-tencent/pull/1097)
- [Refactoring:remove invalid @AutoConfigureAfter and @AutoConfigureBefore from discovery client automatic configuration.](https://github.com/Tencent/spring-cloud-tencent/pull/1115) - [Refactoring:remove invalid @AutoConfigureAfter and @AutoConfigureBefore from discovery client automatic configuration.](https://github.com/Tencent/spring-cloud-tencent/pull/1115)
- [feat: support nacos namespace mapping](https://github.com/Tencent/spring-cloud-tencent/pull/1122) - [feat: support nacos namespace mapping](https://github.com/Tencent/spring-cloud-tencent/pull/1122)
- [feat: support log path configuration parameters.](https://github.com/Tencent/spring-cloud-tencent/pull/1128)
- [refactor:optimize the order and condition matching of service registration automatic configuration.](https://github.com/Tencent/spring-cloud-tencent/pull/1129)
- [feat: add circuit breaker actuator.](https://github.com/Tencent/spring-cloud-tencent/pull/1136)
- [feat: add metadata transfer for http header via spring.cloud.tencent.metadata.headers.](https://github.com/Tencent/spring-cloud-tencent/pull/1137)
- [feat:support service contract reporting.](https://github.com/Tencent/spring-cloud-tencent/pull/1139)
- [feat:add swagger exposure filters.](https://github.com/Tencent/spring-cloud-tencent/pull/1146)
- [feat:add swagger report switch.](https://github.com/Tencent/spring-cloud-tencent/pull/1148)
- [fix:fix retry loadbalancer not working bug.](https://github.com/Tencent/spring-cloud-tencent/pull/1154)

@ -78,7 +78,7 @@ Spring Cloud Tencent 所有组件都已上传到 Maven 中央仓库,只需要
<groupId>com.tencent.cloud</groupId> <groupId>com.tencent.cloud</groupId>
<artifactId>spring-cloud-tencent-dependencies</artifactId> <artifactId>spring-cloud-tencent-dependencies</artifactId>
<!--version number--> <!--version number-->
<version>1.12.0-2021.0.8</version> <version>1.12.1-2021.0.8</version>
<type>pom</type> <type>pom</type>
<scope>import</scope> <scope>import</scope>
</dependency> </dependency>

@ -80,7 +80,7 @@ For example:
<groupId>com.tencent.cloud</groupId> <groupId>com.tencent.cloud</groupId>
<artifactId>spring-cloud-tencent-dependencies</artifactId> <artifactId>spring-cloud-tencent-dependencies</artifactId>
<!--version number--> <!--version number-->
<version>1.12.0-2021.0.8</version> <version>1.12.1-2021.0.8</version>
<type>pom</type> <type>pom</type>
<scope>import</scope> <scope>import</scope>
</dependency> </dependency>

@ -47,6 +47,7 @@
<module>spring-cloud-starter-tencent-polaris-ratelimit</module> <module>spring-cloud-starter-tencent-polaris-ratelimit</module>
<module>spring-cloud-starter-tencent-polaris-circuitbreaker</module> <module>spring-cloud-starter-tencent-polaris-circuitbreaker</module>
<module>spring-cloud-starter-tencent-polaris-router</module> <module>spring-cloud-starter-tencent-polaris-router</module>
<module>spring-cloud-starter-tencent-polaris-contract</module>
<module>spring-cloud-tencent-plugin-starters</module> <module>spring-cloud-tencent-plugin-starters</module>
<module>spring-cloud-tencent-dependencies</module> <module>spring-cloud-tencent-dependencies</module>
<module>spring-cloud-starter-tencent-all</module> <module>spring-cloud-starter-tencent-all</module>
@ -91,7 +92,7 @@
<revision>1.13.0-2021.0.8-SNAPSHOT</revision> <revision>1.13.0-2021.0.8-SNAPSHOT</revision>
<!-- Spring Framework --> <!-- Spring Framework -->
<spring.framework.version>5.3.29</spring.framework.version> <spring.framework.version>5.3.25</spring.framework.version>
<!-- Spring Boot --> <!-- Spring Boot -->
<spring.boot.version>2.6.15</spring.boot.version> <spring.boot.version>2.6.15</spring.boot.version>

@ -45,6 +45,11 @@
<artifactId>spring-cloud-starter-tencent-metadata-transfer</artifactId> <artifactId>spring-cloud-starter-tencent-metadata-transfer</artifactId>
</dependency> </dependency>
<dependency>
<groupId>com.tencent.cloud</groupId>
<artifactId>spring-cloud-starter-tencent-polaris-contract</artifactId>
</dependency>
<!-- Spring Cloud --> <!-- Spring Cloud -->
<dependency> <dependency>
<groupId>org.springframework.cloud</groupId> <groupId>org.springframework.cloud</groupId>
@ -88,12 +93,19 @@
<configuration> <configuration>
<createSourcesJar>true</createSourcesJar> <createSourcesJar>true</createSourcesJar>
<transformers> <transformers>
<transformer implementation="org.apache.maven.plugins.shade.resource.ServicesResourceTransformer"/> <transformer
<transformer implementation="org.apache.maven.plugins.shade.resource.AppendingTransformer"> implementation="org.apache.maven.plugins.shade.resource.ServicesResourceTransformer"/>
<resource>META-INF/spring/org.springframework.boot.actuate.autoconfigure.web.ManagementContextConfiguration.imports</resource> <transformer
implementation="org.apache.maven.plugins.shade.resource.AppendingTransformer">
<resource>
META-INF/spring/org.springframework.boot.actuate.autoconfigure.web.ManagementContextConfiguration.imports
</resource>
</transformer> </transformer>
<transformer implementation="org.apache.maven.plugins.shade.resource.AppendingTransformer"> <transformer
<resource>META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports</resource> implementation="org.apache.maven.plugins.shade.resource.AppendingTransformer">
<resource>
META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports
</resource>
</transformer> </transformer>
</transformers> </transformers>
</configuration> </configuration>

@ -96,6 +96,18 @@
</dependency> </dependency>
<!-- Polaris dependencies end --> <!-- Polaris dependencies end -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-actuator</artifactId>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-actuator-autoconfigure</artifactId>
<optional>true</optional>
</dependency>
<dependency> <dependency>
<groupId>org.springframework.boot</groupId> <groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId> <artifactId>spring-boot-starter-test</artifactId>

@ -0,0 +1,86 @@
/*
* Tencent is pleased to support the open source community by making Spring Cloud Tencent available.
*
* Copyright (C) 2019 THL A29 Limited, a Tencent company. All rights reserved.
*
* Licensed under the BSD 3-Clause License (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://opensource.org/licenses/BSD-3-Clause
*
* 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.tencent.cloud.polaris.circuitbreaker.endpoint;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import com.google.protobuf.InvalidProtocolBufferException;
import com.google.protobuf.util.JsonFormat;
import com.tencent.cloud.common.metadata.MetadataContext;
import com.tencent.cloud.common.util.JacksonUtils;
import com.tencent.cloud.polaris.context.ServiceRuleManager;
import com.tencent.polaris.specification.api.v1.fault.tolerance.CircuitBreakerProto;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.boot.actuate.endpoint.annotation.Endpoint;
import org.springframework.boot.actuate.endpoint.annotation.ReadOperation;
/**
* Endpoint of polaris circuit breaker, include circuit breaker rules.
*
* @author wenxuan70
*/
@Endpoint(id = "polaris-circuit-breaker")
public class PolarisCircuitBreakerEndpoint {
private static final Logger LOG = LoggerFactory.getLogger(PolarisCircuitBreakerEndpoint.class);
private final ServiceRuleManager serviceRuleManager;
public PolarisCircuitBreakerEndpoint(ServiceRuleManager serviceRuleManager) {
this.serviceRuleManager = serviceRuleManager;
}
@ReadOperation
public Map<String, Object> circuitBreaker() {
CircuitBreakerProto.CircuitBreaker circuitBreaker = serviceRuleManager.getServiceCircuitBreakerRule(
MetadataContext.LOCAL_NAMESPACE,
MetadataContext.LOCAL_SERVICE
);
Map<String, Object> polarisCircuitBreakerInfo = new HashMap<>();
polarisCircuitBreakerInfo.put("namespace", MetadataContext.LOCAL_NAMESPACE);
polarisCircuitBreakerInfo.put("service", MetadataContext.LOCAL_SERVICE);
polarisCircuitBreakerInfo.put("circuitBreakerRules", parseCircuitBreakerRule(circuitBreaker));
return polarisCircuitBreakerInfo;
}
private List<Object> parseCircuitBreakerRule(CircuitBreakerProto.CircuitBreaker circuitBreaker) {
List<Object> circuitBreakerRuleList = new ArrayList<>();
for (CircuitBreakerProto.CircuitBreakerRule circuitBreakerRule : circuitBreaker.getRulesList()) {
String ruleJson;
try {
ruleJson = JsonFormat.printer().print(circuitBreakerRule);
}
catch (InvalidProtocolBufferException e) {
LOG.error("rule to Json failed. check rule {}.", circuitBreakerRule, e);
throw new RuntimeException("Json failed.", e);
}
circuitBreakerRuleList.add(JacksonUtils.deserialize2Map(ruleJson));
}
return circuitBreakerRuleList;
}
}

@ -0,0 +1,49 @@
/*
* Tencent is pleased to support the open source community by making Spring Cloud Tencent available.
*
* Copyright (C) 2019 THL A29 Limited, a Tencent company. All rights reserved.
*
* Licensed under the BSD 3-Clause License (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://opensource.org/licenses/BSD-3-Clause
*
* 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.tencent.cloud.polaris.circuitbreaker.endpoint;
import com.tencent.cloud.polaris.circuitbreaker.config.ConditionalOnPolarisCircuitBreakerEnabled;
import com.tencent.cloud.polaris.context.ServiceRuleManager;
import org.springframework.boot.actuate.autoconfigure.endpoint.condition.ConditionalOnAvailableEndpoint;
import org.springframework.boot.actuate.endpoint.annotation.Endpoint;
import org.springframework.boot.autoconfigure.condition.ConditionalOnBean;
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
/**
* The AutoConfiguration for Polaris CircuitBreaker's Endpoint.
*
* @author wenxuan70
*/
@Configuration(proxyBeanMethods = false)
@ConditionalOnClass(Endpoint.class)
@ConditionalOnPolarisCircuitBreakerEnabled
public class PolarisCircuitBreakerEndpointAutoConfiguration {
@Bean
@ConditionalOnBean(ServiceRuleManager.class)
@ConditionalOnMissingBean
@ConditionalOnAvailableEndpoint
public PolarisCircuitBreakerEndpoint polarisCircuitBreakerEndpoint(ServiceRuleManager serviceRuleManager) {
return new PolarisCircuitBreakerEndpoint(serviceRuleManager);
}
}

@ -2,6 +2,7 @@ org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
com.tencent.cloud.polaris.circuitbreaker.config.PolarisCircuitBreakerAutoConfiguration,\ com.tencent.cloud.polaris.circuitbreaker.config.PolarisCircuitBreakerAutoConfiguration,\
com.tencent.cloud.polaris.circuitbreaker.config.ReactivePolarisCircuitBreakerAutoConfiguration,\ com.tencent.cloud.polaris.circuitbreaker.config.ReactivePolarisCircuitBreakerAutoConfiguration,\
com.tencent.cloud.polaris.circuitbreaker.config.PolarisCircuitBreakerFeignClientAutoConfiguration,\ com.tencent.cloud.polaris.circuitbreaker.config.PolarisCircuitBreakerFeignClientAutoConfiguration,\
com.tencent.cloud.polaris.circuitbreaker.config.GatewayPolarisCircuitBreakerAutoConfiguration com.tencent.cloud.polaris.circuitbreaker.config.GatewayPolarisCircuitBreakerAutoConfiguration,\
com.tencent.cloud.polaris.circuitbreaker.endpoint.PolarisCircuitBreakerEndpointAutoConfiguration
org.springframework.cloud.bootstrap.BootstrapConfiguration=\ org.springframework.cloud.bootstrap.BootstrapConfiguration=\
com.tencent.cloud.polaris.circuitbreaker.config.PolarisCircuitBreakerBootstrapConfiguration com.tencent.cloud.polaris.circuitbreaker.config.PolarisCircuitBreakerBootstrapConfiguration

@ -0,0 +1,84 @@
/*
* Tencent is pleased to support the open source community by making Spring Cloud Tencent available.
*
* Copyright (C) 2019 THL A29 Limited, a Tencent company. All rights reserved.
*
* Licensed under the BSD 3-Clause License (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://opensource.org/licenses/BSD-3-Clause
*
* 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.tencent.cloud.polaris.circuitbreaker.endpoint;
import java.util.Map;
import com.google.protobuf.StringValue;
import com.tencent.cloud.common.util.ApplicationContextAwareUtils;
import com.tencent.cloud.polaris.context.ServiceRuleManager;
import com.tencent.polaris.specification.api.v1.fault.tolerance.CircuitBreakerProto;
import com.tencent.polaris.specification.api.v1.model.ModelProto;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;
import org.mockito.junit.jupiter.MockitoExtension;
import org.springframework.boot.test.context.runner.ApplicationContextRunner;
import static com.tencent.polaris.test.common.Consts.NAMESPACE_TEST;
import static com.tencent.polaris.test.common.Consts.SERVICE_PROVIDER;
import static org.assertj.core.api.Assertions.assertThat;
import static org.mockito.ArgumentMatchers.anyString;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.when;
/**
* Test for {@link PolarisCircuitBreakerEndpoint}.
*
* @author wenxuan70
*/
@ExtendWith(MockitoExtension.class)
public class PolarisCircuitBreakerEndpointTest {
private final ApplicationContextRunner contextRunner = new ApplicationContextRunner()
.withBean(ApplicationContextAwareUtils.class)
.withPropertyValues("spring.cloud.polaris.namespace=" + NAMESPACE_TEST)
.withPropertyValues("spring.cloud.polaris.service=" + SERVICE_PROVIDER);
private ServiceRuleManager serviceRuleManager;
@BeforeEach
void setUp() {
serviceRuleManager = mock(ServiceRuleManager.class);
when(serviceRuleManager.getServiceCircuitBreakerRule(anyString(), anyString())).thenAnswer(invocation -> {
CircuitBreakerProto.CircuitBreakerRule.Builder ruleBuilder = CircuitBreakerProto.CircuitBreakerRule.newBuilder();
ruleBuilder.setName("test_for_circuit_breaker");
ruleBuilder.setEnable(true);
ruleBuilder.setLevel(CircuitBreakerProto.Level.METHOD);
CircuitBreakerProto.RuleMatcher.Builder rmBuilder = CircuitBreakerProto.RuleMatcher.newBuilder();
rmBuilder.setDestination(CircuitBreakerProto.RuleMatcher.DestinationService.newBuilder().setNamespace("default").setService("svc2").setMethod(
ModelProto.MatchString.newBuilder().setValue(StringValue.newBuilder().setValue("*").build()).build()).build());
rmBuilder.setSource(CircuitBreakerProto.RuleMatcher.SourceService.newBuilder().setNamespace("*").setService("*").build());
ruleBuilder.setRuleMatcher(rmBuilder.build());
return CircuitBreakerProto.CircuitBreaker.newBuilder().addRules(ruleBuilder.build()).build();
});
}
@Test
public void testPolarisCircuitBreaker() {
contextRunner.run(context -> {
PolarisCircuitBreakerEndpoint endpoint = new PolarisCircuitBreakerEndpoint(serviceRuleManager);
Map<String, Object> circuitBreakerInfo = endpoint.circuitBreaker();
assertThat(circuitBreakerInfo).isNotNull();
assertThat(circuitBreakerInfo.get("namespace")).isNotNull();
assertThat(circuitBreakerInfo.get("service")).isNotNull();
assertThat(circuitBreakerInfo.get("circuitBreakerRules")).asList().isNotEmpty();
});
}
}

@ -27,14 +27,12 @@ import com.tencent.cloud.polaris.config.adapter.PolarisRefreshEntireContextRefre
import com.tencent.cloud.polaris.config.annotation.PolarisConfigAnnotationProcessor; import com.tencent.cloud.polaris.config.annotation.PolarisConfigAnnotationProcessor;
import com.tencent.cloud.polaris.config.condition.ConditionalOnReflectRefreshType; import com.tencent.cloud.polaris.config.condition.ConditionalOnReflectRefreshType;
import com.tencent.cloud.polaris.config.config.PolarisConfigProperties; import com.tencent.cloud.polaris.config.config.PolarisConfigProperties;
import com.tencent.cloud.polaris.config.listener.PolarisConfigApplicationEventListener;
import com.tencent.cloud.polaris.config.listener.PolarisConfigChangeEventListener; import com.tencent.cloud.polaris.config.listener.PolarisConfigChangeEventListener;
import com.tencent.cloud.polaris.config.listener.PolarisConfigRefreshOptimizationListener; import com.tencent.cloud.polaris.config.listener.PolarisConfigRefreshOptimizationListener;
import com.tencent.cloud.polaris.config.logger.PolarisConfigLoggerApplicationListener; import com.tencent.cloud.polaris.config.logger.PolarisConfigLoggerApplicationListener;
import com.tencent.cloud.polaris.config.spring.annotation.SpringValueProcessor; import com.tencent.cloud.polaris.config.spring.annotation.SpringValueProcessor;
import com.tencent.cloud.polaris.config.spring.property.PlaceholderHelper; import com.tencent.cloud.polaris.config.spring.property.PlaceholderHelper;
import com.tencent.cloud.polaris.config.spring.property.SpringValueRegistry; import com.tencent.cloud.polaris.config.spring.property.SpringValueRegistry;
import com.tencent.cloud.polaris.context.PolarisSDKContextManager;
import org.springframework.boot.autoconfigure.AutoConfigureBefore; import org.springframework.boot.autoconfigure.AutoConfigureBefore;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean; import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
@ -122,10 +120,5 @@ public class PolarisConfigAutoConfiguration {
public PolarisConfigRefreshOptimizationListener polarisConfigRefreshOptimizationListener() { public PolarisConfigRefreshOptimizationListener polarisConfigRefreshOptimizationListener() {
return new PolarisConfigRefreshOptimizationListener(); return new PolarisConfigRefreshOptimizationListener();
} }
@Bean
public PolarisConfigApplicationEventListener polarisContextApplicationEventListener(PolarisSDKContextManager polarisSDKContextManager) {
return new PolarisConfigApplicationEventListener(polarisSDKContextManager);
}
} }
} }

@ -101,7 +101,7 @@ public class PolarisConfigFileLocator implements PropertySourceLocator {
private void initCustomPolarisConfigExtensionFiles(CompositePropertySource compositePropertySource) { private void initCustomPolarisConfigExtensionFiles(CompositePropertySource compositePropertySource) {
if (polarisConfigCustomExtensionLayer == null) { if (polarisConfigCustomExtensionLayer == null) {
LOGGER.debug("[SCT Config] PolarisAdaptorTsfConfigExtensionLayer is not init, ignore the following execution steps"); LOGGER.debug("[SCT Config] PolarisConfigCustomExtensionLayer is not init, ignore the following execution steps");
return; return;
} }
polarisConfigCustomExtensionLayer.initConfigFiles(environment, compositePropertySource, polarisPropertySourceManager, configFileService); polarisConfigCustomExtensionLayer.initConfigFiles(environment, compositePropertySource, polarisPropertySourceManager, configFileService);
@ -109,7 +109,7 @@ public class PolarisConfigFileLocator implements PropertySourceLocator {
private void afterLocatePolarisConfigExtension(CompositePropertySource compositePropertySource) { private void afterLocatePolarisConfigExtension(CompositePropertySource compositePropertySource) {
if (polarisConfigCustomExtensionLayer == null) { if (polarisConfigCustomExtensionLayer == null) {
LOGGER.debug("[SCT Config] PolarisAdaptorTsfConfigExtensionLayer is not init, ignore the following execution steps"); LOGGER.debug("[SCT Config] PolarisConfigCustomExtensionLayer is not init, ignore the following execution steps");
return; return;
} }
polarisConfigCustomExtensionLayer.executeAfterLocateConfigReturning(compositePropertySource); polarisConfigCustomExtensionLayer.executeAfterLocateConfigReturning(compositePropertySource);

@ -89,7 +89,7 @@ public abstract class PolarisConfigPropertyAutoRefresher implements ApplicationL
private void customInitRegisterPolarisConfig(PolarisConfigPropertyAutoRefresher polarisConfigPropertyAutoRefresher) { private void customInitRegisterPolarisConfig(PolarisConfigPropertyAutoRefresher polarisConfigPropertyAutoRefresher) {
if (polarisConfigCustomExtensionLayer == null) { if (polarisConfigCustomExtensionLayer == null) {
LOGGER.debug("[SCT Config] PolarisAdaptorTsfConfigExtensionLayer is not init, ignore the following execution steps"); LOGGER.debug("[SCT Config] PolarisConfigCustomExtensionLayer is not init, ignore the following execution steps");
return; return;
} }
polarisConfigCustomExtensionLayer.initRegisterConfig(polarisConfigPropertyAutoRefresher); polarisConfigCustomExtensionLayer.initRegisterConfig(polarisConfigPropertyAutoRefresher);
@ -139,7 +139,7 @@ public abstract class PolarisConfigPropertyAutoRefresher implements ApplicationL
private void customRegisterPolarisConfigPublishChangeListener(PolarisPropertySource polarisPropertySource) { private void customRegisterPolarisConfigPublishChangeListener(PolarisPropertySource polarisPropertySource) {
if (polarisConfigCustomExtensionLayer == null) { if (polarisConfigCustomExtensionLayer == null) {
LOGGER.debug("[SCT Config] PolarisAdaptorTsfConfigExtensionLayer is not init, ignore the following execution steps"); LOGGER.debug("[SCT Config] PolarisConfigCustomExtensionLayer is not init, ignore the following execution steps");
return; return;
} }
polarisConfigCustomExtensionLayer.executeRegisterPublishChangeListener(polarisPropertySource); polarisConfigCustomExtensionLayer.executeRegisterPublishChangeListener(polarisPropertySource);

@ -0,0 +1,69 @@
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns="http://maven.apache.org/POM/4.0.0"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<parent>
<artifactId>spring-cloud-tencent</artifactId>
<groupId>com.tencent.cloud</groupId>
<version>${revision}</version>
<relativePath>../pom.xml</relativePath>
</parent>
<modelVersion>4.0.0</modelVersion>
<artifactId>spring-cloud-starter-tencent-polaris-contract</artifactId>
<name>Spring Cloud Starter Tencent Polaris Contract</name>
<dependencies>
<!-- Spring Cloud Tencent dependencies start -->
<dependency>
<groupId>com.tencent.cloud</groupId>
<artifactId>spring-cloud-starter-tencent-polaris-discovery</artifactId>
</dependency>
<!-- Spring Cloud Tencent dependencies end -->
<!-- Spring cloud dependencies start -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-webflux</artifactId>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
<optional>true</optional>
</dependency>
<!-- Spring cloud dependencies start -->
<dependency>
<groupId>io.springfox</groupId>
<artifactId>springfox-boot-starter</artifactId>
<exclusions>
<exclusion>
<artifactId>swagger-models</artifactId>
<groupId>io.swagger</groupId>
</exclusion>
<exclusion>
<artifactId>swagger-annotations</artifactId>
<groupId>io.swagger</groupId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>io.swagger</groupId>
<artifactId>swagger-models</artifactId>
</dependency>
<dependency>
<groupId>io.swagger</groupId>
<artifactId>swagger-annotations</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
</dependencies>
</project>

@ -0,0 +1,154 @@
/*
* Tencent is pleased to support the open source community by making Spring Cloud Tencent available.
*
* Copyright (C) 2019 THL A29 Limited, a Tencent company. All rights reserved.
*
* Licensed under the BSD 3-Clause License (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://opensource.org/licenses/BSD-3-Clause
*
* 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.tencent.cloud.polaris.contract;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import com.tencent.cloud.common.util.JacksonUtils;
import com.tencent.cloud.polaris.PolarisDiscoveryProperties;
import com.tencent.cloud.polaris.contract.config.PolarisContractProperties;
import com.tencent.polaris.api.core.ProviderAPI;
import com.tencent.polaris.api.plugin.server.InterfaceDescriptor;
import com.tencent.polaris.api.plugin.server.ReportServiceContractRequest;
import com.tencent.polaris.api.plugin.server.ReportServiceContractResponse;
import io.swagger.models.HttpMethod;
import io.swagger.models.Operation;
import io.swagger.models.Path;
import io.swagger.models.Swagger;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import springfox.documentation.service.Documentation;
import springfox.documentation.spring.web.DocumentationCache;
import springfox.documentation.swagger2.mappers.ServiceModelToSwagger2Mapper;
import org.springframework.boot.context.event.ApplicationReadyEvent;
import org.springframework.context.ApplicationListener;
import org.springframework.lang.NonNull;
import org.springframework.util.CollectionUtils;
/**
* Polaris contract reporter.
*
* @author Haotian Zhang
*/
public class PolarisContractReporter implements ApplicationListener<ApplicationReadyEvent> {
private final Logger LOG = LoggerFactory.getLogger(PolarisContractReporter.class);
private final ServiceModelToSwagger2Mapper swagger2Mapper;
private final DocumentationCache documentationCache;
private final PolarisContractProperties polarisContractProperties;
private final ProviderAPI providerAPI;
private final PolarisDiscoveryProperties polarisDiscoveryProperties;
public PolarisContractReporter(DocumentationCache documentationCache, ServiceModelToSwagger2Mapper swagger2Mapper,
PolarisContractProperties polarisContractProperties, ProviderAPI providerAPI, PolarisDiscoveryProperties polarisDiscoveryProperties) {
this.swagger2Mapper = swagger2Mapper;
this.documentationCache = documentationCache;
this.polarisContractProperties = polarisContractProperties;
this.providerAPI = providerAPI;
this.polarisDiscoveryProperties = polarisDiscoveryProperties;
}
@Override
public void onApplicationEvent(@NonNull ApplicationReadyEvent applicationReadyEvent) {
if (polarisContractProperties.isReportEnabled()) {
try {
Documentation documentation = documentationCache.documentationByGroup(polarisContractProperties.getGroup());
Swagger swagger = swagger2Mapper.mapDocumentation(documentation);
if (swagger != null) {
ReportServiceContractRequest request = new ReportServiceContractRequest();
request.setName(polarisDiscoveryProperties.getService());
request.setNamespace(polarisDiscoveryProperties.getNamespace());
request.setService(polarisDiscoveryProperties.getService());
request.setProtocol("http");
request.setVersion(polarisDiscoveryProperties.getVersion());
List<InterfaceDescriptor> interfaceDescriptorList = getInterfaceDescriptorFromSwagger(swagger);
request.setInterfaceDescriptors(interfaceDescriptorList);
ReportServiceContractResponse response = providerAPI.reportServiceContract(request);
LOG.info("Service contract [Namespace: {}. Name: {}. Service: {}. Protocol:{}. Version: {}. API counter: {}] is reported.",
request.getNamespace(), request.getName(), request.getService(), request.getProtocol(),
request.getVersion(), request.getInterfaceDescriptors().size());
if (LOG.isDebugEnabled()) {
String jsonValue = JacksonUtils.serialize2Json(swagger);
LOG.debug("OpenApi json data: {}", jsonValue);
}
}
else {
LOG.warn("Swagger or json is null, documentationCache keys:{}, group:{}", documentationCache.all()
.keySet(), polarisContractProperties.getGroup());
}
}
catch (Throwable t) {
LOG.error("Report contract failed.", t);
}
}
}
private List<InterfaceDescriptor> getInterfaceDescriptorFromSwagger(Swagger swagger) {
List<InterfaceDescriptor> interfaceDescriptorList = new ArrayList<>();
Map<String, Path> paths = swagger.getPaths();
for (Map.Entry<String, Path> p : paths.entrySet()) {
Path path = p.getValue();
Map<String, Operation> operationMap = getOperationMapFromPath(path);
if (CollectionUtils.isEmpty(operationMap)) {
continue;
}
for (Map.Entry<String, Operation> o : operationMap.entrySet()) {
InterfaceDescriptor interfaceDescriptor = new InterfaceDescriptor();
interfaceDescriptor.setPath(p.getKey());
interfaceDescriptor.setMethod(o.getKey());
interfaceDescriptor.setContent(JacksonUtils.serialize2Json(p.getValue()));
interfaceDescriptorList.add(interfaceDescriptor);
}
}
return interfaceDescriptorList;
}
private Map<String, Operation> getOperationMapFromPath(Path path) {
Map<String, Operation> operationMap = new HashMap<>();
if (path.getGet() != null) {
operationMap.put(HttpMethod.GET.name(), path.getGet());
}
if (path.getPut() != null) {
operationMap.put(HttpMethod.PUT.name(), path.getPut());
}
if (path.getPost() != null) {
operationMap.put(HttpMethod.POST.name(), path.getPost());
}
if (path.getHead() != null) {
operationMap.put(HttpMethod.HEAD.name(), path.getHead());
}
if (path.getDelete() != null) {
operationMap.put(HttpMethod.DELETE.name(), path.getDelete());
}
if (path.getPatch() != null) {
operationMap.put(HttpMethod.PATCH.name(), path.getPatch());
}
if (path.getOptions() != null) {
operationMap.put(HttpMethod.OPTIONS.name(), path.getOptions());
}
return operationMap;
}
}

@ -0,0 +1,35 @@
/*
* Tencent is pleased to support the open source community by making Spring Cloud Tencent available.
*
* Copyright (C) 2019 THL A29 Limited, a Tencent company. All rights reserved.
*
* Licensed under the BSD 3-Clause License (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://opensource.org/licenses/BSD-3-Clause
*
* 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.tencent.cloud.polaris.contract;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.context.event.ApplicationEnvironmentPreparedEvent;
import org.springframework.context.ApplicationListener;
public class PolarisSwaggerApplicationListener implements ApplicationListener<ApplicationEnvironmentPreparedEvent> {
@Override
public void onApplicationEvent(ApplicationEnvironmentPreparedEvent startingEvent) {
SpringApplication application = startingEvent.getSpringApplication();
Class<?> mainClass = application.getMainApplicationClass();
if (mainClass == null) {
return;
}
SwaggerContext.setAttribute(String.format("$%s", "MainClass"), mainClass);
}
}

@ -0,0 +1,36 @@
/*
* Tencent is pleased to support the open source community by making Spring Cloud Tencent available.
*
* Copyright (C) 2019 THL A29 Limited, a Tencent company. All rights reserved.
*
* Licensed under the BSD 3-Clause License (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://opensource.org/licenses/BSD-3-Clause
*
* 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.tencent.cloud.polaris.contract;
import java.util.concurrent.ConcurrentHashMap;
public final class SwaggerContext {
private static final ConcurrentHashMap<String, Object> attribute = new ConcurrentHashMap<>();
private SwaggerContext() {
}
public static void setAttribute(String key, Object value) {
attribute.put(key, value);
}
public static Object getAttribute(String key) {
return attribute.get(key);
}
}

@ -0,0 +1,54 @@
/*
* Tencent is pleased to support the open source community by making Spring Cloud Tencent available.
*
* Copyright (C) 2019 THL A29 Limited, a Tencent company. All rights reserved.
*
* Licensed under the BSD 3-Clause License (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://opensource.org/licenses/BSD-3-Clause
*
* 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.tencent.cloud.polaris.contract.config;
/**
* Interface for contract properties.
*
* @author Haotian Zhang
*/
public interface ContractProperties {
boolean isEnabled();
void setEnabled(boolean enabled);
String getBasePackage();
void setBasePackage(String basePackage);
String getExcludePath();
void setExcludePath(String excludePath);
String getGroup();
void setGroup(String group);
String getBasePath();
void setBasePath(String basePath);
boolean isExposure();
void setExposure(boolean exposure);
boolean isReportEnabled();
void setReportEnabled(boolean reportEnabled);
}

@ -0,0 +1,26 @@
/*
* Tencent is pleased to support the open source community by making Spring Cloud Tencent available.
*
* Copyright (C) 2019 THL A29 Limited, a Tencent company. All rights reserved.
*
* Licensed under the BSD 3-Clause License (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://opensource.org/licenses/BSD-3-Clause
*
* 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.tencent.cloud.polaris.contract.config;
/**
* Extend contract properties.
*
* @author Haotian Zhang
*/
public interface ExtendedContractProperties extends ContractProperties {
}

@ -0,0 +1,52 @@
/*
* Tencent is pleased to support the open source community by making Spring Cloud Tencent available.
*
* Copyright (C) 2019 THL A29 Limited, a Tencent company. All rights reserved.
*
* Licensed under the BSD 3-Clause License (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://opensource.org/licenses/BSD-3-Clause
*
* 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.tencent.cloud.polaris.contract.config;
import java.util.List;
import com.tencent.cloud.common.constant.OrderConstant;
import com.tencent.cloud.polaris.context.PolarisConfigModifier;
import com.tencent.polaris.factory.config.ConfigurationImpl;
import com.tencent.polaris.factory.config.provider.RegisterConfigImpl;
/**
* Modifier of service contract.
*
* @author Haotian Zhang
*/
public class PolarisContractModifier implements PolarisConfigModifier {
private final PolarisContractProperties polarisContractProperties;
public PolarisContractModifier(PolarisContractProperties polarisContractProperties) {
this.polarisContractProperties = polarisContractProperties;
}
@Override
public void modify(ConfigurationImpl configuration) {
List<RegisterConfigImpl> registerConfigs = configuration.getProvider().getRegisters();
for (RegisterConfigImpl registerConfig : registerConfigs) {
registerConfig.setReportServiceContractEnable(polarisContractProperties.isEnabled());
}
}
@Override
public int getOrder() {
return OrderConstant.Modifier.SERVICE_CONTRACT_ORDER;
}
}

@ -0,0 +1,151 @@
/*
* Tencent is pleased to support the open source community by making Spring Cloud Tencent available.
*
* Copyright (C) 2019 THL A29 Limited, a Tencent company. All rights reserved.
*
* Licensed under the BSD 3-Clause License (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://opensource.org/licenses/BSD-3-Clause
*
* 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.tencent.cloud.polaris.contract.config;
import java.util.Objects;
import javax.annotation.Nullable;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.context.properties.ConfigurationProperties;
/**
* Properties for Polaris contract.
*
* @author Haotian Zhang
*/
@ConfigurationProperties("spring.cloud.polaris.contract")
public class PolarisContractProperties implements ContractProperties {
private final ExtendedContractProperties extendContractProperties;
private boolean enabled = true;
/**
* Packages to be scanned. Split by ",".
*/
private String basePackage;
/**
* Paths to be excluded. Split by ",".
*/
private String excludePath;
/**
* Group to create swagger docket.
*/
private String group = "default";
/**
* Base paths to be scanned. Split by ",".
*/
private String basePath = "/**";
private boolean exposure = true;
@Value("${spring.cloud.polaris.contract.report.enabled:true}")
private boolean reportEnabled = true;
public PolarisContractProperties(@Nullable ExtendedContractProperties extendContractProperties) {
this.extendContractProperties = extendContractProperties;
}
@Override
public boolean isEnabled() {
if (Objects.nonNull(extendContractProperties)) {
return extendContractProperties.isEnabled();
}
return enabled;
}
@Override
public void setEnabled(boolean enabled) {
this.enabled = enabled;
}
@Override
public String getBasePackage() {
if (Objects.nonNull(extendContractProperties)) {
return extendContractProperties.getBasePackage();
}
return basePackage;
}
@Override
public void setBasePackage(String basePackage) {
this.basePackage = basePackage;
}
@Override
public String getExcludePath() {
if (Objects.nonNull(extendContractProperties)) {
return extendContractProperties.getExcludePath();
}
return excludePath;
}
@Override
public void setExcludePath(String excludePath) {
this.excludePath = excludePath;
}
@Override
public String getGroup() {
if (Objects.nonNull(extendContractProperties)) {
return extendContractProperties.getGroup();
}
return group;
}
@Override
public void setGroup(String group) {
this.group = group;
}
@Override
public String getBasePath() {
if (Objects.nonNull(extendContractProperties)) {
return extendContractProperties.getBasePath();
}
return basePath;
}
@Override
public void setBasePath(String basePath) {
this.basePath = basePath;
}
@Override
public boolean isExposure() {
if (Objects.nonNull(extendContractProperties)) {
return extendContractProperties.isExposure();
}
return exposure;
}
@Override
public void setExposure(boolean exposure) {
this.exposure = exposure;
}
@Override
public boolean isReportEnabled() {
return reportEnabled;
}
@Override
public void setReportEnabled(boolean reportEnabled) {
this.reportEnabled = reportEnabled;
}
}

@ -0,0 +1,48 @@
/*
* Tencent is pleased to support the open source community by making Spring Cloud Tencent available.
*
* Copyright (C) 2019 THL A29 Limited, a Tencent company. All rights reserved.
*
* Licensed under the BSD 3-Clause License (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://opensource.org/licenses/BSD-3-Clause
*
* 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.tencent.cloud.polaris.contract.config;
import javax.annotation.Nullable;
import com.tencent.cloud.polaris.context.ConditionalOnPolarisEnabled;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
/**
* Auto configuration for Polaris contract properties.
*
* @author Haotian Zhang
*/
@Configuration(proxyBeanMethods = false)
@ConditionalOnPolarisEnabled
public class PolarisContractPropertiesAutoConfiguration {
@Bean
@ConditionalOnMissingBean
public PolarisContractProperties polarisContractProperties(@Nullable ExtendedContractProperties extendedContractProperties) {
return new PolarisContractProperties(extendedContractProperties);
}
@Bean
@ConditionalOnMissingBean
public PolarisContractModifier polarisContractModifier(PolarisContractProperties polarisContractProperties) {
return new PolarisContractModifier(polarisContractProperties);
}
}

@ -0,0 +1,34 @@
/*
* Tencent is pleased to support the open source community by making Spring Cloud Tencent available.
*
* Copyright (C) 2019 THL A29 Limited, a Tencent company. All rights reserved.
*
* Licensed under the BSD 3-Clause License (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://opensource.org/licenses/BSD-3-Clause
*
* 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.tencent.cloud.polaris.contract.config;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Import;
/**
* Bootstrap configuration for Polaris contract properties.
*
* @author Haotian Zhang
*/
@Configuration(proxyBeanMethods = false)
@ConditionalOnProperty("spring.cloud.polaris.enabled")
@Import(PolarisContractPropertiesAutoConfiguration.class)
public class PolarisContractPropertiesBootstrapConfiguration {
}

@ -0,0 +1,199 @@
/*
* Tencent is pleased to support the open source community by making Spring Cloud Tencent available.
*
* Copyright (C) 2019 THL A29 Limited, a Tencent company. All rights reserved.
*
* Licensed under the BSD 3-Clause License (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://opensource.org/licenses/BSD-3-Clause
*
* 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.tencent.cloud.polaris.contract.config;
import java.lang.reflect.Field;
import java.time.LocalDate;
import java.util.Date;
import java.util.List;
import java.util.function.Predicate;
import java.util.stream.Collectors;
import com.tencent.cloud.common.util.ReflectionUtils;
import com.tencent.cloud.polaris.PolarisDiscoveryProperties;
import com.tencent.cloud.polaris.context.ConditionalOnPolarisEnabled;
import com.tencent.cloud.polaris.context.PolarisSDKContextManager;
import com.tencent.cloud.polaris.contract.PolarisContractReporter;
import com.tencent.cloud.polaris.contract.PolarisSwaggerApplicationListener;
import com.tencent.cloud.polaris.contract.filter.ApiDocServletFilter;
import com.tencent.cloud.polaris.contract.filter.ApiDocWebFluxFilter;
import com.tencent.cloud.polaris.contract.utils.PackageUtil;
import springfox.boot.starter.autoconfigure.OpenApiAutoConfiguration;
import springfox.documentation.builders.ApiInfoBuilder;
import springfox.documentation.service.Contact;
import springfox.documentation.spi.DocumentationType;
import springfox.documentation.spring.web.DocumentationCache;
import springfox.documentation.spring.web.plugins.Docket;
import springfox.documentation.spring.web.plugins.WebMvcRequestHandlerProvider;
import springfox.documentation.swagger2.mappers.ServiceModelToSwagger2Mapper;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.config.BeanPostProcessor;
import org.springframework.boot.autoconfigure.condition.ConditionalOnBean;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.boot.autoconfigure.condition.ConditionalOnWebApplication;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Import;
import org.springframework.web.servlet.mvc.method.RequestMappingInfoHandlerMapping;
/**
* Auto configuration for Polaris swagger.
*
* @author Haotian Zhang
*/
@Configuration(proxyBeanMethods = false)
@ConditionalOnPolarisEnabled
@ConditionalOnProperty(name = "spring.cloud.polaris.contract.enabled", havingValue = "true", matchIfMissing = true)
@Import(OpenApiAutoConfiguration.class)
public class PolarisSwaggerAutoConfiguration {
static {
// After springboot2.6.x, the default path matching strategy of spring MVC is changed from ANT_PATH_MATCHER
// mode to PATH_PATTERN_PARSER mode, causing an error. The solution is to switch to the original ANT_PATH_MATCHER mode.
System.setProperty("spring.mvc.pathmatch.matching-strategy", "ant-path-matcher");
}
@Bean
public Docket polarisDocket(PolarisContractProperties polarisContractProperties) {
List<Predicate<String>> excludePathList = PackageUtil.getExcludePathPredicates(polarisContractProperties.getExcludePath());
List<Predicate<String>> basePathList = PackageUtil.getBasePathPredicates(polarisContractProperties.getBasePath());
String basePackage = PackageUtil.scanPackage(polarisContractProperties.getBasePackage());
Predicate<String> basePathListOr = null;
for (Predicate<String> basePathPredicate : basePathList) {
if (basePathListOr == null) {
basePathListOr = basePathPredicate;
}
else {
basePathListOr = basePathListOr.or(basePathPredicate);
}
}
Predicate<String> excludePathListOr = null;
for (Predicate<String> excludePathPredicate : excludePathList) {
if (excludePathListOr == null) {
excludePathListOr = excludePathPredicate;
}
else {
excludePathListOr = excludePathListOr.or(excludePathPredicate);
}
}
Predicate<String> pathsPredicate = basePathListOr;
if (excludePathListOr != null) {
excludePathListOr = excludePathListOr.negate();
pathsPredicate = pathsPredicate.and(excludePathListOr);
}
return new Docket(DocumentationType.SWAGGER_2)
.select()
.apis(PackageUtil.basePackage(basePackage))
.paths(pathsPredicate)
.build()
.groupName(polarisContractProperties.getGroup())
.enable(polarisContractProperties.isEnabled())
.directModelSubstitute(LocalDate.class, Date.class)
.apiInfo(new ApiInfoBuilder()
.title("Polaris Swagger API")
.description("This is to show polaris api description.")
.license("BSD-3-Clause")
.licenseUrl("https://opensource.org/licenses/BSD-3-Clause")
.termsOfServiceUrl("")
.version("1.0.0")
.contact(new Contact("", "", ""))
.build());
}
@Bean
@ConditionalOnBean(Docket.class)
@ConditionalOnMissingBean
public PolarisContractReporter polarisContractReporter(DocumentationCache documentationCache,
ServiceModelToSwagger2Mapper swagger2Mapper, PolarisContractProperties polarisContractProperties,
PolarisSDKContextManager polarisSDKContextManager, PolarisDiscoveryProperties polarisDiscoveryProperties) {
return new PolarisContractReporter(documentationCache, swagger2Mapper, polarisContractProperties,
polarisSDKContextManager.getProviderAPI(), polarisDiscoveryProperties);
}
@Bean
@ConditionalOnMissingBean
public PolarisSwaggerApplicationListener polarisSwaggerApplicationListener() {
return new PolarisSwaggerApplicationListener();
}
/**
* Create when web application type is SERVLET.
*/
@Configuration(proxyBeanMethods = false)
@ConditionalOnWebApplication(type = ConditionalOnWebApplication.Type.SERVLET)
protected static class SwaggerServletConfig {
@Bean
public static BeanPostProcessor springfoxHandlerProviderBeanPostProcessor() {
return new BeanPostProcessor() {
@Override
public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
if (bean instanceof WebMvcRequestHandlerProvider) {
customizeSpringfoxHandlerMappings(getHandlerMappings(bean));
}
return bean;
}
private <T extends RequestMappingInfoHandlerMapping> void customizeSpringfoxHandlerMappings(List<T> mappings) {
List<T> copy = mappings.stream()
.filter(mapping -> mapping.getPatternParser() == null)
.collect(Collectors.toList());
mappings.clear();
mappings.addAll(copy);
}
@SuppressWarnings("unchecked")
private List<RequestMappingInfoHandlerMapping> getHandlerMappings(Object bean) {
try {
Field field = ReflectionUtils.findField(bean.getClass(), "handlerMappings");
field.setAccessible(true);
return (List<RequestMappingInfoHandlerMapping>) field.get(bean);
}
catch (IllegalArgumentException | IllegalAccessException e) {
throw new IllegalStateException(e);
}
}
};
}
@Bean
public ApiDocServletFilter apiDocServletFilter(PolarisContractProperties polarisContractProperties) {
return new ApiDocServletFilter(polarisContractProperties);
}
}
/**
* Create when web application type is REACTIVE.
*/
@Configuration(proxyBeanMethods = false)
@ConditionalOnWebApplication(type = ConditionalOnWebApplication.Type.REACTIVE)
protected static class SwaggerReactiveConfig {
@Bean
public ApiDocWebFluxFilter apiDocWebFluxFilter(PolarisContractProperties polarisContractProperties) {
return new ApiDocWebFluxFilter(polarisContractProperties);
}
}
}

@ -0,0 +1,73 @@
/*
* Tencent is pleased to support the open source community by making Spring Cloud Tencent available.
*
* Copyright (C) 2019 THL A29 Limited, a Tencent company. All rights reserved.
*
* Licensed under the BSD 3-Clause License (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://opensource.org/licenses/BSD-3-Clause
*
* 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.tencent.cloud.polaris.contract.filter;
import java.io.IOException;
import javax.servlet.FilterChain;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import com.tencent.cloud.polaris.contract.config.PolarisContractProperties;
import org.springframework.lang.NonNull;
import org.springframework.web.filter.OncePerRequestFilter;
import static com.tencent.cloud.polaris.contract.filter.FilterConstant.SWAGGER_RESOURCE_PREFIX;
import static com.tencent.cloud.polaris.contract.filter.FilterConstant.SWAGGER_UI_V2_URL;
import static com.tencent.cloud.polaris.contract.filter.FilterConstant.SWAGGER_UI_V3_URL;
import static com.tencent.cloud.polaris.contract.filter.FilterConstant.SWAGGER_V2_API_DOC_URL;
import static com.tencent.cloud.polaris.contract.filter.FilterConstant.SWAGGER_V3_API_DOC_URL;
import static com.tencent.cloud.polaris.contract.filter.FilterConstant.SWAGGER_WEBJARS_V2_PREFIX;
import static com.tencent.cloud.polaris.contract.filter.FilterConstant.SWAGGER_WEBJARS_V3_PREFIX;
/**
* Filter to disable api doc controller.
*
* @author Haotian Zhang
*/
public class ApiDocServletFilter extends OncePerRequestFilter {
private final PolarisContractProperties polarisContractProperties;
public ApiDocServletFilter(PolarisContractProperties polarisContractProperties) {
this.polarisContractProperties = polarisContractProperties;
}
@Override
public void doFilterInternal(@NonNull HttpServletRequest httpServletRequest,
@NonNull HttpServletResponse httpServletResponse, @NonNull FilterChain filterChain)
throws ServletException, IOException {
if (!polarisContractProperties.isExposure()) {
String path = httpServletRequest.getServletPath();
if (path.startsWith(SWAGGER_V2_API_DOC_URL) ||
path.startsWith(SWAGGER_V3_API_DOC_URL) ||
path.startsWith(SWAGGER_UI_V2_URL) ||
path.startsWith(SWAGGER_UI_V3_URL) ||
path.startsWith(SWAGGER_RESOURCE_PREFIX) ||
path.startsWith(SWAGGER_WEBJARS_V2_PREFIX) ||
path.startsWith(SWAGGER_WEBJARS_V3_PREFIX)) {
httpServletResponse.setStatus(HttpServletResponse.SC_FORBIDDEN);
return;
}
}
filterChain.doFilter(httpServletRequest, httpServletResponse);
}
}

@ -0,0 +1,71 @@
/*
* Tencent is pleased to support the open source community by making Spring Cloud Tencent available.
*
* Copyright (C) 2019 THL A29 Limited, a Tencent company. All rights reserved.
*
* Licensed under the BSD 3-Clause License (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://opensource.org/licenses/BSD-3-Clause
*
* 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.tencent.cloud.polaris.contract.filter;
import com.tencent.cloud.polaris.contract.config.PolarisContractProperties;
import reactor.core.publisher.Mono;
import org.springframework.core.io.buffer.DataBuffer;
import org.springframework.http.HttpStatus;
import org.springframework.http.server.reactive.ServerHttpResponse;
import org.springframework.web.server.ServerWebExchange;
import org.springframework.web.server.WebFilter;
import org.springframework.web.server.WebFilterChain;
import static com.tencent.cloud.polaris.contract.filter.FilterConstant.SWAGGER_RESOURCE_PREFIX;
import static com.tencent.cloud.polaris.contract.filter.FilterConstant.SWAGGER_UI_V2_URL;
import static com.tencent.cloud.polaris.contract.filter.FilterConstant.SWAGGER_UI_V3_URL;
import static com.tencent.cloud.polaris.contract.filter.FilterConstant.SWAGGER_V2_API_DOC_URL;
import static com.tencent.cloud.polaris.contract.filter.FilterConstant.SWAGGER_V3_API_DOC_URL;
import static com.tencent.cloud.polaris.contract.filter.FilterConstant.SWAGGER_WEBJARS_V2_PREFIX;
import static com.tencent.cloud.polaris.contract.filter.FilterConstant.SWAGGER_WEBJARS_V3_PREFIX;
/**
* Filter to disable api doc controller.
*
* @author Haotian Zhang
*/
public class ApiDocWebFluxFilter implements WebFilter {
private final PolarisContractProperties polarisContractProperties;
public ApiDocWebFluxFilter(PolarisContractProperties polarisContractProperties) {
this.polarisContractProperties = polarisContractProperties;
}
@Override
public Mono<Void> filter(ServerWebExchange serverWebExchange, WebFilterChain webFilterChain) {
if (!polarisContractProperties.isExposure()) {
String path = serverWebExchange.getRequest().getURI().getPath();
if (path.startsWith(SWAGGER_V2_API_DOC_URL) ||
path.startsWith(SWAGGER_V3_API_DOC_URL) ||
path.startsWith(SWAGGER_UI_V2_URL) ||
path.startsWith(SWAGGER_UI_V3_URL) ||
path.startsWith(SWAGGER_RESOURCE_PREFIX) ||
path.startsWith(SWAGGER_WEBJARS_V2_PREFIX) ||
path.startsWith(SWAGGER_WEBJARS_V3_PREFIX)) {
ServerHttpResponse response = serverWebExchange.getResponse();
response.setRawStatusCode(HttpStatus.FORBIDDEN.value());
DataBuffer dataBuffer = response.bufferFactory().allocateBuffer();
return response.writeWith(Mono.just(dataBuffer));
}
}
return webFilterChain.filter(serverWebExchange);
}
}

@ -0,0 +1,64 @@
/*
* Tencent is pleased to support the open source community by making Spring Cloud Tencent available.
*
* Copyright (C) 2019 THL A29 Limited, a Tencent company. All rights reserved.
*
* Licensed under the BSD 3-Clause License (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://opensource.org/licenses/BSD-3-Clause
*
* 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.tencent.cloud.polaris.contract.filter;
/**
* Constant for filter.
*
* @author Haotian Zhang
*/
public final class FilterConstant {
/**
* Swagger api doc V2 url.
*/
public static final String SWAGGER_V2_API_DOC_URL = "/v2/api-docs";
/**
* Swagger api doc V3 url.
*/
public static final String SWAGGER_V3_API_DOC_URL = "/v3/api-docs";
/**
* Swagger UI V2 url.
*/
public static final String SWAGGER_UI_V2_URL = "/swagger-ui.html";
/**
* Swagger UI V3 url.
*/
public static final String SWAGGER_UI_V3_URL = "/swagger-ui/index.html";
/**
* Swagger resource url prefix.
*/
public static final String SWAGGER_RESOURCE_PREFIX = "/swagger-resource/";
/**
* Swagger webjars V2 url prefix.
*/
public static final String SWAGGER_WEBJARS_V2_PREFIX = "/webjars/springfox-swagger-ui/";
/**
* Swagger webjars V3 url prefix.
*/
public static final String SWAGGER_WEBJARS_V3_PREFIX = "/webjars/swagger-ui/";
private FilterConstant() {
}
}

@ -0,0 +1,213 @@
/*
* Tencent is pleased to support the open source community by making Spring Cloud Tencent available.
*
* Copyright (C) 2019 THL A29 Limited, a Tencent company. All rights reserved.
*
* Licensed under the BSD 3-Clause License (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://opensource.org/licenses/BSD-3-Clause
*
* 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.tencent.cloud.polaris.contract.utils;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import java.util.function.Predicate;
import com.google.common.base.Function;
import com.google.common.base.Optional;
import com.tencent.cloud.polaris.contract.SwaggerContext;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import springfox.documentation.RequestHandler;
import springfox.documentation.builders.PathSelectors;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.util.StringUtils;
import static com.google.common.base.Optional.fromNullable;
/**
* Util for package processing.
*
* @author Haotian Zhang
*/
public final class PackageUtil {
private static final Logger LOG = LoggerFactory.getLogger(PackageUtil.class);
private static final String SPLITTER = ",";
private PackageUtil() {
}
public static Predicate<RequestHandler> basePackage(String basePackage) {
return input -> declaringClass(input).transform(handlerPackage(basePackage, SPLITTER)).or(false);
}
public static Optional<Class<?>> declaringClass(RequestHandler input) {
if (input == null) {
return Optional.absent();
}
return fromNullable(input.declaringClass());
}
public static Function<Class<?>, Boolean> handlerPackage(String basePackage, String splitter) {
return input -> {
try {
if (StringUtils.isEmpty(basePackage)) {
return false;
}
String[] packages = basePackage.trim().split(splitter);
// Loop to determine matching
for (String strPackage : packages) {
if (input == null) {
continue;
}
Package pkg = input.getPackage();
if (pkg == null) {
continue;
}
String name = pkg.getName();
if (StringUtils.isEmpty(name)) {
continue;
}
boolean isMatch = name.startsWith(strPackage);
if (isMatch) {
return true;
}
}
}
catch (Exception e) {
LOG.error("handler package error", e);
}
return false;
};
}
public static List<Predicate<String>> getExcludePathPredicates(String excludePath) {
List<Predicate<String>> excludePathList = new ArrayList<>();
if (StringUtils.isEmpty(excludePath)) {
return excludePathList;
}
String[] exs = excludePath.split(SPLITTER);
for (String ex : exs) {
if (!StringUtils.isEmpty(ex)) {
excludePathList.add(PathSelectors.ant(ex));
}
}
return excludePathList;
}
public static List<Predicate<String>> getBasePathPredicates(String basePath) {
List<Predicate<String>> basePathList = new ArrayList<>();
if (!StringUtils.isEmpty(basePath)) {
String[] bps = basePath.split(SPLITTER);
for (String bp : bps) {
if (!StringUtils.isEmpty(bp)) {
basePathList.add(PathSelectors.ant(bp));
}
}
}
if (basePathList.isEmpty()) {
basePathList.add(PathSelectors.ant("/**"));
}
return basePathList;
}
public static String scanPackage(String configBasePackage) {
String validScanPackage;
// Externally configured scan package
Set<String> configPackageSet = new HashSet<>();
if (!StringUtils.isEmpty(configBasePackage)) {
configPackageSet.addAll(Arrays.asList(configBasePackage.split(SPLITTER)));
}
Object mainClz = SwaggerContext.getAttribute(String.format("$%s", "MainClass"));
// Verification of the valid path of MainClass
if (mainClz != null) {
Set<String> autoDetectPackageSet = parseDefaultScanPackage((Class<?>) mainClz);
if (LOG.isInfoEnabled() && !autoDetectPackageSet.isEmpty()) {
LOG.info("Auto detect default swagger scan packages: {}",
String.join(SPLITTER, autoDetectPackageSet).trim());
}
Set<String> validScanPackageSet = merge(configPackageSet, autoDetectPackageSet);
validScanPackage = String.join(SPLITTER, validScanPackageSet).trim();
if (LOG.isInfoEnabled() && !StringUtils.isEmpty(validScanPackage)) {
LOG.info("Swagger scan valid packages: {}", validScanPackage);
}
}
else {
// If there is no MainClass, the configured path is used for scanning
validScanPackage = String.join(SPLITTER, configPackageSet);
if (LOG.isWarnEnabled()) {
LOG.warn("Cannot detect main class, swagger scanning packages is set to: {}",
validScanPackage);
}
}
return validScanPackage;
}
public static Set<String> merge(Set<String> configPackageSet, Set<String> autoDetectPackageSet) {
if (configPackageSet == null || configPackageSet.size() == 0) {
return autoDetectPackageSet;
}
return configPackageSet;
}
public static Set<String> parseDefaultScanPackage(Class<?> mainClass) {
Set<String> packageSets = new HashSet<>();
String defaultPackage = mainClass.getPackage().getName();
try {
boolean springBootEnv = true;
try {
Class.forName("org.springframework.boot.autoconfigure.SpringBootApplication");
}
catch (Throwable t) {
LOG.info("Can not load annotation @SpringBootApplication, " +
"current environment is not in spring boot framework. ");
springBootEnv = false;
}
if (!springBootEnv) {
packageSets.add(defaultPackage);
return packageSets;
}
SpringBootApplication bootAnnotation = mainClass.getAnnotation(SpringBootApplication.class);
Class<?>[] baseClassPackages;
String[] basePackages;
if (bootAnnotation == null) {
packageSets.add(defaultPackage);
}
else {
// baseClassPackages annotation
baseClassPackages = bootAnnotation.scanBasePackageClasses();
for (Class<?> clz : baseClassPackages) {
packageSets.add(clz.getPackage().getName());
}
// basePackage annotation
basePackages = bootAnnotation.scanBasePackages();
packageSets.addAll(Arrays.asList(basePackages));
// When basePackage and baseClassPackages are both empty, the package path where the MainClass class is located is used by default.
if (packageSets.isEmpty()) {
packageSets.add(defaultPackage);
}
}
}
catch (Throwable t) {
LOG.warn("Swagger scan package is empty and auto detect main class occur exception: {}",
t.getMessage());
}
return packageSets;
}
}

@ -0,0 +1,90 @@
/*
*
* Copyright 2015 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 springfox.documentation.spring.web;
import java.util.HashSet;
import java.util.Set;
import java.util.stream.Collectors;
import org.springframework.web.servlet.mvc.condition.PatternsRequestCondition;
import static springfox.documentation.spring.web.paths.Paths.maybeChompLeadingSlash;
import static springfox.documentation.spring.web.paths.Paths.maybeChompTrailingSlash;
/**
* Modified to be compatible with spring-boot-actuator.
*/
public class WebMvcPatternsRequestConditionWrapper
implements springfox.documentation.spring.wrapper.PatternsRequestCondition<PatternsRequestCondition> {
private final String contextPath;
private final PatternsRequestCondition condition;
public WebMvcPatternsRequestConditionWrapper(
String contextPath,
PatternsRequestCondition condition) {
this.contextPath = contextPath;
this.condition = condition;
}
@Override
public springfox.documentation.spring.wrapper.PatternsRequestCondition combine(
springfox.documentation.spring.wrapper.PatternsRequestCondition<PatternsRequestCondition> other) {
if (other instanceof WebMvcPatternsRequestConditionWrapper && !this.equals(other)) {
return new WebMvcPatternsRequestConditionWrapper(
contextPath,
condition.combine(((WebMvcPatternsRequestConditionWrapper) other).condition));
}
return this;
}
@Override
public Set<String> getPatterns() {
// polaris add start
if (this.condition == null) {
return new HashSet<>();
}
// polaris add end
return this.condition.getPatterns().stream()
.map(p -> String.format("%s/%s", maybeChompTrailingSlash(contextPath), maybeChompLeadingSlash(p)))
.collect(Collectors.toSet());
}
@Override
public boolean equals(Object o) {
if (o instanceof WebMvcPatternsRequestConditionWrapper) {
return this.condition.equals(((WebMvcPatternsRequestConditionWrapper) o).condition);
}
return false;
}
@Override
public int hashCode() {
return this.condition.hashCode();
}
@Override
public String toString() {
return this.condition.toString();
}
}

@ -0,0 +1,175 @@
/*
*
* Copyright 2016-2017 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 springfox.documentation.spring.web;
import java.lang.annotation.Annotation;
import java.util.HashSet;
import java.util.List;
import java.util.Optional;
import java.util.Set;
import java.util.StringJoiner;
import com.fasterxml.classmate.ResolvedType;
import springfox.documentation.RequestHandler;
import springfox.documentation.RequestHandlerKey;
import springfox.documentation.service.ResolvedMethodParameter;
import springfox.documentation.spring.web.readers.operation.HandlerMethodResolver;
import springfox.documentation.spring.wrapper.NameValueExpression;
import springfox.documentation.spring.wrapper.PatternsRequestCondition;
import org.springframework.core.annotation.AnnotationUtils;
import org.springframework.http.MediaType;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.method.HandlerMethod;
import org.springframework.web.servlet.mvc.method.RequestMappingInfo;
import static java.util.Optional.ofNullable;
/**
* Modified to be compatible with spring-boot-actuator.
*/
public class WebMvcRequestHandler implements RequestHandler {
private final String contextPath;
private final HandlerMethodResolver methodResolver;
private final RequestMappingInfo requestMapping;
private final HandlerMethod handlerMethod;
public WebMvcRequestHandler(
String contextPath,
HandlerMethodResolver methodResolver,
RequestMappingInfo requestMapping,
HandlerMethod handlerMethod) {
this.contextPath = contextPath;
this.methodResolver = methodResolver;
this.requestMapping = requestMapping;
this.handlerMethod = handlerMethod;
}
@Override
public HandlerMethod getHandlerMethod() {
return handlerMethod;
}
@Override
public RequestHandler combine(RequestHandler other) {
return this;
}
@Override
public Class<?> declaringClass() {
return handlerMethod.getBeanType();
}
@Override
public boolean isAnnotatedWith(Class<? extends Annotation> annotation) {
return null != AnnotationUtils.findAnnotation(handlerMethod.getMethod(), annotation);
}
@Override
public PatternsRequestCondition getPatternsCondition() {
return new WebMvcPatternsRequestConditionWrapper(
contextPath,
requestMapping.getPatternsCondition());
}
@Override
public String groupName() {
return ControllerNamingUtils.controllerNameAsGroup(handlerMethod);
}
@Override
public String getName() {
return handlerMethod.getMethod().getName();
}
@Override
public Set<RequestMethod> supportedMethods() {
return requestMapping.getMethodsCondition().getMethods();
}
@Override
public Set<MediaType> produces() {
return requestMapping.getProducesCondition().getProducibleMediaTypes();
}
@Override
public Set<MediaType> consumes() {
return requestMapping.getConsumesCondition().getConsumableMediaTypes();
}
@Override
public Set<NameValueExpression<String>> headers() {
return WebMvcNameValueExpressionWrapper.from(requestMapping.getHeadersCondition().getExpressions());
}
@Override
public Set<NameValueExpression<String>> params() {
return WebMvcNameValueExpressionWrapper.from(requestMapping.getParamsCondition().getExpressions());
}
@Override
public <T extends Annotation> Optional<T> findAnnotation(Class<T> annotation) {
return ofNullable(AnnotationUtils.findAnnotation(handlerMethod.getMethod(), annotation));
}
@Override
public RequestHandlerKey key() {
// polaris add start
Set<String> patterns = new HashSet<>();
if (requestMapping.getPatternsCondition() != null && requestMapping.getPatternsCondition()
.getPatterns() != null) {
patterns = requestMapping.getPatternsCondition().getPatterns();
}
// polaris add end
return new RequestHandlerKey(
patterns,
requestMapping.getMethodsCondition().getMethods(),
requestMapping.getConsumesCondition().getConsumableMediaTypes(),
requestMapping.getProducesCondition().getProducibleMediaTypes());
}
@Override
public springfox.documentation.spring.wrapper.RequestMappingInfo<?> getRequestMapping() {
return new WebMvcRequestMappingInfoWrapper(requestMapping);
}
@Override
public List<ResolvedMethodParameter> getParameters() {
return methodResolver.methodParameters(handlerMethod);
}
@Override
public ResolvedType getReturnType() {
return methodResolver.methodReturnType(handlerMethod);
}
@Override
public <T extends Annotation> Optional<T> findControllerAnnotation(Class<T> annotation) {
return ofNullable(AnnotationUtils.findAnnotation(handlerMethod.getBeanType(), annotation));
}
@Override
public String toString() {
return new StringJoiner(", ", WebMvcRequestHandler.class.getSimpleName() + "{", "}")
.add("requestMapping=" + requestMapping)
.add("handlerMethod=" + handlerMethod)
.add("key=" + key())
.toString();
}
}

@ -0,0 +1,46 @@
{
"properties": [
{
"name": "spring.cloud.polaris.contract.enabled",
"type": "java.lang.Boolean",
"defaultValue": true,
"description": "Enable polaris record contract or not."
},
{
"name": "spring.cloud.polaris.contract.basePackage",
"type": "java.lang.String",
"defaultValue": "",
"description": "Packages to be scanned. Split by \",\"."
},
{
"name": "spring.cloud.polaris.contract.excludePath",
"type": "java.lang.String",
"defaultValue": "",
"description": "Paths to be excluded. Split by \",\"."
},
{
"name": "spring.cloud.polaris.contract.group",
"type": "java.lang.String",
"defaultValue": "default",
"description": "Group to create swagger docket."
},
{
"name": "spring.cloud.polaris.contract.basePath",
"type": "java.lang.String",
"defaultValue": "/**",
"description": "Base paths to be scanned. Split by \",\"."
},
{
"name": "spring.cloud.polaris.contract.exposure",
"type": "java.lang.Boolean",
"defaultValue": "true",
"description": "Enable polaris contract exposure or not."
},
{
"name": "spring.cloud.polaris.contract.report.enabled",
"type": "java.lang.Boolean",
"defaultValue": "true",
"description": "Enable polaris contract report or not."
}
]
}

@ -0,0 +1,7 @@
org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
com.tencent.cloud.polaris.contract.config.PolarisSwaggerAutoConfiguration,\
com.tencent.cloud.polaris.contract.config.PolarisContractProperties
org.springframework.cloud.bootstrap.BootstrapConfiguration=\
com.tencent.cloud.polaris.contract.config.PolarisContractPropertiesAutoConfiguration
org.springframework.context.ApplicationListener=\
com.tencent.cloud.polaris.contract.PolarisSwaggerApplicationListener

@ -64,7 +64,7 @@ public class PolarisDiscoveryProperties {
/** /**
* Version number. * Version number.
*/ */
private String version; private String version = "1.0.0";
/** /**
* Protocol name such as http, https. * Protocol name such as http, https.

@ -25,12 +25,12 @@ import com.tencent.cloud.rpc.enhancement.resttemplate.EnhancedRestTemplateInterc
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.autoconfigure.AutoConfigureAfter; import org.springframework.boot.autoconfigure.AutoConfigureAfter;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.boot.context.properties.EnableConfigurationProperties; import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.cloud.client.ConditionalOnDiscoveryEnabled; import org.springframework.cloud.client.ConditionalOnDiscoveryEnabled;
import org.springframework.cloud.client.loadbalancer.LoadBalancerInterceptor; import org.springframework.cloud.client.loadbalancer.LoadBalancerInterceptor;
import org.springframework.cloud.client.loadbalancer.RestTemplateCustomizer; import org.springframework.cloud.client.loadbalancer.RestTemplateCustomizer;
import org.springframework.cloud.client.loadbalancer.RetryLoadBalancerInterceptor;
import org.springframework.cloud.loadbalancer.annotation.LoadBalancerClients; import org.springframework.cloud.loadbalancer.annotation.LoadBalancerClients;
import org.springframework.cloud.loadbalancer.config.LoadBalancerAutoConfiguration; import org.springframework.cloud.loadbalancer.config.LoadBalancerAutoConfiguration;
import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Bean;
@ -52,19 +52,23 @@ import org.springframework.http.client.ClientHttpRequestInterceptor;
public class PolarisLoadBalancerAutoConfiguration { public class PolarisLoadBalancerAutoConfiguration {
@Bean @Bean
@ConditionalOnMissingBean public RestTemplateCustomizer restTemplateCustomizer(
public RestTemplateCustomizer restTemplateCustomizer(@Autowired(required = false) LoadBalancerInterceptor loadBalancerInterceptor) { @Autowired(required = false) RetryLoadBalancerInterceptor retryLoadBalancerInterceptor,
@Autowired(required = false) LoadBalancerInterceptor loadBalancerInterceptor) {
return restTemplate -> { return restTemplate -> {
List<ClientHttpRequestInterceptor> list = new ArrayList<>(restTemplate.getInterceptors()); List<ClientHttpRequestInterceptor> list = new ArrayList<>(restTemplate.getInterceptors());
// LoadBalancerInterceptor must invoke before EnhancedRestTemplateInterceptor // LoadBalancerInterceptor must invoke before EnhancedRestTemplateInterceptor
if (loadBalancerInterceptor != null) { if (retryLoadBalancerInterceptor != null || loadBalancerInterceptor != null) {
int addIndex = list.size(); int addIndex = list.size();
for (int i = 0; i < list.size(); i++) { for (int i = 0; i < list.size(); i++) {
if (list.get(i) instanceof EnhancedRestTemplateInterceptor) { if (list.get(i) instanceof EnhancedRestTemplateInterceptor) {
addIndex = i; addIndex = i;
} }
} }
list.add(addIndex, loadBalancerInterceptor); list.add(addIndex,
retryLoadBalancerInterceptor != null
? retryLoadBalancerInterceptor
: loadBalancerInterceptor);
} }
restTemplate.setInterceptors(list); restTemplate.setInterceptors(list);
}; };

@ -31,14 +31,14 @@ import com.tencent.cloud.rpc.enhancement.stat.config.PolarisStatProperties;
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.autoconfigure.AutoConfigureAfter; import org.springframework.boot.autoconfigure.AutoConfigureAfter;
import org.springframework.boot.autoconfigure.AutoConfigureBefore;
import org.springframework.boot.autoconfigure.condition.ConditionalOnBean; import org.springframework.boot.autoconfigure.condition.ConditionalOnBean;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.boot.context.properties.EnableConfigurationProperties; import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.boot.web.reactive.context.ReactiveWebServerApplicationContext; import org.springframework.boot.web.reactive.context.ReactiveWebServerApplicationContext;
import org.springframework.boot.web.servlet.context.ServletWebServerApplicationContext; import org.springframework.boot.web.servlet.context.ServletWebServerApplicationContext;
import org.springframework.cloud.client.serviceregistry.AutoServiceRegistrationAutoConfiguration; import org.springframework.cloud.client.serviceregistry.AutoServiceRegistrationAutoConfiguration;
import org.springframework.cloud.client.serviceregistry.AutoServiceRegistrationConfiguration;
import org.springframework.cloud.client.serviceregistry.AutoServiceRegistrationProperties; import org.springframework.cloud.client.serviceregistry.AutoServiceRegistrationProperties;
import org.springframework.cloud.client.serviceregistry.ServiceRegistryAutoConfiguration;
import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration; import org.springframework.context.annotation.Configuration;
@ -49,10 +49,10 @@ import org.springframework.context.annotation.Configuration;
*/ */
@Configuration(proxyBeanMethods = false) @Configuration(proxyBeanMethods = false)
@EnableConfigurationProperties @EnableConfigurationProperties
@ConditionalOnBean(AutoServiceRegistrationProperties.class)
@ConditionalOnPolarisRegisterEnabled @ConditionalOnPolarisRegisterEnabled
@ConditionalOnProperty(value = "spring.cloud.service-registry.auto-registration.enabled", matchIfMissing = true) @AutoConfigureBefore(ServiceRegistryAutoConfiguration.class)
@AutoConfigureAfter({AutoServiceRegistrationConfiguration.class, AutoServiceRegistrationAutoConfiguration.class, @AutoConfigureAfter({AutoServiceRegistrationAutoConfiguration.class, PolarisDiscoveryAutoConfiguration.class})
PolarisDiscoveryAutoConfiguration.class})
public class PolarisServiceRegistryAutoConfiguration { public class PolarisServiceRegistryAutoConfiguration {
@Bean @Bean
@ -65,7 +65,6 @@ public class PolarisServiceRegistryAutoConfiguration {
} }
@Bean @Bean
@ConditionalOnBean(AutoServiceRegistrationProperties.class)
public PolarisRegistration polarisRegistration( public PolarisRegistration polarisRegistration(
PolarisDiscoveryProperties polarisDiscoveryProperties, PolarisDiscoveryProperties polarisDiscoveryProperties,
PolarisContextProperties polarisContextProperties, PolarisContextProperties polarisContextProperties,
@ -81,7 +80,6 @@ public class PolarisServiceRegistryAutoConfiguration {
} }
@Bean @Bean
@ConditionalOnBean(AutoServiceRegistrationProperties.class)
public PolarisAutoServiceRegistration polarisAutoServiceRegistration( public PolarisAutoServiceRegistration polarisAutoServiceRegistration(
PolarisServiceRegistry registry, PolarisServiceRegistry registry,
AutoServiceRegistrationProperties autoServiceRegistrationProperties, AutoServiceRegistrationProperties autoServiceRegistrationProperties,

@ -171,5 +171,10 @@ public class OrderConstant {
* Order of stat reporter configuration modifier. * Order of stat reporter configuration modifier.
*/ */
public static Integer STAT_REPORTER_ORDER = 1; public static Integer STAT_REPORTER_ORDER = 1;
/**
* Order of service contract configuration modifier.
*/
public static Integer SERVICE_CONTRACT_ORDER = Integer.MAX_VALUE - 9;
} }
} }

@ -68,8 +68,8 @@ public final class MetadataContextHolder {
metadataContext.setTransitiveMetadata(staticMetadataManager.getMergedStaticTransitiveMetadata()); metadataContext.setTransitiveMetadata(staticMetadataManager.getMergedStaticTransitiveMetadata());
metadataContext.setDisposableMetadata(staticMetadataManager.getMergedStaticDisposableMetadata()); metadataContext.setDisposableMetadata(staticMetadataManager.getMergedStaticDisposableMetadata());
if (StringUtils.hasText(staticMetadataManager.getTransHeaderFromEnv())) { if (StringUtils.hasText(staticMetadataManager.getTransHeader())) {
metadataContext.setTransHeaders(staticMetadataManager.getTransHeaderFromEnv(), ""); metadataContext.setTransHeaders(staticMetadataManager.getTransHeader(), "");
} }
METADATA_CONTEXT.set(metadataContext); METADATA_CONTEXT.set(metadataContext);

@ -17,8 +17,11 @@
package com.tencent.cloud.common.metadata; package com.tencent.cloud.common.metadata;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections; import java.util.Collections;
import java.util.HashMap; import java.util.HashMap;
import java.util.HashSet;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
import java.util.Set; import java.util.Set;
@ -71,6 +74,7 @@ public class StaticMetadataManager {
private Map<String, String> configMetadata; private Map<String, String> configMetadata;
private Map<String, String> configTransitiveMetadata; private Map<String, String> configTransitiveMetadata;
private Map<String, String> configDisposableMetadata; private Map<String, String> configDisposableMetadata;
private String configTransHeaders;
private Map<String, String> customSPIMetadata; private Map<String, String> customSPIMetadata;
private Map<String, String> customSPITransitiveMetadata; private Map<String, String> customSPITransitiveMetadata;
private Map<String, String> customSPIDisposableMetadata; private Map<String, String> customSPIDisposableMetadata;
@ -162,6 +166,7 @@ public class StaticMetadataManager {
Map<String, String> allMetadata = metadataLocalProperties.getContent(); Map<String, String> allMetadata = metadataLocalProperties.getContent();
List<String> transitiveKeys = metadataLocalProperties.getTransitive(); List<String> transitiveKeys = metadataLocalProperties.getTransitive();
List<String> disposableKeys = metadataLocalProperties.getDisposable(); List<String> disposableKeys = metadataLocalProperties.getDisposable();
List<String> headers = metadataLocalProperties.getHeaders();
Map<String, String> transitiveResult = new HashMap<>(); Map<String, String> transitiveResult = new HashMap<>();
for (String key : transitiveKeys) { for (String key : transitiveKeys) {
@ -179,6 +184,7 @@ public class StaticMetadataManager {
configTransitiveMetadata = Collections.unmodifiableMap(transitiveResult); configTransitiveMetadata = Collections.unmodifiableMap(transitiveResult);
configDisposableMetadata = Collections.unmodifiableMap(disposableResult); configDisposableMetadata = Collections.unmodifiableMap(disposableResult);
configTransHeaders = CollectionUtils.isEmpty(headers) ? null : String.join(",", headers);
configMetadata = Collections.unmodifiableMap(allMetadata); configMetadata = Collections.unmodifiableMap(allMetadata);
} }
@ -313,6 +319,29 @@ public class StaticMetadataManager {
return envNotReportMetadata.get(ENV_TRAFFIC_CONTENT_RAW_TRANSHEADERS); return envNotReportMetadata.get(ENV_TRAFFIC_CONTENT_RAW_TRANSHEADERS);
} }
public String getTransHeaderFromConfig() {
return configTransHeaders;
}
public String getTransHeader() {
Set<String> transHeaderSet = new HashSet<>();
String transHeaderFromEnv = getTransHeaderFromEnv();
String transHeaderFromConfig = getTransHeaderFromConfig();
Set<String> transHeaderFromEnvSet = StringUtils.isNotBlank(transHeaderFromEnv)
? Arrays.stream(transHeaderFromEnv.split(",")).collect(Collectors.toSet())
: Collections.emptySet();
Set<String> transHeaderFromConfigSet = StringUtils.isNotBlank(transHeaderFromConfig)
? Arrays.stream(transHeaderFromConfig.split(",")).collect(Collectors.toSet())
: Collections.emptySet();
transHeaderSet.addAll(transHeaderFromEnvSet);
transHeaderSet.addAll(transHeaderFromConfigSet);
return new ArrayList<>(transHeaderSet).stream().sorted().collect(Collectors.joining(","));
}
public Map<String, String> getEnvTransitiveMetadata() { public Map<String, String> getEnvTransitiveMetadata() {
return envTransitiveMetadata; return envTransitiveMetadata;
} }
@ -390,6 +419,7 @@ public class StaticMetadataManager {
", envTransitiveMetadata=" + envTransitiveMetadata + ", envTransitiveMetadata=" + envTransitiveMetadata +
", configMetadata=" + configMetadata + ", configMetadata=" + configMetadata +
", configTransitiveMetadata=" + configTransitiveMetadata + ", configTransitiveMetadata=" + configTransitiveMetadata +
", configTransHeaders='" + configTransHeaders + '\'' +
", customSPIMetadata=" + customSPIMetadata + ", customSPIMetadata=" + customSPIMetadata +
", customSPITransitiveMetadata=" + customSPITransitiveMetadata + ", customSPITransitiveMetadata=" + customSPITransitiveMetadata +
", mergedStaticMetadata=" + mergedStaticMetadata + ", mergedStaticMetadata=" + mergedStaticMetadata +

@ -48,6 +48,11 @@ public class MetadataLocalProperties {
*/ */
private List<String> disposable; private List<String> disposable;
/**
* A transitive http header key list.
*/
private List<String> headers;
public Map<String, String> getContent() { public Map<String, String> getContent() {
if (CollectionUtils.isEmpty(content)) { if (CollectionUtils.isEmpty(content)) {
content = new HashMap<>(); content = new HashMap<>();
@ -80,4 +85,15 @@ public class MetadataLocalProperties {
public void setDisposable(List<String> disposable) { public void setDisposable(List<String> disposable) {
this.disposable = disposable; this.disposable = disposable;
} }
public List<String> getHeaders() {
if (CollectionUtils.isEmpty(headers)) {
headers = new ArrayList<>();
}
return headers;
}
public void setHeaders(List<String> headers) {
this.headers = headers;
}
} }

@ -95,6 +95,11 @@ public class PolarisServiceInstance implements ServiceInstance {
return this.scheme; return this.scheme;
} }
/**
* To fix loadbalancer not working bug when importing spring-retry.
* @param o object
* @return if equals
*/
@Override @Override
public boolean equals(Object o) { public boolean equals(Object o) {
if (this == o) { if (this == o) {

@ -14,6 +14,11 @@
"name": "spring.cloud.tencent.metadata.disposable", "name": "spring.cloud.tencent.metadata.disposable",
"type": "java.util.List", "type": "java.util.List",
"description": "Custom disposable metadata key list." "description": "Custom disposable metadata key list."
},
{
"name": "spring.cloud.tencent.metadata.headers",
"type": "java.util.List",
"description": "Custom transitive http header key list."
} }
] ]
} }

@ -52,6 +52,10 @@ public class MetadataContextHolderTest {
Assertions.assertThat(customMetadata.get("a")).isEqualTo("1"); Assertions.assertThat(customMetadata.get("a")).isEqualTo("1");
Assertions.assertThat(customMetadata.get("b")).isEqualTo("2"); Assertions.assertThat(customMetadata.get("b")).isEqualTo("2");
Map<String, String> transHeaders = MetadataContextHolder.get().getTransHeaders();
Assertions.assertThat(transHeaders.size()).isEqualTo(1);
Assertions.assertThat(transHeaders.keySet().iterator().next()).isEqualTo("c,d");
MetadataContextHolder.remove(); MetadataContextHolder.remove();
customMetadata = new HashMap<>(); customMetadata = new HashMap<>();
@ -65,6 +69,10 @@ public class MetadataContextHolderTest {
Assertions.assertThat(customMetadata.get("b")).isEqualTo("22"); Assertions.assertThat(customMetadata.get("b")).isEqualTo("22");
Assertions.assertThat(customMetadata.get("c")).isEqualTo("3"); Assertions.assertThat(customMetadata.get("c")).isEqualTo("3");
Assertions.assertThat(MetadataContext.LOCAL_NAMESPACE).isEqualTo("default"); Assertions.assertThat(MetadataContext.LOCAL_NAMESPACE).isEqualTo("default");
transHeaders = MetadataContextHolder.get().getTransHeaders();
Assertions.assertThat(transHeaders.size()).isEqualTo(1);
Assertions.assertThat(transHeaders.keySet().iterator().next()).isEqualTo("c,d");
} }
@Test @Test

@ -97,6 +97,7 @@ public class StaticMetadataManagerTest {
when(metadataLocalProperties.getContent()).thenReturn(content); when(metadataLocalProperties.getContent()).thenReturn(content);
when(metadataLocalProperties.getTransitive()).thenReturn(Collections.singletonList("k1")); when(metadataLocalProperties.getTransitive()).thenReturn(Collections.singletonList("k1"));
when(metadataLocalProperties.getDisposable()).thenReturn(Collections.singletonList("k1")); when(metadataLocalProperties.getDisposable()).thenReturn(Collections.singletonList("k1"));
when(metadataLocalProperties.getHeaders()).thenReturn(Arrays.asList("a", "d"));
StaticMetadataManager metadataManager = new StaticMetadataManager(metadataLocalProperties, null); StaticMetadataManager metadataManager = new StaticMetadataManager(metadataLocalProperties, null);
@ -119,6 +120,9 @@ public class StaticMetadataManagerTest {
Map<String, String> locationInfo = metadataManager.getLocationMetadata(); Map<String, String> locationInfo = metadataManager.getLocationMetadata();
assertThat(locationInfo.get("zone")).isEqualTo("zone1"); assertThat(locationInfo.get("zone")).isEqualTo("zone1");
assertThat(locationInfo.get("region")).isEqualTo("region1"); assertThat(locationInfo.get("region")).isEqualTo("region1");
String transHeaderFromConfig = metadataManager.getTransHeaderFromConfig();
assertThat(transHeaderFromConfig).isEqualTo("a,d");
} }
@Test @Test
@ -161,6 +165,9 @@ public class StaticMetadataManagerTest {
@Test @Test
public void testMergedMetadata() { public void testMergedMetadata() {
// set environment variables
environmentVariables.set("SCT_TRAFFIC_CONTENT_RAW_TRANSHEADERS", "a,b,c,e");
Map<String, String> content = new HashMap<>(); Map<String, String> content = new HashMap<>();
content.put("k1", "v1"); content.put("k1", "v1");
content.put("k2", "v2"); content.put("k2", "v2");
@ -170,6 +177,7 @@ public class StaticMetadataManagerTest {
when(metadataLocalProperties.getContent()).thenReturn(content); when(metadataLocalProperties.getContent()).thenReturn(content);
when(metadataLocalProperties.getTransitive()).thenReturn(Collections.singletonList("k1")); when(metadataLocalProperties.getTransitive()).thenReturn(Collections.singletonList("k1"));
when(metadataLocalProperties.getHeaders()).thenReturn(Arrays.asList("b", "d"));
StaticMetadataManager metadataManager = new StaticMetadataManager(metadataLocalProperties, StaticMetadataManager metadataManager = new StaticMetadataManager(metadataLocalProperties,
Arrays.asList(new MockedMetadataProvider(), new DefaultInstanceMetadataProvider(null))); Arrays.asList(new MockedMetadataProvider(), new DefaultInstanceMetadataProvider(null)));
@ -204,6 +212,9 @@ public class StaticMetadataManagerTest {
assertThat(locationInfo.get("zone")).isEqualTo("zone2"); assertThat(locationInfo.get("zone")).isEqualTo("zone2");
assertThat(locationInfo.get("region")).isEqualTo("region1"); assertThat(locationInfo.get("region")).isEqualTo("region1");
assertThat(locationInfo.get("campus")).isEqualTo("campus2"); assertThat(locationInfo.get("campus")).isEqualTo("campus2");
String transHeader = metadataManager.getTransHeader();
assertThat(transHeader).isEqualTo("a,b,c,d,e");
} }
@Test @Test

@ -52,6 +52,12 @@ public class MetadataLocalPropertiesTest {
Assertions.assertThat(metadataLocalProperties.getTransitive().contains("b")).isTrue(); Assertions.assertThat(metadataLocalProperties.getTransitive().contains("b")).isTrue();
} }
@Test
public void test3() {
Assertions.assertThat(metadataLocalProperties.getHeaders().contains("c")).isTrue();
Assertions.assertThat(metadataLocalProperties.getHeaders().contains("d")).isTrue();
}
@SpringBootApplication @SpringBootApplication
protected static class TestApplication { protected static class TestApplication {

@ -14,3 +14,6 @@ spring:
b: 2 b: 2
transitive: transitive:
- b - b
headers:
- c
- d

@ -64,10 +64,14 @@
<artifactId>spring-cloud-starter-tencent-polaris-config</artifactId> <artifactId>spring-cloud-starter-tencent-polaris-config</artifactId>
</dependency> </dependency>
<dependency>
<groupId>com.tencent.cloud</groupId>
<artifactId>spring-cloud-starter-tencent-polaris-contract</artifactId>
</dependency>
<dependency> <dependency>
<groupId>com.tencent.cloud</groupId> <groupId>com.tencent.cloud</groupId>
<artifactId>spring-cloud-starter-tencent-discovery-adapter-plugin</artifactId> <artifactId>spring-cloud-starter-tencent-discovery-adapter-plugin</artifactId>
<version>${revision}</version>
</dependency> </dependency>
<dependency> <dependency>

@ -76,6 +76,8 @@
<polaris.version>1.15.0-SNAPSHOT</polaris.version> <polaris.version>1.15.0-SNAPSHOT</polaris.version>
<guava.version>32.0.1-jre</guava.version> <guava.version>32.0.1-jre</guava.version>
<logback.version>1.2.11</logback.version> <logback.version>1.2.11</logback.version>
<springfox.swagger2.version>3.0.0</springfox.swagger2.version>
<io.swagger.version>1.5.24</io.swagger.version>
<mocktio.version>4.5.1</mocktio.version> <mocktio.version>4.5.1</mocktio.version>
<byte-buddy.version>1.12.10</byte-buddy.version> <byte-buddy.version>1.12.10</byte-buddy.version>
<protobuf-java.version>3.21.7</protobuf-java.version> <protobuf-java.version>3.21.7</protobuf-java.version>
@ -154,6 +156,12 @@
<version>${revision}</version> <version>${revision}</version>
</dependency> </dependency>
<dependency>
<groupId>com.tencent.cloud</groupId>
<artifactId>spring-cloud-starter-tencent-polaris-contract</artifactId>
<version>${revision}</version>
</dependency>
<dependency> <dependency>
<groupId>com.tencent.cloud</groupId> <groupId>com.tencent.cloud</groupId>
<artifactId>spring-cloud-starter-tencent-all</artifactId> <artifactId>spring-cloud-starter-tencent-all</artifactId>
@ -212,6 +220,24 @@
<version>${logback.version}</version> <version>${logback.version}</version>
</dependency> </dependency>
<dependency>
<groupId>io.springfox</groupId>
<artifactId>springfox-boot-starter</artifactId>
<version>${springfox.swagger2.version}</version>
</dependency>
<dependency>
<groupId>io.swagger</groupId>
<artifactId>swagger-models</artifactId>
<version>${io.swagger.version}</version>
</dependency>
<dependency>
<groupId>io.swagger</groupId>
<artifactId>swagger-annotations</artifactId>
<version>${io.swagger.version}</version>
</dependency>
<dependency> <dependency>
<groupId>com.google.protobuf</groupId> <groupId>com.google.protobuf</groupId>
<artifactId>protobuf-java</artifactId> <artifactId>protobuf-java</artifactId>

@ -19,10 +19,10 @@
<artifactId>spring-boot-starter-webflux</artifactId> <artifactId>spring-boot-starter-webflux</artifactId>
</dependency> </dependency>
<!-- <dependency>--> <dependency>
<!-- <groupId>org.springframework.boot</groupId>--> <groupId>com.tencent.cloud</groupId>
<!-- <artifactId>spring-boot-starter-web</artifactId>--> <artifactId>spring-cloud-starter-tencent-polaris-contract</artifactId>
<!-- </dependency>--> </dependency>
<dependency> <dependency>
<groupId>com.tencent.cloud</groupId> <groupId>com.tencent.cloud</groupId>

@ -11,6 +11,8 @@ spring:
discovery: discovery:
enabled: true enabled: true
register: true register: true
contract:
exposure: true
stat: stat:
enabled: true enabled: true
port: 28082 port: 28082

@ -28,6 +28,16 @@
<artifactId>spring-cloud-starter-tencent-polaris-discovery</artifactId> <artifactId>spring-cloud-starter-tencent-polaris-discovery</artifactId>
</dependency> </dependency>
<dependency>
<groupId>com.tencent.cloud</groupId>
<artifactId>spring-cloud-starter-tencent-polaris-contract</artifactId>
</dependency>
<!-- <dependency>-->
<!-- <groupId>org.springframework.retry</groupId>-->
<!-- <artifactId>spring-retry</artifactId>-->
<!-- </dependency>-->
<!-- <dependency>--> <!-- <dependency>-->
<!-- <groupId>com.tencent.polaris</groupId>--> <!-- <groupId>com.tencent.polaris</groupId>-->
<!-- <artifactId>connector-consul</artifactId>--> <!-- <artifactId>connector-consul</artifactId>-->

@ -45,7 +45,7 @@ public class DiscoveryCallerController {
* @param value2 value 2 * @param value2 value 2
* @return sum * @return sum
*/ */
@GetMapping("/feign") @RequestMapping("/feign")
public int feign(@RequestParam int value1, @RequestParam int value2) { public int feign(@RequestParam int value1, @RequestParam int value2) {
return discoveryCalleeService.sum(value1, value2); return discoveryCalleeService.sum(value1, value2);
} }

@ -22,6 +22,10 @@ spring:
heartbeat: heartbeat:
enabled: true enabled: true
health-check-url: /discovery/service/caller/healthCheck health-check-url: /discovery/service/caller/healthCheck
contract:
exposure: true
report:
enabled: true
stat: stat:
enabled: true enabled: true
port: 28081 port: 28081

@ -27,13 +27,14 @@ import com.tencent.polaris.api.pojo.ServiceRule;
import com.tencent.polaris.api.rpc.GetServiceRuleRequest; import com.tencent.polaris.api.rpc.GetServiceRuleRequest;
import com.tencent.polaris.api.rpc.ServiceRuleResponse; import com.tencent.polaris.api.rpc.ServiceRuleResponse;
import com.tencent.polaris.client.api.SDKContext; import com.tencent.polaris.client.api.SDKContext;
import com.tencent.polaris.specification.api.v1.fault.tolerance.CircuitBreakerProto;
import com.tencent.polaris.specification.api.v1.traffic.manage.RateLimitProto; import com.tencent.polaris.specification.api.v1.traffic.manage.RateLimitProto;
import com.tencent.polaris.specification.api.v1.traffic.manage.RoutingProto; import com.tencent.polaris.specification.api.v1.traffic.manage.RoutingProto;
import org.slf4j.Logger; import org.slf4j.Logger;
import org.slf4j.LoggerFactory; import org.slf4j.LoggerFactory;
/** /**
* the manager of service governance rules. for example: rate limit rule, router rules. * the manager of service governance rules. for example: rate limit rule, router rules, circuit breaker rules.
* *
* @author lepdou 2022-05-13 * @author lepdou 2022-05-13
*/ */
@ -88,6 +89,20 @@ public class ServiceRuleManager {
return rules; return rules;
} }
public CircuitBreakerProto.CircuitBreaker getServiceCircuitBreakerRule(String namespace, String service) {
LOG.debug("Get service circuit breaker rules with namespace:{} and service:{}.", namespace, service);
ServiceRule serviceRule = getServiceRule(namespace, service, ServiceEventKey.EventType.CIRCUIT_BREAKING);
if (serviceRule != null) {
Object rule = serviceRule.getRule();
if (rule instanceof CircuitBreakerProto.CircuitBreaker) {
return (CircuitBreakerProto.CircuitBreaker) rule;
}
}
return null;
}
private ServiceRule getServiceRule(String namespace, String service, ServiceEventKey.EventType eventType) { private ServiceRule getServiceRule(String namespace, String service, ServiceEventKey.EventType eventType) {
GetServiceRuleRequest getServiceRuleRequest = new GetServiceRuleRequest(); GetServiceRuleRequest getServiceRuleRequest = new GetServiceRuleRequest();
getServiceRuleRequest.setRuleType(eventType); getServiceRuleRequest.setRuleType(eventType);

@ -25,6 +25,7 @@ import com.tencent.cloud.polaris.context.ModifyAddress;
import com.tencent.cloud.polaris.context.PolarisConfigModifier; import com.tencent.cloud.polaris.context.PolarisConfigModifier;
import com.tencent.cloud.polaris.context.PolarisSDKContextManager; import com.tencent.cloud.polaris.context.PolarisSDKContextManager;
import com.tencent.cloud.polaris.context.ServiceRuleManager; import com.tencent.cloud.polaris.context.ServiceRuleManager;
import com.tencent.cloud.polaris.context.listener.PolarisContextApplicationEventListener;
import com.tencent.polaris.api.exception.PolarisException; import com.tencent.polaris.api.exception.PolarisException;
import com.tencent.polaris.client.api.SDKContext; import com.tencent.polaris.client.api.SDKContext;
@ -58,4 +59,9 @@ public class PolarisContextAutoConfiguration {
public ServiceRuleManager serviceRuleManager(PolarisSDKContextManager polarisSDKContextManager) { public ServiceRuleManager serviceRuleManager(PolarisSDKContextManager polarisSDKContextManager) {
return new ServiceRuleManager(polarisSDKContextManager.getSDKContext(), polarisSDKContextManager.getConsumerAPI()); return new ServiceRuleManager(polarisSDKContextManager.getSDKContext(), polarisSDKContextManager.getConsumerAPI());
} }
@Bean
public PolarisContextApplicationEventListener contextApplicationEventListener(PolarisSDKContextManager polarisSDKContextManager) {
return new PolarisContextApplicationEventListener(polarisSDKContextManager);
}
} }

@ -16,42 +16,33 @@
* *
*/ */
package com.tencent.cloud.polaris.config.listener; package com.tencent.cloud.polaris.context.listener;
import com.tencent.cloud.polaris.context.PolarisSDKContextManager; import com.tencent.cloud.polaris.context.PolarisSDKContextManager;
import com.tencent.polaris.configuration.client.internal.RemoteConfigFileRepo;
import org.springframework.boot.context.event.ApplicationFailedEvent; import org.springframework.boot.context.event.ApplicationFailedEvent;
import org.springframework.boot.context.event.ApplicationPreparedEvent;
import org.springframework.context.ApplicationEvent; import org.springframework.context.ApplicationEvent;
import org.springframework.context.ApplicationListener; import org.springframework.context.ApplicationListener;
import org.springframework.lang.NonNull; import org.springframework.lang.NonNull;
/* /**
* Polaris config non-daemon thread stop listener * @author frankjlli
* * @since 2023/9/18
* @author shuiqingliu
* @since 2023/8/29
**/ **/
public class PolarisConfigApplicationEventListener implements ApplicationListener<ApplicationEvent> {
public class PolarisContextApplicationEventListener implements ApplicationListener<ApplicationEvent> {
private final PolarisSDKContextManager polarisSDKContextManager; private final PolarisSDKContextManager polarisSDKContextManager;
public PolarisConfigApplicationEventListener(PolarisSDKContextManager polarisSDKContextManager) { public PolarisContextApplicationEventListener(PolarisSDKContextManager polarisSDKContextManager) {
this.polarisSDKContextManager = polarisSDKContextManager; this.polarisSDKContextManager = polarisSDKContextManager;
} }
@Override @Override
public void onApplicationEvent(@NonNull ApplicationEvent event) { public void onApplicationEvent(@NonNull ApplicationEvent event) {
if (event instanceof ApplicationPreparedEvent) {
RemoteConfigFileRepo.registerRepoDestroyHook(polarisSDKContextManager.getSDKContext());
}
if (event instanceof ApplicationFailedEvent) { if (event instanceof ApplicationFailedEvent) {
RemoteConfigFileRepo.registerRepoDestroyHook(polarisSDKContextManager.getSDKContext());
//implicit invoke 'destroy' when the spring application fails to start, in order to stop non-daemon threads. //implicit invoke 'destroy' when the spring application fails to start, in order to stop non-daemon threads.
polarisSDKContextManager.getSDKContext().destroy(); polarisSDKContextManager.getSDKContext().destroy();
} }
} }
} }

@ -16,7 +16,9 @@
*/ */
package com.tencent.cloud.polaris.context.logging; package com.tencent.cloud.polaris.context.logging;
import com.tencent.polaris.logging.LoggingConsts;
import com.tencent.polaris.logging.PolarisLogging; import com.tencent.polaris.logging.PolarisLogging;
import org.apache.commons.lang.StringUtils;
import org.springframework.boot.context.event.ApplicationEnvironmentPreparedEvent; import org.springframework.boot.context.event.ApplicationEnvironmentPreparedEvent;
import org.springframework.boot.context.event.ApplicationFailedEvent; import org.springframework.boot.context.event.ApplicationFailedEvent;
@ -24,6 +26,7 @@ import org.springframework.boot.context.logging.LoggingApplicationListener;
import org.springframework.context.ApplicationEvent; import org.springframework.context.ApplicationEvent;
import org.springframework.context.event.GenericApplicationListener; import org.springframework.context.event.GenericApplicationListener;
import org.springframework.core.ResolvableType; import org.springframework.core.ResolvableType;
import org.springframework.core.env.ConfigurableEnvironment;
import org.springframework.lang.NonNull; import org.springframework.lang.NonNull;
/** /**
@ -52,6 +55,22 @@ public class PolarisLoggingApplicationListener implements GenericApplicationList
@Override @Override
public void onApplicationEvent(@NonNull ApplicationEvent applicationEvent) { public void onApplicationEvent(@NonNull ApplicationEvent applicationEvent) {
ConfigurableEnvironment environment = null;
if (ApplicationEnvironmentPreparedEvent.class.isAssignableFrom(applicationEvent.getClass())) {
environment = ((ApplicationEnvironmentPreparedEvent) applicationEvent).getEnvironment();
}
else if (ApplicationFailedEvent.class.isAssignableFrom(applicationEvent.getClass())) {
environment = ((ApplicationFailedEvent) applicationEvent).getApplicationContext().getEnvironment();
}
if (environment != null) {
String loggingPath = environment.getProperty("spring.cloud.polaris.logging.path");
if (StringUtils.isNotBlank(loggingPath)) {
System.setProperty(LoggingConsts.LOGGING_PATH_PROPERTY, loggingPath);
}
}
PolarisLogging.getInstance().loadConfiguration(); PolarisLogging.getInstance().loadConfiguration();
} }
} }

@ -45,6 +45,12 @@
"type": "java.lang.Integer", "type": "java.lang.Integer",
"defaultValue": "", "defaultValue": "",
"description": "current server local port to be registered." "description": "current server local port to be registered."
},
{
"name": "spring.cloud.polaris.logging.path",
"type": "java.lang.String",
"defaultValue": "./polaris/logs",
"description": "polaris log storage path."
} }
], ],
"hints": [] "hints": []

@ -0,0 +1,43 @@
/*
* Tencent is pleased to support the open source community by making Spring Cloud Tencent available.
*
* Copyright (C) 2019 THL A29 Limited, a Tencent company. All rights reserved.
*
* Licensed under the BSD 3-Clause License (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://opensource.org/licenses/BSD-3-Clause
*
* 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.tencent.cloud.polaris.context.logging;
import org.junit.jupiter.api.Test;
import org.springframework.boot.test.context.runner.ApplicationContextRunner;
import static org.assertj.core.api.Assertions.assertThat;
/**
* Test to get <code>spring.cloud.polaris.logging.path</code> from environment.
*
* @author wenxuan70
*/
public class PolarisLoggingPathPropertyTest {
private final ApplicationContextRunner contextRunner = new ApplicationContextRunner()
.withPropertyValues("spring.cloud.polaris.logging.path=/tmp/polaris/logs");
@Test
public void testGetPropertyFromEnvironment() {
contextRunner.run(context -> {
String loggingPath = context.getEnvironment().getProperty("spring.cloud.polaris.logging.path");
assertThat(loggingPath).isEqualTo("/tmp/polaris/logs");
});
}
}

@ -0,0 +1,44 @@
/*
* Tencent is pleased to support the open source community by making Spring Cloud Tencent available.
*
* Copyright (C) 2019 THL A29 Limited, a Tencent company. All rights reserved.
*
* Licensed under the BSD 3-Clause License (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://opensource.org/licenses/BSD-3-Clause
*
* 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.tencent.cloud.polaris.context.logging;
import com.tencent.cloud.polaris.context.PolarisContextApplication;
import com.tencent.polaris.logging.LoggingConsts;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.test.context.junit.jupiter.SpringExtension;
import static org.assertj.core.api.Assertions.assertThat;
/**
* Test for {@link PolarisLoggingApplicationListener}
*
* @author wenxuan70
*/
@ExtendWith(SpringExtension.class)
@SpringBootTest(classes = PolarisContextApplication.class,
properties = {"spring.config.location=classpath:bootstrap.yml"})
public class PolarisLoggingPathSystemPropertyTest {
@Test
public void testSystemProperty() {
assertThat(System.getProperty(LoggingConsts.LOGGING_PATH_PROPERTY)).isEqualTo("/tmp/polaris/logs");
}
}

@ -7,3 +7,5 @@ spring:
service: TestApp service: TestApp
enabled: true enabled: true
local-port: 9090 local-port: 9090
logging:
path: /tmp/polaris/logs

@ -30,12 +30,6 @@ import com.tencent.cloud.rpc.enhancement.filter.EnhancedServletFilter;
import com.tencent.cloud.rpc.enhancement.plugin.DefaultEnhancedPluginRunner; import com.tencent.cloud.rpc.enhancement.plugin.DefaultEnhancedPluginRunner;
import com.tencent.cloud.rpc.enhancement.plugin.EnhancedPlugin; import com.tencent.cloud.rpc.enhancement.plugin.EnhancedPlugin;
import com.tencent.cloud.rpc.enhancement.plugin.EnhancedPluginRunner; import com.tencent.cloud.rpc.enhancement.plugin.EnhancedPluginRunner;
import com.tencent.cloud.rpc.enhancement.plugin.assembly.client.AssemblyClientExceptionHook;
import com.tencent.cloud.rpc.enhancement.plugin.assembly.client.AssemblyClientPostHook;
import com.tencent.cloud.rpc.enhancement.plugin.assembly.client.AssemblyClientPreHook;
import com.tencent.cloud.rpc.enhancement.plugin.assembly.server.AssemblyServerExceptionHook;
import com.tencent.cloud.rpc.enhancement.plugin.assembly.server.AssemblyServerPostHook;
import com.tencent.cloud.rpc.enhancement.plugin.assembly.server.AssemblyServerPreHook;
import com.tencent.cloud.rpc.enhancement.plugin.reporter.ExceptionPolarisReporter; import com.tencent.cloud.rpc.enhancement.plugin.reporter.ExceptionPolarisReporter;
import com.tencent.cloud.rpc.enhancement.plugin.reporter.SuccessPolarisReporter; import com.tencent.cloud.rpc.enhancement.plugin.reporter.SuccessPolarisReporter;
import com.tencent.cloud.rpc.enhancement.resttemplate.EnhancedRestTemplateInterceptor; import com.tencent.cloud.rpc.enhancement.resttemplate.EnhancedRestTemplateInterceptor;
@ -115,36 +109,6 @@ public class RpcEnhancementAutoConfiguration {
return new ExceptionPolarisReporter(properties, polarisSDKContextManager.getConsumerAPI()); return new ExceptionPolarisReporter(properties, polarisSDKContextManager.getConsumerAPI());
} }
@Bean
public AssemblyClientExceptionHook assemblyClientExceptionHook(PolarisSDKContextManager polarisSDKContextManager, InstanceTransformer instanceTransformer) {
return new AssemblyClientExceptionHook(polarisSDKContextManager.getAssemblyAPI(), instanceTransformer);
}
@Bean
public AssemblyClientPostHook assemblyClientPostHook(PolarisSDKContextManager polarisSDKContextManager, InstanceTransformer instanceTransformer) {
return new AssemblyClientPostHook(polarisSDKContextManager.getAssemblyAPI(), instanceTransformer);
}
@Bean
public AssemblyClientPreHook assemblyClientPreHook(PolarisSDKContextManager polarisSDKContextManager) {
return new AssemblyClientPreHook(polarisSDKContextManager.getAssemblyAPI());
}
@Bean
public AssemblyServerExceptionHook assemblyServerExceptionHook(PolarisSDKContextManager polarisSDKContextManager) {
return new AssemblyServerExceptionHook(polarisSDKContextManager.getAssemblyAPI());
}
@Bean
public AssemblyServerPostHook assemblyServerPostHook(PolarisSDKContextManager polarisSDKContextManager) {
return new AssemblyServerPostHook(polarisSDKContextManager.getAssemblyAPI());
}
@Bean
public AssemblyServerPreHook assemblyServerPreHook(PolarisSDKContextManager polarisSDKContextManager) {
return new AssemblyServerPreHook(polarisSDKContextManager.getAssemblyAPI());
}
@Configuration(proxyBeanMethods = false) @Configuration(proxyBeanMethods = false)
@ConditionalOnWebApplication(type = ConditionalOnWebApplication.Type.SERVLET) @ConditionalOnWebApplication(type = ConditionalOnWebApplication.Type.SERVLET)
protected static class RpcEnhancementServletFilterConfig { protected static class RpcEnhancementServletFilterConfig {

@ -44,27 +44,5 @@ public class PluginOrderConstant {
* {@link com.tencent.cloud.polaris.circuitbreaker.reporter.ExceptionCircuitBreakerReporter}. * {@link com.tencent.cloud.polaris.circuitbreaker.reporter.ExceptionCircuitBreakerReporter}.
*/ */
public static final int CIRCUIT_BREAKER_REPORTER_PLUGIN_ORDER = Ordered.HIGHEST_PRECEDENCE + 2; public static final int CIRCUIT_BREAKER_REPORTER_PLUGIN_ORDER = Ordered.HIGHEST_PRECEDENCE + 2;
/**
* order for
* {@link com.tencent.cloud.rpc.enhancement.plugin.assembly.client.AssemblyClientPreHook}
* and
* {@link com.tencent.cloud.rpc.enhancement.plugin.assembly.client.AssemblyClientPostHook}
* and
* {@link com.tencent.cloud.rpc.enhancement.plugin.assembly.client.AssemblyClientExceptionHook}.
*/
public static final int ASSEMBLY_PLUGIN_ORDER = Ordered.HIGHEST_PRECEDENCE + 3;
}
public static class ServerPluginOrder {
/**
* order for
* {@link com.tencent.cloud.rpc.enhancement.plugin.assembly.server.AssemblyServerPreHook}
* and
* {@link com.tencent.cloud.rpc.enhancement.plugin.assembly.server.AssemblyServerPostHook}
* and
* {@link com.tencent.cloud.rpc.enhancement.plugin.assembly.server.AssemblyServerExceptionHook}.
*/
public static final int ASSEMBLY_PLUGIN_ORDER = Ordered.HIGHEST_PRECEDENCE + 1;
} }
} }

@ -1,56 +0,0 @@
/*
* Tencent is pleased to support the open source community by making Spring Cloud Tencent available.
*
* Copyright (C) 2019 THL A29 Limited, a Tencent company. All rights reserved.
*
* Licensed under the BSD 3-Clause License (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://opensource.org/licenses/BSD-3-Clause
*
* 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.tencent.cloud.rpc.enhancement.plugin.assembly;
import com.tencent.polaris.api.pojo.ServiceKey;
import com.tencent.polaris.api.rpc.MetadataProvider;
import org.springframework.cloud.client.ServiceInstance;
/**
* AssemblyMetadataProvider.
*
* @author sean yu
*/
public class AssemblyMetadataProvider implements MetadataProvider {
private final ServiceInstance serviceInstance;
private final String namespace;
public AssemblyMetadataProvider(ServiceInstance localServiceInstance, String namespace) {
this.serviceInstance = localServiceInstance;
this.namespace = namespace;
}
@Override
public String getMetadata(String key) {
return serviceInstance.getMetadata().get(key);
}
@Override
public ServiceKey getLocalService() {
return new ServiceKey(namespace, serviceInstance.getServiceId());
}
@Override
public String getLocalIp() {
return serviceInstance.getHost();
}
}

@ -1,126 +0,0 @@
/*
* Tencent is pleased to support the open source community by making Spring Cloud Tencent available.
*
* Copyright (C) 2019 THL A29 Limited, a Tencent company. All rights reserved.
*
* Licensed under the BSD 3-Clause License (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://opensource.org/licenses/BSD-3-Clause
*
* 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.tencent.cloud.rpc.enhancement.plugin.assembly;
import java.net.URI;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Optional;
import java.util.stream.Collectors;
import com.google.common.net.HttpHeaders;
import com.tencent.cloud.rpc.enhancement.plugin.EnhancedRequestContext;
import com.tencent.polaris.api.pojo.ServiceKey;
import com.tencent.polaris.api.rpc.RequestContext;
import org.springframework.http.HttpMethod;
/**
* AssemblyRequestContext.
*
* @author sean yu
*/
public class AssemblyRequestContext implements RequestContext {
private final EnhancedRequestContext requestContext;
private final ServiceKey callerService;
private final String callerIp;
private final Map<String, String> cookies;
public AssemblyRequestContext(EnhancedRequestContext requestContext, ServiceKey callerService, String callerIp) {
this.requestContext = requestContext;
this.callerService = callerService;
this.callerIp = callerIp;
this.cookies = new HashMap<>();
List<String> allCookies =
Optional.ofNullable(requestContext.getHttpHeaders().get(HttpHeaders.COOKIE))
.orElse(new ArrayList<>())
.stream()
.flatMap(it -> Arrays.stream(it.split(";")))
.collect(Collectors.toList());
allCookies.forEach(cookie -> {
String[] cookieKV = cookie.split("=");
if (cookieKV.length == 2) {
cookies.put(cookieKV[0], cookieKV[1]);
}
});
}
@Override
public String getMethod() {
return requestContext.getHttpMethod().name();
}
@Override
public void setMethod(String method) {
requestContext.setHttpMethod(HttpMethod.valueOf(method));
}
@Override
public String getHeader(String key) {
return requestContext.getHttpHeaders().getFirst(key);
}
@Override
public void setHeader(String key, String value) {
requestContext.getHttpHeaders().set(key, value);
}
@Override
public Collection<String> listHeaderKeys() {
return requestContext.getHttpHeaders().keySet();
}
@Override
public String getCookie(String key) {
return this.cookies.get(key);
}
@Override
public void setCookie(String key, String value) {
this.cookies.put(key, value);
}
@Override
public Collection<String> listCookieKeys() {
return this.cookies.keySet();
}
@Override
public String getCallerIp() {
return callerIp;
}
@Override
public ServiceKey getCallerService() {
return callerService;
}
@Override
public URI getURI() {
return requestContext.getUrl();
}
}

@ -1,87 +0,0 @@
/*
* Tencent is pleased to support the open source community by making Spring Cloud Tencent available.
*
* Copyright (C) 2019 THL A29 Limited, a Tencent company. All rights reserved.
*
* Licensed under the BSD 3-Clause License (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://opensource.org/licenses/BSD-3-Clause
*
* 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.tencent.cloud.rpc.enhancement.plugin.assembly;
import java.util.Collection;
import com.tencent.cloud.rpc.enhancement.plugin.EnhancedResponseContext;
import com.tencent.cloud.rpc.enhancement.plugin.PolarisEnhancedPluginUtils;
import com.tencent.polaris.api.pojo.RetStatus;
import com.tencent.polaris.api.rpc.ResponseContext;
import org.springframework.lang.Nullable;
/**
* AssemblyResponseContext.
*
* @author sean yu
*/
public class AssemblyResponseContext implements ResponseContext {
private final EnhancedResponseContext responseContext;
private final Throwable throwable;
private final RetStatus retStatus;
public AssemblyResponseContext(@Nullable EnhancedResponseContext responseContext, @Nullable Throwable throwable) {
this.responseContext = responseContext;
this.throwable = throwable;
if (responseContext == null) {
this.retStatus = PolarisEnhancedPluginUtils.getRetStatusFromRequest(null, null, throwable);
}
else {
this.retStatus = PolarisEnhancedPluginUtils.getRetStatusFromRequest(responseContext.getHttpHeaders(), responseContext.getHttpStatus(), throwable);
}
}
@Override
public Object getRetCode() {
if (responseContext == null) {
return null;
}
return this.responseContext.getHttpStatus();
}
@Override
public String getHeader(String key) {
if (responseContext == null) {
return null;
}
return this.responseContext.getHttpHeaders().getFirst(key);
}
@Override
public Collection<String> listHeaders() {
if (responseContext == null) {
return null;
}
return this.responseContext.getHttpHeaders().keySet();
}
@Override
public Throwable getThrowable() {
return this.throwable;
}
@Override
public RetStatus getRetStatus() {
return this.retStatus;
}
}

@ -1,82 +0,0 @@
/*
* Tencent is pleased to support the open source community by making Spring Cloud Tencent available.
*
* Copyright (C) 2019 THL A29 Limited, a Tencent company. All rights reserved.
*
* Licensed under the BSD 3-Clause License (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://opensource.org/licenses/BSD-3-Clause
*
* 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.tencent.cloud.rpc.enhancement.plugin.assembly.client;
import com.tencent.cloud.common.metadata.MetadataContext;
import com.tencent.cloud.rpc.enhancement.plugin.EnhancedPlugin;
import com.tencent.cloud.rpc.enhancement.plugin.EnhancedPluginContext;
import com.tencent.cloud.rpc.enhancement.plugin.EnhancedPluginType;
import com.tencent.cloud.rpc.enhancement.plugin.PolarisEnhancedPluginUtils;
import com.tencent.cloud.rpc.enhancement.plugin.assembly.AssemblyMetadataProvider;
import com.tencent.cloud.rpc.enhancement.plugin.assembly.AssemblyRequestContext;
import com.tencent.cloud.rpc.enhancement.plugin.assembly.AssemblyResponseContext;
import com.tencent.cloud.rpc.enhancement.transformer.InstanceTransformer;
import com.tencent.polaris.api.pojo.ServiceKey;
import com.tencent.polaris.assembly.api.AssemblyAPI;
import com.tencent.polaris.assembly.api.pojo.AfterRequest;
import com.tencent.polaris.assembly.api.pojo.Capability;
import static com.tencent.cloud.rpc.enhancement.plugin.PluginOrderConstant.ClientPluginOrder.ASSEMBLY_PLUGIN_ORDER;
/**
* AssemblyClientExceptionHook.
*
* @author sean yu
*/
public class AssemblyClientExceptionHook implements EnhancedPlugin {
private final AssemblyAPI assemblyAPI;
private final InstanceTransformer instanceTransformer;
public AssemblyClientExceptionHook(AssemblyAPI assemblyAPI, InstanceTransformer instanceTransformer) {
this.assemblyAPI = assemblyAPI;
this.instanceTransformer = instanceTransformer;
}
@Override
public EnhancedPluginType getType() {
return EnhancedPluginType.Client.EXCEPTION;
}
@Override
public void run(EnhancedPluginContext context) {
AfterRequest afterRequest = new AfterRequest();
afterRequest.setCapabilities(new Capability[]{Capability.ALL});
afterRequest.setRequestContext(new AssemblyRequestContext(
context.getRequest(),
new ServiceKey(MetadataContext.LOCAL_NAMESPACE, context.getLocalServiceInstance().getServiceId()),
context.getLocalServiceInstance().getHost()
));
afterRequest.setResponseContext(new AssemblyResponseContext(null, context.getThrowable()));
afterRequest.setMetadataProvider(new AssemblyMetadataProvider(context.getLocalServiceInstance(), MetadataContext.LOCAL_NAMESPACE));
afterRequest.setDelay(context.getDelay());
afterRequest.setRouteLabels(PolarisEnhancedPluginUtils.getLabelMap(context.getRequest().getHttpHeaders()));
// TargetService and TargetInstance only exist in client side
afterRequest.setTargetService(new ServiceKey(MetadataContext.LOCAL_NAMESPACE, context.getTargetServiceInstance().getServiceId()));
afterRequest.setTargetInstance(instanceTransformer.transform(context.getTargetServiceInstance()));
assemblyAPI.afterCallService(afterRequest);
}
@Override
public int getOrder() {
return ASSEMBLY_PLUGIN_ORDER;
}
}

@ -1,83 +0,0 @@
/*
* Tencent is pleased to support the open source community by making Spring Cloud Tencent available.
*
* Copyright (C) 2019 THL A29 Limited, a Tencent company. All rights reserved.
*
* Licensed under the BSD 3-Clause License (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://opensource.org/licenses/BSD-3-Clause
*
* 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.tencent.cloud.rpc.enhancement.plugin.assembly.client;
import com.tencent.cloud.common.metadata.MetadataContext;
import com.tencent.cloud.rpc.enhancement.plugin.EnhancedPlugin;
import com.tencent.cloud.rpc.enhancement.plugin.EnhancedPluginContext;
import com.tencent.cloud.rpc.enhancement.plugin.EnhancedPluginType;
import com.tencent.cloud.rpc.enhancement.plugin.PolarisEnhancedPluginUtils;
import com.tencent.cloud.rpc.enhancement.plugin.assembly.AssemblyMetadataProvider;
import com.tencent.cloud.rpc.enhancement.plugin.assembly.AssemblyRequestContext;
import com.tencent.cloud.rpc.enhancement.plugin.assembly.AssemblyResponseContext;
import com.tencent.cloud.rpc.enhancement.transformer.InstanceTransformer;
import com.tencent.polaris.api.pojo.ServiceKey;
import com.tencent.polaris.assembly.api.AssemblyAPI;
import com.tencent.polaris.assembly.api.pojo.AfterRequest;
import com.tencent.polaris.assembly.api.pojo.Capability;
import static com.tencent.cloud.rpc.enhancement.plugin.PluginOrderConstant.ClientPluginOrder.ASSEMBLY_PLUGIN_ORDER;
/**
* AssemblyClientPostHook.
*
* @author sean yu
*/
public class AssemblyClientPostHook implements EnhancedPlugin {
private final AssemblyAPI assemblyAPI;
private final InstanceTransformer instanceTransformer;
public AssemblyClientPostHook(AssemblyAPI assemblyAPI, InstanceTransformer instanceTransformer) {
this.assemblyAPI = assemblyAPI;
this.instanceTransformer = instanceTransformer;
}
@Override
public EnhancedPluginType getType() {
return EnhancedPluginType.Client.POST;
}
@Override
public void run(EnhancedPluginContext context) {
AfterRequest afterRequest = new AfterRequest();
afterRequest.setCapabilities(new Capability[]{Capability.ALL});
afterRequest.setRequestContext(new AssemblyRequestContext(
context.getRequest(),
new ServiceKey(MetadataContext.LOCAL_NAMESPACE, context.getLocalServiceInstance().getServiceId()),
context.getLocalServiceInstance().getHost()
));
afterRequest.setResponseContext(new AssemblyResponseContext(context.getResponse(), null));
afterRequest.setMetadataProvider(new AssemblyMetadataProvider(context.getLocalServiceInstance(), MetadataContext.LOCAL_NAMESPACE));
afterRequest.setDelay(context.getDelay());
afterRequest.setRouteLabels(PolarisEnhancedPluginUtils.getLabelMap(context.getRequest().getHttpHeaders()));
// TargetService and TargetInstance only exist in client side
afterRequest.setTargetService(new ServiceKey(MetadataContext.LOCAL_NAMESPACE, context.getTargetServiceInstance().getServiceId()));
afterRequest.setTargetInstance(instanceTransformer.transform(context.getTargetServiceInstance()));
assemblyAPI.afterCallService(afterRequest);
}
@Override
public int getOrder() {
return ASSEMBLY_PLUGIN_ORDER;
}
}

@ -1,73 +0,0 @@
/*
* Tencent is pleased to support the open source community by making Spring Cloud Tencent available.
*
* Copyright (C) 2019 THL A29 Limited, a Tencent company. All rights reserved.
*
* Licensed under the BSD 3-Clause License (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://opensource.org/licenses/BSD-3-Clause
*
* 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.tencent.cloud.rpc.enhancement.plugin.assembly.client;
import com.tencent.cloud.common.metadata.MetadataContext;
import com.tencent.cloud.rpc.enhancement.plugin.EnhancedPlugin;
import com.tencent.cloud.rpc.enhancement.plugin.EnhancedPluginContext;
import com.tencent.cloud.rpc.enhancement.plugin.EnhancedPluginType;
import com.tencent.cloud.rpc.enhancement.plugin.assembly.AssemblyMetadataProvider;
import com.tencent.cloud.rpc.enhancement.plugin.assembly.AssemblyRequestContext;
import com.tencent.polaris.api.pojo.ServiceKey;
import com.tencent.polaris.assembly.api.AssemblyAPI;
import com.tencent.polaris.assembly.api.pojo.BeforeRequest;
import com.tencent.polaris.assembly.api.pojo.Capability;
import static com.tencent.cloud.rpc.enhancement.plugin.PluginOrderConstant.ClientPluginOrder.ASSEMBLY_PLUGIN_ORDER;
/**
* AssemblyClientPreHook.
*
* @author sean yu
*/
public class AssemblyClientPreHook implements EnhancedPlugin {
private final AssemblyAPI assemblyAPI;
public AssemblyClientPreHook(AssemblyAPI assemblyAPI) {
this.assemblyAPI = assemblyAPI;
}
@Override
public EnhancedPluginType getType() {
return EnhancedPluginType.Client.PRE;
}
@Override
public void run(EnhancedPluginContext context) {
BeforeRequest beforeRequest = new BeforeRequest();
beforeRequest.setCapabilities(new Capability[]{Capability.ALL});
beforeRequest.setRequestContext(new AssemblyRequestContext(
context.getRequest(),
new ServiceKey(MetadataContext.LOCAL_NAMESPACE, context.getLocalServiceInstance().getServiceId()),
context.getLocalServiceInstance().getHost()
));
beforeRequest.setMetadataProvider(new AssemblyMetadataProvider(context.getLocalServiceInstance(), MetadataContext.LOCAL_NAMESPACE));
// TargetService only exist in client side
beforeRequest.setTargetService(new ServiceKey(MetadataContext.LOCAL_NAMESPACE, context.getTargetServiceInstance().getServiceId()));
assemblyAPI.beforeCallService(beforeRequest);
}
@Override
public int getOrder() {
return ASSEMBLY_PLUGIN_ORDER;
}
}

@ -1,76 +0,0 @@
/*
* Tencent is pleased to support the open source community by making Spring Cloud Tencent available.
*
* Copyright (C) 2019 THL A29 Limited, a Tencent company. All rights reserved.
*
* Licensed under the BSD 3-Clause License (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://opensource.org/licenses/BSD-3-Clause
*
* 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.tencent.cloud.rpc.enhancement.plugin.assembly.server;
import com.tencent.cloud.common.metadata.MetadataContext;
import com.tencent.cloud.rpc.enhancement.plugin.EnhancedPlugin;
import com.tencent.cloud.rpc.enhancement.plugin.EnhancedPluginContext;
import com.tencent.cloud.rpc.enhancement.plugin.EnhancedPluginType;
import com.tencent.cloud.rpc.enhancement.plugin.PolarisEnhancedPluginUtils;
import com.tencent.cloud.rpc.enhancement.plugin.assembly.AssemblyMetadataProvider;
import com.tencent.cloud.rpc.enhancement.plugin.assembly.AssemblyRequestContext;
import com.tencent.cloud.rpc.enhancement.plugin.assembly.AssemblyResponseContext;
import com.tencent.polaris.api.pojo.ServiceKey;
import com.tencent.polaris.assembly.api.AssemblyAPI;
import com.tencent.polaris.assembly.api.pojo.AfterRequest;
import com.tencent.polaris.assembly.api.pojo.Capability;
import static com.tencent.cloud.rpc.enhancement.plugin.PluginOrderConstant.ServerPluginOrder.ASSEMBLY_PLUGIN_ORDER;
/**
* AssemblyServerExceptionHook.
*
* @author sean yu
*/
public class AssemblyServerExceptionHook implements EnhancedPlugin {
private final AssemblyAPI assemblyAPI;
public AssemblyServerExceptionHook(AssemblyAPI assemblyAPI) {
this.assemblyAPI = assemblyAPI;
}
@Override
public EnhancedPluginType getType() {
return EnhancedPluginType.Server.EXCEPTION;
}
@Override
public void run(EnhancedPluginContext context) {
AfterRequest afterRequest = new AfterRequest();
afterRequest.setCapabilities(new Capability[]{Capability.ALL});
afterRequest.setRequestContext(new AssemblyRequestContext(
context.getRequest(),
new ServiceKey(MetadataContext.LOCAL_NAMESPACE, context.getLocalServiceInstance().getServiceId()),
context.getLocalServiceInstance().getHost()
));
afterRequest.setResponseContext(new AssemblyResponseContext(null, context.getThrowable()));
afterRequest.setMetadataProvider(new AssemblyMetadataProvider(context.getLocalServiceInstance(), MetadataContext.LOCAL_NAMESPACE));
afterRequest.setDelay(context.getDelay());
afterRequest.setRouteLabels(PolarisEnhancedPluginUtils.getLabelMap(context.getRequest().getHttpHeaders()));
assemblyAPI.afterProcess(afterRequest);
}
@Override
public int getOrder() {
return ASSEMBLY_PLUGIN_ORDER;
}
}

@ -1,75 +0,0 @@
/*
* Tencent is pleased to support the open source community by making Spring Cloud Tencent available.
*
* Copyright (C) 2019 THL A29 Limited, a Tencent company. All rights reserved.
*
* Licensed under the BSD 3-Clause License (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://opensource.org/licenses/BSD-3-Clause
*
* 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.tencent.cloud.rpc.enhancement.plugin.assembly.server;
import com.tencent.cloud.common.metadata.MetadataContext;
import com.tencent.cloud.rpc.enhancement.plugin.EnhancedPlugin;
import com.tencent.cloud.rpc.enhancement.plugin.EnhancedPluginContext;
import com.tencent.cloud.rpc.enhancement.plugin.EnhancedPluginType;
import com.tencent.cloud.rpc.enhancement.plugin.PolarisEnhancedPluginUtils;
import com.tencent.cloud.rpc.enhancement.plugin.assembly.AssemblyMetadataProvider;
import com.tencent.cloud.rpc.enhancement.plugin.assembly.AssemblyRequestContext;
import com.tencent.cloud.rpc.enhancement.plugin.assembly.AssemblyResponseContext;
import com.tencent.polaris.api.pojo.ServiceKey;
import com.tencent.polaris.assembly.api.AssemblyAPI;
import com.tencent.polaris.assembly.api.pojo.AfterRequest;
import com.tencent.polaris.assembly.api.pojo.Capability;
import static com.tencent.cloud.rpc.enhancement.plugin.PluginOrderConstant.ServerPluginOrder.ASSEMBLY_PLUGIN_ORDER;
/**
* AssemblyServerPostHook.
*
* @author sean yu
*/
public class AssemblyServerPostHook implements EnhancedPlugin {
private final AssemblyAPI assemblyAPI;
public AssemblyServerPostHook(AssemblyAPI assemblyAPI) {
this.assemblyAPI = assemblyAPI;
}
@Override
public EnhancedPluginType getType() {
return EnhancedPluginType.Server.POST;
}
@Override
public void run(EnhancedPluginContext context) {
AfterRequest afterRequest = new AfterRequest();
afterRequest.setCapabilities(new Capability[]{Capability.ALL});
afterRequest.setRequestContext(new AssemblyRequestContext(
context.getRequest(),
new ServiceKey(MetadataContext.LOCAL_NAMESPACE, context.getLocalServiceInstance().getServiceId()),
context.getLocalServiceInstance().getHost()
));
afterRequest.setResponseContext(new AssemblyResponseContext(context.getResponse(), null));
afterRequest.setMetadataProvider(new AssemblyMetadataProvider(context.getLocalServiceInstance(), MetadataContext.LOCAL_NAMESPACE));
afterRequest.setDelay(context.getDelay());
afterRequest.setRouteLabels(PolarisEnhancedPluginUtils.getLabelMap(context.getRequest().getHttpHeaders()));
assemblyAPI.afterProcess(afterRequest);
}
@Override
public int getOrder() {
return ASSEMBLY_PLUGIN_ORDER;
}
}

@ -1,70 +0,0 @@
/*
* Tencent is pleased to support the open source community by making Spring Cloud Tencent available.
*
* Copyright (C) 2019 THL A29 Limited, a Tencent company. All rights reserved.
*
* Licensed under the BSD 3-Clause License (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://opensource.org/licenses/BSD-3-Clause
*
* 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.tencent.cloud.rpc.enhancement.plugin.assembly.server;
import com.tencent.cloud.common.metadata.MetadataContext;
import com.tencent.cloud.rpc.enhancement.plugin.EnhancedPlugin;
import com.tencent.cloud.rpc.enhancement.plugin.EnhancedPluginContext;
import com.tencent.cloud.rpc.enhancement.plugin.EnhancedPluginType;
import com.tencent.cloud.rpc.enhancement.plugin.assembly.AssemblyMetadataProvider;
import com.tencent.cloud.rpc.enhancement.plugin.assembly.AssemblyRequestContext;
import com.tencent.polaris.api.pojo.ServiceKey;
import com.tencent.polaris.assembly.api.AssemblyAPI;
import com.tencent.polaris.assembly.api.pojo.BeforeRequest;
import com.tencent.polaris.assembly.api.pojo.Capability;
import static com.tencent.cloud.rpc.enhancement.plugin.PluginOrderConstant.ServerPluginOrder.ASSEMBLY_PLUGIN_ORDER;
/**
* AssemblyServerPreHook.
*
* @author sean yu
*/
public class AssemblyServerPreHook implements EnhancedPlugin {
private final AssemblyAPI assemblyAPI;
public AssemblyServerPreHook(AssemblyAPI assemblyAPI) {
this.assemblyAPI = assemblyAPI;
}
@Override
public EnhancedPluginType getType() {
return EnhancedPluginType.Server.PRE;
}
@Override
public void run(EnhancedPluginContext context) {
BeforeRequest beforeRequest = new BeforeRequest();
beforeRequest.setCapabilities(new Capability[]{Capability.ALL});
beforeRequest.setRequestContext(new AssemblyRequestContext(
context.getRequest(),
new ServiceKey(MetadataContext.LOCAL_NAMESPACE, context.getLocalServiceInstance().getServiceId()),
context.getLocalServiceInstance().getHost()
));
beforeRequest.setMetadataProvider(new AssemblyMetadataProvider(context.getLocalServiceInstance(), MetadataContext.LOCAL_NAMESPACE));
assemblyAPI.beforeProcess(beforeRequest);
}
@Override
public int getOrder() {
return ASSEMBLY_PLUGIN_ORDER;
}
}

@ -1,146 +0,0 @@
/*
* Tencent is pleased to support the open source community by making Spring Cloud Tencent available.
*
* Copyright (C) 2019 THL A29 Limited, a Tencent company. All rights reserved.
*
* Licensed under the BSD 3-Clause License (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://opensource.org/licenses/BSD-3-Clause
*
* 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.tencent.cloud.rpc.enhancement.plugin;
import java.net.URI;
import com.tencent.cloud.common.metadata.MetadataContext;
import com.tencent.cloud.common.util.ApplicationContextAwareUtils;
import com.tencent.cloud.rpc.enhancement.config.RpcEnhancementReporterProperties;
import com.tencent.cloud.rpc.enhancement.plugin.assembly.client.AssemblyClientExceptionHook;
import com.tencent.cloud.rpc.enhancement.transformer.InstanceTransformer;
import com.tencent.polaris.assembly.api.AssemblyAPI;
import org.junit.jupiter.api.AfterAll;
import org.junit.jupiter.api.BeforeAll;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;
import org.mockito.InjectMocks;
import org.mockito.Mock;
import org.mockito.MockedStatic;
import org.mockito.Mockito;
import org.mockito.junit.jupiter.MockitoExtension;
import org.springframework.cloud.client.DefaultServiceInstance;
import org.springframework.context.ApplicationContext;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpMethod;
import static com.tencent.polaris.test.common.Consts.NAMESPACE_TEST;
import static com.tencent.polaris.test.common.Consts.SERVICE_PROVIDER;
import static org.assertj.core.api.Assertions.assertThat;
import static org.mockito.ArgumentMatchers.anyString;
import static org.mockito.Mockito.doReturn;
import static org.mockito.Mockito.mock;
/**
* AssemblyClientExceptionHookTest.
*
* @author sean yu
*/
@ExtendWith(MockitoExtension.class)
public class AssemblyClientExceptionHookTest {
private static MockedStatic<ApplicationContextAwareUtils> mockedApplicationContextAwareUtils;
@InjectMocks
private AssemblyClientExceptionHook assemblyClientExceptionHook;
@Mock
private AssemblyAPI assemblyAPI;
@Mock
private InstanceTransformer instanceTransformer;
@BeforeAll
static void beforeAll() {
mockedApplicationContextAwareUtils = Mockito.mockStatic(ApplicationContextAwareUtils.class);
mockedApplicationContextAwareUtils.when(() -> ApplicationContextAwareUtils.getProperties(anyString()))
.thenReturn("unit-test");
ApplicationContext applicationContext = mock(ApplicationContext.class);
RpcEnhancementReporterProperties reporterProperties = mock(RpcEnhancementReporterProperties.class);
doReturn(reporterProperties)
.when(applicationContext).getBean(RpcEnhancementReporterProperties.class);
mockedApplicationContextAwareUtils.when(ApplicationContextAwareUtils::getApplicationContext)
.thenReturn(applicationContext);
}
@AfterAll
static void afterAll() {
mockedApplicationContextAwareUtils.close();
}
@BeforeEach
void setUp() {
MetadataContext.LOCAL_NAMESPACE = NAMESPACE_TEST;
MetadataContext.LOCAL_SERVICE = SERVICE_PROVIDER;
}
@Test
public void testGetName() {
assertThat(assemblyClientExceptionHook.getName()).isEqualTo(AssemblyClientExceptionHook.class.getName());
}
@Test
public void testType() {
assertThat(assemblyClientExceptionHook.getType()).isEqualTo(EnhancedPluginType.Client.EXCEPTION);
}
@Test
public void testRun() {
EnhancedPluginContext pluginContext = new EnhancedPluginContext();
EnhancedRequestContext request = EnhancedRequestContext.builder()
.httpMethod(HttpMethod.GET)
.url(URI.create("http://0.0.0.0/"))
.httpHeaders(new HttpHeaders())
.build();
request.toString();
EnhancedResponseContext response = EnhancedResponseContext.builder()
.httpStatus(200)
.build();
response.toString();
DefaultServiceInstance targetServiceInstance = new DefaultServiceInstance();
targetServiceInstance.setServiceId(SERVICE_PROVIDER);
DefaultServiceInstance localServiceInstance = new DefaultServiceInstance();
localServiceInstance.setServiceId(SERVICE_PROVIDER);
pluginContext.setRequest(request);
pluginContext.setResponse(response);
pluginContext.setTargetServiceInstance(targetServiceInstance, null);
pluginContext.setLocalServiceInstance(localServiceInstance);
pluginContext.setThrowable(new RuntimeException());
assemblyClientExceptionHook.run(pluginContext);
assemblyClientExceptionHook.getOrder();
assemblyClientExceptionHook.getName();
assemblyClientExceptionHook.getType();
}
@Test
public void testHandlerThrowable() {
// mock request
EnhancedRequestContext request = mock(EnhancedRequestContext.class);
// mock response
EnhancedResponseContext response = mock(EnhancedResponseContext.class);
EnhancedPluginContext context = new EnhancedPluginContext();
context.setRequest(request);
context.setResponse(response);
assemblyClientExceptionHook.handlerThrowable(context, new RuntimeException("Mock exception."));
}
}

@ -1,146 +0,0 @@
/*
* Tencent is pleased to support the open source community by making Spring Cloud Tencent available.
*
* Copyright (C) 2019 THL A29 Limited, a Tencent company. All rights reserved.
*
* Licensed under the BSD 3-Clause License (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://opensource.org/licenses/BSD-3-Clause
*
* 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.tencent.cloud.rpc.enhancement.plugin;
import java.net.URI;
import com.tencent.cloud.common.metadata.MetadataContext;
import com.tencent.cloud.common.util.ApplicationContextAwareUtils;
import com.tencent.cloud.rpc.enhancement.config.RpcEnhancementReporterProperties;
import com.tencent.cloud.rpc.enhancement.plugin.assembly.client.AssemblyClientPostHook;
import com.tencent.cloud.rpc.enhancement.transformer.InstanceTransformer;
import com.tencent.polaris.assembly.api.AssemblyAPI;
import org.junit.jupiter.api.AfterAll;
import org.junit.jupiter.api.BeforeAll;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;
import org.mockito.InjectMocks;
import org.mockito.Mock;
import org.mockito.MockedStatic;
import org.mockito.Mockito;
import org.mockito.junit.jupiter.MockitoExtension;
import org.springframework.cloud.client.DefaultServiceInstance;
import org.springframework.context.ApplicationContext;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpMethod;
import static com.tencent.polaris.test.common.Consts.NAMESPACE_TEST;
import static com.tencent.polaris.test.common.Consts.SERVICE_PROVIDER;
import static org.assertj.core.api.Assertions.assertThat;
import static org.mockito.ArgumentMatchers.anyString;
import static org.mockito.Mockito.doReturn;
import static org.mockito.Mockito.mock;
/**
* AssemblyClientPostHookTest.
*
* @author sean yu
*/
@ExtendWith(MockitoExtension.class)
public class AssemblyClientPostHookTest {
private static MockedStatic<ApplicationContextAwareUtils> mockedApplicationContextAwareUtils;
@InjectMocks
private AssemblyClientPostHook assemblyClientPostHook;
@Mock
private AssemblyAPI assemblyAPI;
@Mock
private InstanceTransformer instanceTransformer;
@BeforeAll
static void beforeAll() {
mockedApplicationContextAwareUtils = Mockito.mockStatic(ApplicationContextAwareUtils.class);
mockedApplicationContextAwareUtils.when(() -> ApplicationContextAwareUtils.getProperties(anyString()))
.thenReturn("unit-test");
ApplicationContext applicationContext = mock(ApplicationContext.class);
RpcEnhancementReporterProperties reporterProperties = mock(RpcEnhancementReporterProperties.class);
doReturn(reporterProperties)
.when(applicationContext).getBean(RpcEnhancementReporterProperties.class);
mockedApplicationContextAwareUtils.when(ApplicationContextAwareUtils::getApplicationContext)
.thenReturn(applicationContext);
}
@AfterAll
static void afterAll() {
mockedApplicationContextAwareUtils.close();
}
@BeforeEach
void setUp() {
MetadataContext.LOCAL_NAMESPACE = NAMESPACE_TEST;
MetadataContext.LOCAL_SERVICE = SERVICE_PROVIDER;
}
@Test
public void testGetName() {
assertThat(assemblyClientPostHook.getName()).isEqualTo(AssemblyClientPostHook.class.getName());
}
@Test
public void testType() {
assertThat(assemblyClientPostHook.getType()).isEqualTo(EnhancedPluginType.Client.POST);
}
@Test
public void testRun() {
EnhancedPluginContext pluginContext = new EnhancedPluginContext();
EnhancedRequestContext request = EnhancedRequestContext.builder()
.httpMethod(HttpMethod.GET)
.url(URI.create("http://0.0.0.0/"))
.httpHeaders(new HttpHeaders())
.build();
request.toString();
EnhancedResponseContext response = EnhancedResponseContext.builder()
.httpStatus(200)
.build();
response.toString();
DefaultServiceInstance targetServiceInstance = new DefaultServiceInstance();
targetServiceInstance.setServiceId(SERVICE_PROVIDER);
DefaultServiceInstance localServiceInstance = new DefaultServiceInstance();
localServiceInstance.setServiceId(SERVICE_PROVIDER);
pluginContext.setRequest(request);
pluginContext.setResponse(response);
pluginContext.setTargetServiceInstance(targetServiceInstance, null);
pluginContext.setLocalServiceInstance(localServiceInstance);
pluginContext.setThrowable(new RuntimeException());
assemblyClientPostHook.run(pluginContext);
assemblyClientPostHook.getOrder();
assemblyClientPostHook.getName();
assemblyClientPostHook.getType();
}
@Test
public void testHandlerThrowable() {
// mock request
EnhancedRequestContext request = mock(EnhancedRequestContext.class);
// mock response
EnhancedResponseContext response = mock(EnhancedResponseContext.class);
EnhancedPluginContext context = new EnhancedPluginContext();
context.setRequest(request);
context.setResponse(response);
assemblyClientPostHook.handlerThrowable(context, new RuntimeException("Mock exception."));
}
}

@ -1,143 +0,0 @@
/*
* Tencent is pleased to support the open source community by making Spring Cloud Tencent available.
*
* Copyright (C) 2019 THL A29 Limited, a Tencent company. All rights reserved.
*
* Licensed under the BSD 3-Clause License (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://opensource.org/licenses/BSD-3-Clause
*
* 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.tencent.cloud.rpc.enhancement.plugin;
import java.net.URI;
import com.tencent.cloud.common.metadata.MetadataContext;
import com.tencent.cloud.common.util.ApplicationContextAwareUtils;
import com.tencent.cloud.rpc.enhancement.config.RpcEnhancementReporterProperties;
import com.tencent.cloud.rpc.enhancement.plugin.assembly.client.AssemblyClientPreHook;
import com.tencent.polaris.assembly.api.AssemblyAPI;
import org.junit.jupiter.api.AfterAll;
import org.junit.jupiter.api.BeforeAll;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;
import org.mockito.InjectMocks;
import org.mockito.Mock;
import org.mockito.MockedStatic;
import org.mockito.Mockito;
import org.mockito.junit.jupiter.MockitoExtension;
import org.springframework.cloud.client.DefaultServiceInstance;
import org.springframework.context.ApplicationContext;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpMethod;
import static com.tencent.polaris.test.common.Consts.NAMESPACE_TEST;
import static com.tencent.polaris.test.common.Consts.SERVICE_PROVIDER;
import static org.assertj.core.api.Assertions.assertThat;
import static org.mockito.ArgumentMatchers.anyString;
import static org.mockito.Mockito.doReturn;
import static org.mockito.Mockito.mock;
/**
* AssemblyClientPreHookTest.
*
* @author sean yu
*/
@ExtendWith(MockitoExtension.class)
public class AssemblyClientPreHookTest {
private static MockedStatic<ApplicationContextAwareUtils> mockedApplicationContextAwareUtils;
@InjectMocks
private AssemblyClientPreHook assemblyClientPreHook;
@Mock
private AssemblyAPI assemblyAPI;
@BeforeAll
static void beforeAll() {
mockedApplicationContextAwareUtils = Mockito.mockStatic(ApplicationContextAwareUtils.class);
mockedApplicationContextAwareUtils.when(() -> ApplicationContextAwareUtils.getProperties(anyString()))
.thenReturn("unit-test");
ApplicationContext applicationContext = mock(ApplicationContext.class);
RpcEnhancementReporterProperties reporterProperties = mock(RpcEnhancementReporterProperties.class);
doReturn(reporterProperties)
.when(applicationContext).getBean(RpcEnhancementReporterProperties.class);
mockedApplicationContextAwareUtils.when(ApplicationContextAwareUtils::getApplicationContext)
.thenReturn(applicationContext);
}
@AfterAll
static void afterAll() {
mockedApplicationContextAwareUtils.close();
}
@BeforeEach
void setUp() {
MetadataContext.LOCAL_NAMESPACE = NAMESPACE_TEST;
MetadataContext.LOCAL_SERVICE = SERVICE_PROVIDER;
}
@Test
public void testGetName() {
assertThat(assemblyClientPreHook.getName()).isEqualTo(AssemblyClientPreHook.class.getName());
}
@Test
public void testType() {
assertThat(assemblyClientPreHook.getType()).isEqualTo(EnhancedPluginType.Client.PRE);
}
@Test
public void testRun() {
EnhancedPluginContext pluginContext = new EnhancedPluginContext();
EnhancedRequestContext request = EnhancedRequestContext.builder()
.httpMethod(HttpMethod.GET)
.url(URI.create("http://0.0.0.0/"))
.httpHeaders(new HttpHeaders())
.build();
request.toString();
EnhancedResponseContext response = EnhancedResponseContext.builder()
.httpStatus(200)
.build();
response.toString();
DefaultServiceInstance targetServiceInstance = new DefaultServiceInstance();
targetServiceInstance.setServiceId(SERVICE_PROVIDER);
DefaultServiceInstance localServiceInstance = new DefaultServiceInstance();
localServiceInstance.setServiceId(SERVICE_PROVIDER);
pluginContext.setRequest(request);
pluginContext.setResponse(response);
pluginContext.setTargetServiceInstance(targetServiceInstance, null);
pluginContext.setLocalServiceInstance(localServiceInstance);
pluginContext.setThrowable(new RuntimeException());
assemblyClientPreHook.run(pluginContext);
assemblyClientPreHook.getOrder();
assemblyClientPreHook.getName();
assemblyClientPreHook.getType();
}
@Test
public void testHandlerThrowable() {
// mock request
EnhancedRequestContext request = mock(EnhancedRequestContext.class);
// mock response
EnhancedResponseContext response = mock(EnhancedResponseContext.class);
EnhancedPluginContext context = new EnhancedPluginContext();
context.setRequest(request);
context.setResponse(response);
assemblyClientPreHook.handlerThrowable(context, new RuntimeException("Mock exception."));
}
}

@ -1,57 +0,0 @@
/*
* Tencent is pleased to support the open source community by making Spring Cloud Tencent available.
*
* Copyright (C) 2019 THL A29 Limited, a Tencent company. All rights reserved.
*
* Licensed under the BSD 3-Clause License (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://opensource.org/licenses/BSD-3-Clause
*
* 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.tencent.cloud.rpc.enhancement.plugin;
import java.util.HashMap;
import java.util.Map;
import com.tencent.cloud.rpc.enhancement.plugin.assembly.AssemblyMetadataProvider;
import com.tencent.polaris.api.pojo.ServiceKey;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;
import org.mockito.Mockito;
import org.mockito.junit.jupiter.MockitoExtension;
import org.springframework.cloud.client.ServiceInstance;
import static org.assertj.core.api.Assertions.assertThat;
import static org.mockito.Mockito.doReturn;
/**
* AssemblyMetadataProviderTest.
*
* @author sean yu
*/
@ExtendWith(MockitoExtension.class)
public class AssemblyMetadataProviderTest {
@Test
public void testAssemblyMetadataProvider() {
ServiceInstance serviceInstance = Mockito.mock(ServiceInstance.class);
Map<String, String> metadata = new HashMap<String, String>() {{
put("k", "v");
}};
doReturn(metadata).when(serviceInstance).getMetadata();
doReturn("0.0.0.0").when(serviceInstance).getHost();
doReturn("test").when(serviceInstance).getServiceId();
AssemblyMetadataProvider assemblyMetadataProvider = new AssemblyMetadataProvider(serviceInstance, "test");
assertThat(assemblyMetadataProvider.getMetadata("k")).isEqualTo("v");
assertThat(assemblyMetadataProvider.getLocalIp()).isEqualTo("0.0.0.0");
assertThat(assemblyMetadataProvider.getLocalService()).isEqualTo(new ServiceKey("test", "test"));
}
}

@ -1,83 +0,0 @@
/*
* Tencent is pleased to support the open source community by making Spring Cloud Tencent available.
*
* Copyright (C) 2019 THL A29 Limited, a Tencent company. All rights reserved.
*
* Licensed under the BSD 3-Clause License (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://opensource.org/licenses/BSD-3-Clause
*
* 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.tencent.cloud.rpc.enhancement.plugin;
import java.net.URI;
import java.util.Arrays;
import java.util.HashSet;
import com.tencent.cloud.rpc.enhancement.plugin.assembly.AssemblyRequestContext;
import com.tencent.polaris.api.pojo.ServiceKey;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;
import org.mockito.junit.jupiter.MockitoExtension;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpMethod;
import static org.assertj.core.api.Assertions.assertThat;
/**
* AssemblyRequestContextTest.
*
* @author sean yu
*/
@ExtendWith(MockitoExtension.class)
public class AssemblyRequestContextTest {
@Test
public void testAssemblyRequestContext() {
URI uri = URI.create("http://0.0.0.0/");
HttpHeaders httpHeaders = new HttpHeaders();
httpHeaders.add("a", "a");
httpHeaders.add(HttpHeaders.COOKIE, "cookies-k1=cookies-v1;cookies-k2=cookies-v2");
EnhancedRequestContext enhancedRequestContext = EnhancedRequestContext.builder()
.httpMethod(HttpMethod.GET)
.url(uri)
.httpHeaders(httpHeaders)
.build();
ServiceKey callerService = new ServiceKey("test", "test");
AssemblyRequestContext assemblyRequestContext = new AssemblyRequestContext(
enhancedRequestContext,
callerService,
"0.0.0.0"
);
assertThat(assemblyRequestContext.getURI()).isEqualTo(uri);
assertThat(assemblyRequestContext.getHeader("a")).isEqualTo("a");
assemblyRequestContext.setHeader("b", "b");
assertThat(assemblyRequestContext.listHeaderKeys()).isEqualTo(new HashSet<>(Arrays.asList(HttpHeaders.COOKIE, "a", "b")));
assertThat(assemblyRequestContext.getMethod()).isEqualTo(HttpMethod.GET.toString());
assemblyRequestContext.setMethod(HttpMethod.OPTIONS.name());
assertThat(assemblyRequestContext.getMethod()).isEqualTo(HttpMethod.OPTIONS.toString());
assertThat(assemblyRequestContext.getCookie("cookies-k1")).isEqualTo("cookies-v1");
assertThat(assemblyRequestContext.getCookie("cookies-k2")).isEqualTo("cookies-v2");
assemblyRequestContext.setCookie("cookies-k3", "cookies-v3");
assertThat(assemblyRequestContext.listCookieKeys()).isEqualTo(new HashSet<>(Arrays.asList("cookies-k1", "cookies-k2", "cookies-k3")));
assertThat(assemblyRequestContext.getCallerService()).isEqualTo(callerService);
assertThat(assemblyRequestContext.getCallerIp()).isEqualTo("0.0.0.0");
}
}

@ -1,101 +0,0 @@
/*
* Tencent is pleased to support the open source community by making Spring Cloud Tencent available.
*
* Copyright (C) 2019 THL A29 Limited, a Tencent company. All rights reserved.
*
* Licensed under the BSD 3-Clause License (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://opensource.org/licenses/BSD-3-Clause
*
* 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.tencent.cloud.rpc.enhancement.plugin;
import java.net.SocketTimeoutException;
import java.util.Arrays;
import java.util.HashSet;
import com.tencent.cloud.common.util.ApplicationContextAwareUtils;
import com.tencent.cloud.rpc.enhancement.config.RpcEnhancementReporterProperties;
import com.tencent.cloud.rpc.enhancement.plugin.assembly.AssemblyResponseContext;
import com.tencent.polaris.api.pojo.RetStatus;
import org.junit.jupiter.api.AfterAll;
import org.junit.jupiter.api.BeforeAll;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;
import org.mockito.MockedStatic;
import org.mockito.Mockito;
import org.mockito.junit.jupiter.MockitoExtension;
import org.springframework.context.ApplicationContext;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpStatus;
import static org.assertj.core.api.Assertions.assertThat;
import static org.mockito.ArgumentMatchers.anyString;
import static org.mockito.Mockito.doReturn;
import static org.mockito.Mockito.mock;
/**
* AssemblyResponseContextTest.
*
* @author sean yu
*/
@ExtendWith(MockitoExtension.class)
public class AssemblyResponseContextTest {
private static MockedStatic<ApplicationContextAwareUtils> mockedApplicationContextAwareUtils;
@BeforeAll
static void beforeAll() {
mockedApplicationContextAwareUtils = Mockito.mockStatic(ApplicationContextAwareUtils.class);
mockedApplicationContextAwareUtils.when(() -> ApplicationContextAwareUtils.getProperties(anyString()))
.thenReturn("unit-test");
ApplicationContext applicationContext = mock(ApplicationContext.class);
RpcEnhancementReporterProperties reporterProperties = mock(RpcEnhancementReporterProperties.class);
doReturn(reporterProperties)
.when(applicationContext).getBean(RpcEnhancementReporterProperties.class);
mockedApplicationContextAwareUtils.when(ApplicationContextAwareUtils::getApplicationContext)
.thenReturn(applicationContext);
}
@AfterAll
static void afterAll() {
mockedApplicationContextAwareUtils.close();
}
@Test
public void testAssemblyResponseContext() {
HttpHeaders httpHeaders = new HttpHeaders();
httpHeaders.add("a", "a");
EnhancedResponseContext enhancedResponseContext = EnhancedResponseContext.builder()
.httpHeaders(httpHeaders)
.httpStatus(HttpStatus.OK.value())
.build();
AssemblyResponseContext assemblyResponseContext = new AssemblyResponseContext(enhancedResponseContext, null);
assertThat(assemblyResponseContext.getHeader("a")).isEqualTo("a");
assertThat(assemblyResponseContext.getRetCode()).isEqualTo(HttpStatus.OK.value());
assertThat(assemblyResponseContext.getThrowable()).isEqualTo(null);
assertThat(assemblyResponseContext.getRetStatus()).isEqualTo(RetStatus.RetSuccess);
assertThat(assemblyResponseContext.listHeaders()).isEqualTo(new HashSet<>(Arrays.asList("a")));
Throwable e = new SocketTimeoutException();
assemblyResponseContext = new AssemblyResponseContext(null, e);
assertThat(assemblyResponseContext.getHeader("a")).isEqualTo(null);
assertThat(assemblyResponseContext.getRetCode()).isEqualTo(null);
assertThat(assemblyResponseContext.getThrowable()).isEqualTo(e);
assertThat(assemblyResponseContext.getRetStatus()).isEqualTo(RetStatus.RetTimeout);
assertThat(assemblyResponseContext.listHeaders()).isEqualTo(null);
}
}

@ -1,143 +0,0 @@
/*
* Tencent is pleased to support the open source community by making Spring Cloud Tencent available.
*
* Copyright (C) 2019 THL A29 Limited, a Tencent company. All rights reserved.
*
* Licensed under the BSD 3-Clause License (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://opensource.org/licenses/BSD-3-Clause
*
* 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.tencent.cloud.rpc.enhancement.plugin;
import java.net.URI;
import com.tencent.cloud.common.metadata.MetadataContext;
import com.tencent.cloud.common.util.ApplicationContextAwareUtils;
import com.tencent.cloud.rpc.enhancement.config.RpcEnhancementReporterProperties;
import com.tencent.cloud.rpc.enhancement.plugin.assembly.server.AssemblyServerExceptionHook;
import com.tencent.polaris.assembly.api.AssemblyAPI;
import org.junit.jupiter.api.AfterAll;
import org.junit.jupiter.api.BeforeAll;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;
import org.mockito.InjectMocks;
import org.mockito.Mock;
import org.mockito.MockedStatic;
import org.mockito.Mockito;
import org.mockito.junit.jupiter.MockitoExtension;
import org.springframework.cloud.client.DefaultServiceInstance;
import org.springframework.context.ApplicationContext;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpMethod;
import static com.tencent.polaris.test.common.Consts.NAMESPACE_TEST;
import static com.tencent.polaris.test.common.Consts.SERVICE_PROVIDER;
import static org.assertj.core.api.Assertions.assertThat;
import static org.mockito.ArgumentMatchers.anyString;
import static org.mockito.Mockito.doReturn;
import static org.mockito.Mockito.mock;
/**
* AssemblyServerExceptionHookTest.
*
* @author sean yu
*/
@ExtendWith(MockitoExtension.class)
public class AssemblyServerExceptionHookTest {
private static MockedStatic<ApplicationContextAwareUtils> mockedApplicationContextAwareUtils;
@InjectMocks
private AssemblyServerExceptionHook assemblyServerExceptionHook;
@Mock
private AssemblyAPI assemblyAPI;
@BeforeAll
static void beforeAll() {
mockedApplicationContextAwareUtils = Mockito.mockStatic(ApplicationContextAwareUtils.class);
mockedApplicationContextAwareUtils.when(() -> ApplicationContextAwareUtils.getProperties(anyString()))
.thenReturn("unit-test");
ApplicationContext applicationContext = mock(ApplicationContext.class);
RpcEnhancementReporterProperties reporterProperties = mock(RpcEnhancementReporterProperties.class);
doReturn(reporterProperties)
.when(applicationContext).getBean(RpcEnhancementReporterProperties.class);
mockedApplicationContextAwareUtils.when(ApplicationContextAwareUtils::getApplicationContext)
.thenReturn(applicationContext);
}
@AfterAll
static void afterAll() {
mockedApplicationContextAwareUtils.close();
}
@BeforeEach
void setUp() {
MetadataContext.LOCAL_NAMESPACE = NAMESPACE_TEST;
MetadataContext.LOCAL_SERVICE = SERVICE_PROVIDER;
}
@Test
public void testGetName() {
assertThat(assemblyServerExceptionHook.getName()).isEqualTo(AssemblyServerExceptionHook.class.getName());
}
@Test
public void testType() {
assertThat(assemblyServerExceptionHook.getType()).isEqualTo(EnhancedPluginType.Server.EXCEPTION);
}
@Test
public void testRun() {
EnhancedPluginContext pluginContext = new EnhancedPluginContext();
EnhancedRequestContext request = EnhancedRequestContext.builder()
.httpMethod(HttpMethod.GET)
.url(URI.create("http://0.0.0.0/"))
.httpHeaders(new HttpHeaders())
.build();
request.toString();
EnhancedResponseContext response = EnhancedResponseContext.builder()
.httpStatus(200)
.build();
response.toString();
DefaultServiceInstance targetServiceInstance = new DefaultServiceInstance();
targetServiceInstance.setServiceId(SERVICE_PROVIDER);
DefaultServiceInstance localServiceInstance = new DefaultServiceInstance();
localServiceInstance.setServiceId(SERVICE_PROVIDER);
pluginContext.setRequest(request);
pluginContext.setResponse(response);
pluginContext.setTargetServiceInstance(targetServiceInstance, null);
pluginContext.setLocalServiceInstance(localServiceInstance);
pluginContext.setThrowable(new RuntimeException());
assemblyServerExceptionHook.run(pluginContext);
assemblyServerExceptionHook.getOrder();
assemblyServerExceptionHook.getName();
assemblyServerExceptionHook.getType();
}
@Test
public void testHandlerThrowable() {
// mock request
EnhancedRequestContext request = mock(EnhancedRequestContext.class);
// mock response
EnhancedResponseContext response = mock(EnhancedResponseContext.class);
EnhancedPluginContext context = new EnhancedPluginContext();
context.setRequest(request);
context.setResponse(response);
assemblyServerExceptionHook.handlerThrowable(context, new RuntimeException("Mock exception."));
}
}

@ -1,143 +0,0 @@
/*
* Tencent is pleased to support the open source community by making Spring Cloud Tencent available.
*
* Copyright (C) 2019 THL A29 Limited, a Tencent company. All rights reserved.
*
* Licensed under the BSD 3-Clause License (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://opensource.org/licenses/BSD-3-Clause
*
* 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.tencent.cloud.rpc.enhancement.plugin;
import java.net.URI;
import com.tencent.cloud.common.metadata.MetadataContext;
import com.tencent.cloud.common.util.ApplicationContextAwareUtils;
import com.tencent.cloud.rpc.enhancement.config.RpcEnhancementReporterProperties;
import com.tencent.cloud.rpc.enhancement.plugin.assembly.server.AssemblyServerPostHook;
import com.tencent.polaris.assembly.api.AssemblyAPI;
import org.junit.jupiter.api.AfterAll;
import org.junit.jupiter.api.BeforeAll;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;
import org.mockito.InjectMocks;
import org.mockito.Mock;
import org.mockito.MockedStatic;
import org.mockito.Mockito;
import org.mockito.junit.jupiter.MockitoExtension;
import org.springframework.cloud.client.DefaultServiceInstance;
import org.springframework.context.ApplicationContext;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpMethod;
import static com.tencent.polaris.test.common.Consts.NAMESPACE_TEST;
import static com.tencent.polaris.test.common.Consts.SERVICE_PROVIDER;
import static org.assertj.core.api.Assertions.assertThat;
import static org.mockito.ArgumentMatchers.anyString;
import static org.mockito.Mockito.doReturn;
import static org.mockito.Mockito.mock;
/**
* AssemblyServerPostHookTest.
*
* @author sean yu
*/
@ExtendWith(MockitoExtension.class)
public class AssemblyServerPostHookTest {
private static MockedStatic<ApplicationContextAwareUtils> mockedApplicationContextAwareUtils;
@InjectMocks
private AssemblyServerPostHook assemblyServerPostHook;
@Mock
private AssemblyAPI assemblyAPI;
@BeforeAll
static void beforeAll() {
mockedApplicationContextAwareUtils = Mockito.mockStatic(ApplicationContextAwareUtils.class);
mockedApplicationContextAwareUtils.when(() -> ApplicationContextAwareUtils.getProperties(anyString()))
.thenReturn("unit-test");
ApplicationContext applicationContext = mock(ApplicationContext.class);
RpcEnhancementReporterProperties reporterProperties = mock(RpcEnhancementReporterProperties.class);
doReturn(reporterProperties)
.when(applicationContext).getBean(RpcEnhancementReporterProperties.class);
mockedApplicationContextAwareUtils.when(ApplicationContextAwareUtils::getApplicationContext)
.thenReturn(applicationContext);
}
@AfterAll
static void afterAll() {
mockedApplicationContextAwareUtils.close();
}
@BeforeEach
void setUp() {
MetadataContext.LOCAL_NAMESPACE = NAMESPACE_TEST;
MetadataContext.LOCAL_SERVICE = SERVICE_PROVIDER;
}
@Test
public void testGetName() {
assertThat(assemblyServerPostHook.getName()).isEqualTo(AssemblyServerPostHook.class.getName());
}
@Test
public void testType() {
assertThat(assemblyServerPostHook.getType()).isEqualTo(EnhancedPluginType.Server.POST);
}
@Test
public void testRun() {
EnhancedPluginContext pluginContext = new EnhancedPluginContext();
EnhancedRequestContext request = EnhancedRequestContext.builder()
.httpMethod(HttpMethod.GET)
.url(URI.create("http://0.0.0.0/"))
.httpHeaders(new HttpHeaders())
.build();
request.toString();
EnhancedResponseContext response = EnhancedResponseContext.builder()
.httpStatus(200)
.build();
response.toString();
DefaultServiceInstance targetServiceInstance = new DefaultServiceInstance();
targetServiceInstance.setServiceId(SERVICE_PROVIDER);
DefaultServiceInstance localServiceInstance = new DefaultServiceInstance();
localServiceInstance.setServiceId(SERVICE_PROVIDER);
pluginContext.setRequest(request);
pluginContext.setResponse(response);
pluginContext.setTargetServiceInstance(targetServiceInstance, null);
pluginContext.setLocalServiceInstance(localServiceInstance);
pluginContext.setThrowable(new RuntimeException());
assemblyServerPostHook.run(pluginContext);
assemblyServerPostHook.getOrder();
assemblyServerPostHook.getName();
assemblyServerPostHook.getType();
}
@Test
public void testHandlerThrowable() {
// mock request
EnhancedRequestContext request = mock(EnhancedRequestContext.class);
// mock response
EnhancedResponseContext response = mock(EnhancedResponseContext.class);
EnhancedPluginContext context = new EnhancedPluginContext();
context.setRequest(request);
context.setResponse(response);
assemblyServerPostHook.handlerThrowable(context, new RuntimeException("Mock exception."));
}
}

@ -1,143 +0,0 @@
/*
* Tencent is pleased to support the open source community by making Spring Cloud Tencent available.
*
* Copyright (C) 2019 THL A29 Limited, a Tencent company. All rights reserved.
*
* Licensed under the BSD 3-Clause License (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://opensource.org/licenses/BSD-3-Clause
*
* 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.tencent.cloud.rpc.enhancement.plugin;
import java.net.URI;
import com.tencent.cloud.common.metadata.MetadataContext;
import com.tencent.cloud.common.util.ApplicationContextAwareUtils;
import com.tencent.cloud.rpc.enhancement.config.RpcEnhancementReporterProperties;
import com.tencent.cloud.rpc.enhancement.plugin.assembly.server.AssemblyServerPreHook;
import com.tencent.polaris.assembly.api.AssemblyAPI;
import org.junit.jupiter.api.AfterAll;
import org.junit.jupiter.api.BeforeAll;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;
import org.mockito.InjectMocks;
import org.mockito.Mock;
import org.mockito.MockedStatic;
import org.mockito.Mockito;
import org.mockito.junit.jupiter.MockitoExtension;
import org.springframework.cloud.client.DefaultServiceInstance;
import org.springframework.context.ApplicationContext;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpMethod;
import static com.tencent.polaris.test.common.Consts.NAMESPACE_TEST;
import static com.tencent.polaris.test.common.Consts.SERVICE_PROVIDER;
import static org.assertj.core.api.Assertions.assertThat;
import static org.mockito.ArgumentMatchers.anyString;
import static org.mockito.Mockito.doReturn;
import static org.mockito.Mockito.mock;
/**
* AssemblyServerPreHookTest.
*
* @author sean yu
*/
@ExtendWith(MockitoExtension.class)
public class AssemblyServerPreHookTest {
private static MockedStatic<ApplicationContextAwareUtils> mockedApplicationContextAwareUtils;
@InjectMocks
private AssemblyServerPreHook assemblyServerPreHook;
@Mock
private AssemblyAPI assemblyAPI;
@BeforeAll
static void beforeAll() {
mockedApplicationContextAwareUtils = Mockito.mockStatic(ApplicationContextAwareUtils.class);
mockedApplicationContextAwareUtils.when(() -> ApplicationContextAwareUtils.getProperties(anyString()))
.thenReturn("unit-test");
ApplicationContext applicationContext = mock(ApplicationContext.class);
RpcEnhancementReporterProperties reporterProperties = mock(RpcEnhancementReporterProperties.class);
doReturn(reporterProperties)
.when(applicationContext).getBean(RpcEnhancementReporterProperties.class);
mockedApplicationContextAwareUtils.when(ApplicationContextAwareUtils::getApplicationContext)
.thenReturn(applicationContext);
}
@AfterAll
static void afterAll() {
mockedApplicationContextAwareUtils.close();
}
@BeforeEach
void setUp() {
MetadataContext.LOCAL_NAMESPACE = NAMESPACE_TEST;
MetadataContext.LOCAL_SERVICE = SERVICE_PROVIDER;
}
@Test
public void testGetName() {
assertThat(assemblyServerPreHook.getName()).isEqualTo(AssemblyServerPreHook.class.getName());
}
@Test
public void testType() {
assertThat(assemblyServerPreHook.getType()).isEqualTo(EnhancedPluginType.Server.PRE);
}
@Test
public void testRun() {
EnhancedPluginContext pluginContext = new EnhancedPluginContext();
EnhancedRequestContext request = EnhancedRequestContext.builder()
.httpMethod(HttpMethod.GET)
.url(URI.create("http://0.0.0.0/"))
.httpHeaders(new HttpHeaders())
.build();
request.toString();
EnhancedResponseContext response = EnhancedResponseContext.builder()
.httpStatus(200)
.build();
response.toString();
DefaultServiceInstance targetServiceInstance = new DefaultServiceInstance();
targetServiceInstance.setServiceId(SERVICE_PROVIDER);
DefaultServiceInstance localServiceInstance = new DefaultServiceInstance();
localServiceInstance.setServiceId(SERVICE_PROVIDER);
pluginContext.setRequest(request);
pluginContext.setResponse(response);
pluginContext.setTargetServiceInstance(targetServiceInstance, null);
pluginContext.setLocalServiceInstance(localServiceInstance);
pluginContext.setThrowable(new RuntimeException());
assemblyServerPreHook.run(pluginContext);
assemblyServerPreHook.getOrder();
assemblyServerPreHook.getName();
assemblyServerPreHook.getType();
}
@Test
public void testHandlerThrowable() {
// mock request
EnhancedRequestContext request = mock(EnhancedRequestContext.class);
// mock response
EnhancedResponseContext response = mock(EnhancedResponseContext.class);
EnhancedPluginContext context = new EnhancedPluginContext();
context.setRequest(request);
context.setResponse(response);
assemblyServerPreHook.handlerThrowable(context, new RuntimeException("Mock exception."));
}
}
Loading…
Cancel
Save