Compare commits
82 Commits
3.2
...
3.3-config
| Author | SHA1 | Date |
|---|---|---|
|
|
f020f3e3d1 | |
|
|
9eb83d16bb | |
|
|
98e7313e71 | |
|
|
a6a6d57dd7 | |
|
|
8009c72030 | |
|
|
7e6a32ba68 | |
|
|
36a80e4db7 | |
|
|
bf3d4f4ca3 | |
|
|
f91246ab09 | |
|
|
679ce4496c | |
|
|
4e9a0a41fc | |
|
|
7a4ec6c525 | |
|
|
ae150c01e5 | |
|
|
629bee3987 | |
|
|
5ae875d951 | |
|
|
04f3fe7d2b | |
|
|
059fdf2613 | |
|
|
7c971ca1bd | |
|
|
b18eeb7077 | |
|
|
6c5a876f31 | |
|
|
ce65317207 | |
|
|
046898bbc8 | |
|
|
29d9c070d4 | |
|
|
8fefd95a98 | |
|
|
2973426b2a | |
|
|
70605f4dd0 | |
|
|
d1719c5358 | |
|
|
0e17f4f168 | |
|
|
72e5d20ce9 | |
|
|
0db8605974 | |
|
|
80d496c5b1 | |
|
|
093fb7c208 | |
|
|
f78b4f5dea | |
|
|
1f8a0fa5ec | |
|
|
f2ec217f54 | |
|
|
c7d411c3cb | |
|
|
8bb17b85f2 | |
|
|
4b62513dff | |
|
|
9bbf7625a8 | |
|
|
0d4e8304bc | |
|
|
48cc5b24de | |
|
|
37f150263a | |
|
|
95207b9079 | |
|
|
da8d0cd994 | |
|
|
27e6838c3b | |
|
|
1c65617fb1 | |
|
|
cf2a63580e | |
|
|
d6776e4008 | |
|
|
b14201f393 | |
|
|
c96a06eba1 | |
|
|
1e59ab524a | |
|
|
fd14e7b76f | |
|
|
642f741dba | |
|
|
85bc6ea472 | |
|
|
391d3cdb35 | |
|
|
2031a4c531 | |
|
|
e642e72ce8 | |
|
|
4604b8074a | |
|
|
30daba2d74 | |
|
|
1f39543632 | |
|
|
71046bdd6f | |
|
|
ae4899a462 | |
|
|
7661cab6f5 | |
|
|
d798e7c3be | |
|
|
34eb252178 | |
|
|
59758f4b58 | |
|
|
52e4e4e301 | |
|
|
71cc51bf69 | |
|
|
a80ad7f505 | |
|
|
9f0e1589a5 | |
|
|
471f44b52d | |
|
|
992abd2d34 | |
|
|
9d9df82194 | |
|
|
6c8f79c889 | |
|
|
2997fa6a2e | |
|
|
13558a8e6a | |
|
|
59832d45d4 | |
|
|
fe55491d4a | |
|
|
b23bae38cc | |
|
|
0b6f2e4a8d | |
|
|
414785c05b | |
|
|
52611099ab |
42
.artifacts
42
.artifacts
|
|
@ -19,6 +19,7 @@
|
|||
dubbo
|
||||
dubbo-auth
|
||||
dubbo-apache-release
|
||||
dubbo-all-shaded
|
||||
dubbo-bom
|
||||
dubbo-build-tools
|
||||
dubbo-cluster
|
||||
|
|
@ -28,7 +29,11 @@ dubbo-compiler
|
|||
dubbo-config
|
||||
dubbo-config-api
|
||||
dubbo-config-spring
|
||||
dubbo-config-spring6
|
||||
dubbo-config-test
|
||||
dubbo-configcenter
|
||||
dubbo-configcenter-api
|
||||
dubbo-configcenter-file
|
||||
dubbo-configcenter-apollo
|
||||
dubbo-configcenter-nacos
|
||||
dubbo-configcenter-zookeeper
|
||||
|
|
@ -49,6 +54,7 @@ dubbo-kubernetes
|
|||
dubbo-maven-plugin
|
||||
dubbo-metadata
|
||||
dubbo-metadata-api
|
||||
dubbo-metadata-rest
|
||||
dubbo-metadata-definition-protobuf
|
||||
dubbo-metadata-processor
|
||||
dubbo-metadata-report-nacos
|
||||
|
|
@ -61,11 +67,13 @@ dubbo-metrics-metadata
|
|||
dubbo-metrics-prometheus
|
||||
dubbo-metrics-registry
|
||||
dubbo-metrics-config-center
|
||||
dubbo-metrics-netty
|
||||
dubbo-metrics-event
|
||||
dubbo-monitor
|
||||
dubbo-monitor-api
|
||||
dubbo-monitor-common
|
||||
dubbo-monitor-default
|
||||
dubbo-native
|
||||
dubbo-native-plugin
|
||||
dubbo-parent
|
||||
dubbo-plugin
|
||||
dubbo-qos
|
||||
|
|
@ -82,6 +90,7 @@ dubbo-remoting-api
|
|||
dubbo-remoting-http
|
||||
dubbo-remoting-netty
|
||||
dubbo-remoting-netty4
|
||||
dubbo-remoting-zookeeper-api
|
||||
dubbo-remoting-zookeeper
|
||||
dubbo-remoting-zookeeper-curator5
|
||||
dubbo-rpc
|
||||
|
|
@ -102,16 +111,35 @@ dubbo-spring-boot-actuator-compatible
|
|||
dubbo-spring-boot-autoconfigure
|
||||
dubbo-spring-boot-autoconfigure-compatible
|
||||
dubbo-spring-boot-compatible
|
||||
dubbo-spring-boot-observability-starters
|
||||
dubbo-spring-boot-observability-autoconfigure
|
||||
dubbo-spring-boot-tracing-brave-zipkin-starter
|
||||
dubbo-spring-boot-tracing-otel-zipkin-starter
|
||||
dubbo-spring-boot-tracing-otel-otlp-starter
|
||||
dubbo-spring-boot-observability-starter
|
||||
dubbo-observability-spring-boot-starters
|
||||
dubbo-observability-spring-boot-autoconfigure
|
||||
dubbo-tracing-brave-zipkin-spring-boot-starter
|
||||
dubbo-tracing-otel-zipkin-spring-boot-starter
|
||||
dubbo-tracing-otel-otlp-spring-boot-starter
|
||||
dubbo-observability-spring-boot-starter
|
||||
dubbo-spring-boot-starter
|
||||
dubbo-spring-boot-starters
|
||||
dubbo-spring-boot-interceptor
|
||||
dubbo-nacos-spring-boot-starter
|
||||
dubbo-zookeeper-spring-boot-starter
|
||||
dubbo-zookeeper-curator5-spring-boot-starter
|
||||
dubbo-sentinel-spring-boot-starter
|
||||
dubbo-seata-spring-boot-starter
|
||||
dubbo-spring-security
|
||||
dubbo-tracing
|
||||
dubbo-xds
|
||||
dubbo-plugin-cluster-mergeable
|
||||
dubbo-plugin-mock
|
||||
dubbo-plugin-router-script
|
||||
dubbo-plugin-router-mesh
|
||||
dubbo-plugin-router-condition
|
||||
dubbo-plugin-router-tag
|
||||
dubbo-plugin-loadbalance-adaptive
|
||||
dubbo-plugin-access-log
|
||||
dubbo-plugin-tps
|
||||
dubbo-plugin-token
|
||||
dubbo-plugin-generic-invoke
|
||||
dubbo-plugin-context
|
||||
dubbo-plugin-classloader-filter
|
||||
dubbo-plugin-proxy-bytebuddy
|
||||
dubbo-plugin-qos-trace
|
||||
|
|
|
|||
|
|
@ -54,7 +54,7 @@ jobs:
|
|||
- uses: actions/setup-java@v3
|
||||
with:
|
||||
distribution: 'zulu'
|
||||
java-version: 8
|
||||
java-version: 17
|
||||
- uses: actions/cache@v3
|
||||
name: "Cache local Maven repository"
|
||||
with:
|
||||
|
|
|
|||
|
|
@ -97,10 +97,13 @@ header:
|
|||
- 'dubbo-maven-plugin/src/main/java/org/apache/dubbo/maven/plugin/aot/RunArguments.java'
|
||||
- 'dubbo-maven-plugin/src/main/java/org/apache/dubbo/maven/plugin/aot/RunProcess.java'
|
||||
- 'dubbo-native/src/main/java/org/apache/dubbo/aot/generate/BasicJsonWriter.java'
|
||||
- 'dubbo-native/src/main/java/org/apache/dubbo/aot/generate/ExecutableMode.java'
|
||||
- 'dubbo-native/src/main/java/org/apache/dubbo/aot/generate/MemberCategory.java'
|
||||
- 'dubbo-native/src/main/java/org/apache/dubbo/aot/api/ExecutableMode.java'
|
||||
- 'dubbo-native/src/main/java/org/apache/dubbo/aot/api/MemberCategory.java'
|
||||
- 'dubbo-metrics/dubbo-metrics-api/src/main/java/org/apache/dubbo/metrics/aggregate/DubboMergingDigest.java'
|
||||
- 'dubbo-metrics/dubbo-metrics-api/src/main/java/org/apache/dubbo/metrics/aggregate/DubboAbstractTDigest.java'
|
||||
- 'dubbo-annotation-processor/src/main/java/org/apache/dubbo/annotation/permit/**'
|
||||
- 'dubbo-common/src/main/java/org/apache/dubbo/common/logger/helpers/FormattingTuple.java'
|
||||
- 'dubbo-common/src/main/java/org/apache/dubbo/common/logger/helpers/MessageFormatter.java'
|
||||
|
||||
comment: on-failure
|
||||
|
||||
|
|
@ -199,10 +202,26 @@ dependency:
|
|||
license: Apache-2.0
|
||||
- name: org.sonatype.plexus:plexus-cipher
|
||||
license: Apache-2.0
|
||||
- name: com.alibaba.csp:sentinel-apache-dubbo3-adapter
|
||||
license: Apache-2.0
|
||||
- name: com.alibaba.csp:sentinel-transport-simple-http
|
||||
license: Apache-2.0
|
||||
- name: com.alibaba.csp:sentinel-transport-common
|
||||
license: Apache-2.0
|
||||
- name: com.alibaba.csp:sentinel-datasource-extension
|
||||
license: Apache-2.0
|
||||
- name: com.alibaba.csp:sentinel-core
|
||||
license: Apache-2.0
|
||||
- name: com.google.protobuf:protobuf-java
|
||||
license: BSD 3-clause
|
||||
- name: com.google.protobuf:protobuf-java-util
|
||||
license: BSD 3-clause
|
||||
- name: org.antlr:antlr4
|
||||
license: BSD 3-clause
|
||||
- name: org.antlr:antlr-runtime
|
||||
license: BSD 3-clause
|
||||
- name: org.antlr:ST4
|
||||
license: BSD 3-clause
|
||||
# multi license
|
||||
- name: org.javassist:javassist
|
||||
license: Apache-2.0
|
||||
|
|
|
|||
2
NOTICE
2
NOTICE
|
|
@ -4,7 +4,7 @@ Copyright 2018-2023 The Apache Software Foundation
|
|||
This product includes software developed at
|
||||
The Apache Software Foundation (http://www.apache.org/).
|
||||
|
||||
This product contains code form the Netty Project:
|
||||
This product contains code from the Netty Project:
|
||||
|
||||
The Netty Project
|
||||
=================
|
||||
|
|
|
|||
|
|
@ -1,21 +1,8 @@
|
|||
## What is the purpose of the change
|
||||
## What is the purpose of the change?
|
||||
|
||||
|
||||
|
||||
## Brief changelog
|
||||
|
||||
|
||||
## Verifying this change
|
||||
|
||||
|
||||
<!-- Follow this checklist to help us incorporate your contribution quickly and easily: -->
|
||||
|
||||
## Checklist
|
||||
- [x] Make sure there is a [GitHub_issue](https://github.com/apache/dubbo/issues) field for the change (usually before you start working on it). Trivial changes like typos do not require a GitHub issue. Your pull request should address just this issue, without pulling in other changes - one PR resolves one issue.
|
||||
- [ ] Each commit in the pull request should have a meaningful subject line and body.
|
||||
- [ ] Write a pull request description that is detailed enough to understand what the pull request does, how, and why.
|
||||
- [ ] Check if is necessary to patch to Dubbo 3 if you are work on Dubbo 2.7
|
||||
- [ ] Write necessary unit-test to verify your logic correction, more mock a little better when cross module dependency exist. If the new feature or significant change is committed, please remember to add sample in [dubbo samples](https://github.com/apache/dubbo-samples) project.
|
||||
- [ ] Add some description to [dubbo-website](https://github.com/apache/dubbo-website) project if you are requesting to add a feature.
|
||||
- [ ] GitHub Actions works fine on your own branch.
|
||||
- [ ] If this contribution is large, please follow the [Software Donation Guide](https://github.com/apache/dubbo/wiki/Software-donation-guide).
|
||||
- [x] Make sure there is a [GitHub_issue](https://github.com/apache/dubbo/issues) field for the change.
|
||||
- [x] Write a pull request description that is detailed enough to understand what the pull request does, how, and why.
|
||||
- [x] Write necessary unit-test to verify your logic correction. If the new feature or significant change is committed, please remember to add sample in [dubbo samples](https://github.com/apache/dubbo-samples) project.
|
||||
- [x] Make sure gitHub actions can pass. [Why the workflow is failing and how to fix it?](./CONTRIBUTING.md)
|
||||
|
|
|
|||
255
README.md
255
README.md
|
|
@ -10,236 +10,69 @@
|
|||
[](https://twitter.com/intent/follow?screen_name=ApacheDubbo)
|
||||
[](https://gitter.im/alibaba/dubbo?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge)
|
||||
|
||||
Apache Dubbo is a high-performance, Java-based open-source RPC framework. Please visit the [official site](http://dubbo.apache.org) for the quick start guide and documentation, as well as the [wiki](https://github.com/apache/dubbo/wiki) for news, FAQ, and release notes.
|
||||
Apache Dubbo is an easy-to-use Web and RPC framework that provides multiple
|
||||
language implementations(Java, [Go](https://github.com/apache/dubbo-go), [Rust](https://github.com/apache/dubbo-rust), [Node.js](https://github.com/apache/dubbo-js), [Web](https://github.com/apache/dubbo-js)) for communication, service discovery, traffic management,
|
||||
observability, security, tools, and best practices for building enterprise-ready microservices.
|
||||
|
||||
We are now collecting Dubbo user info to help us to improve Dubbo further. Kindly support us by providing your usage information on [issue#9436: Wanted: who's using dubbo](https://github.com/apache/dubbo/issues/9436), thanks :)
|
||||
Visit [the official website](https://dubbo.apache.org/) for more information.
|
||||
|
||||
## Architecture
|
||||
|
||||

|
||||
|
||||
## Features
|
||||
|
||||
* Transparent interface based RPC
|
||||
* Intelligent load balancing
|
||||
* Automatic service registration and discovery
|
||||
* High extensibility
|
||||
* Runtime traffic routing
|
||||
* Visualized service governance
|
||||
* Consumer and provider communicate with each other using RPC protocol like triple, tcp, rest, etc.
|
||||
* Consumers automatically trace provider instances registered in registries(Zookeeper, Nacos) and distribute traffic among them by following traffic strategies.
|
||||
* Rich features for monitoring and managing the cluster with dynamic configuration, metrics, tracing, security, and visualized console.
|
||||
|
||||
## Getting started
|
||||
Follow the instructions below to learn how to:
|
||||
|
||||
The following code snippet comes from [Dubbo Samples](https://github.com/apache/dubbo-samples.git). You may clone the sample project and step into the `dubbo-samples-api` subdirectory before proceeding.
|
||||
### Programming with lightweight RPC API
|
||||
[5 minutes step-by-step guide](https://dubbo.apache.org/zh-cn/overview/quickstart/rpc/java)
|
||||
|
||||
```bash
|
||||
git clone https://github.com/apache/dubbo-samples.git
|
||||
cd dubbo-samples/1-basic/dubbo-samples-api
|
||||
```
|
||||
|
||||
There's a [README](https://github.com/apache/dubbo-samples/blob/389cd612f1ea57ee6e575005b32f195c442c35a2/1-basic/dubbo-samples-api/README.md) file under `dubbo-samples-api` directory. We recommend referencing the samples in that directory by following the below-mentioned instructions:
|
||||
|
||||
### Maven dependency
|
||||
|
||||
```xml
|
||||
<properties>
|
||||
<dubbo.version>3.2.5</dubbo.version>
|
||||
</properties>
|
||||
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>org.apache.dubbo</groupId>
|
||||
<artifactId>dubbo</artifactId>
|
||||
<version>${dubbo.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.apache.dubbo</groupId>
|
||||
<artifactId>dubbo-dependencies-zookeeper</artifactId>
|
||||
<version>${dubbo.version}</version>
|
||||
<type>pom</type>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
```
|
||||
|
||||
### Define service interfaces
|
||||
|
||||
```java
|
||||
package org.apache.dubbo.samples.api;
|
||||
|
||||
public interface GreetingsService {
|
||||
String sayHi(String name);
|
||||
}
|
||||
```
|
||||
|
||||
*See [api/GreetingsService.java](https://github.com/apache/dubbo-samples/blob/389cd612f1ea57ee6e575005b32f195c442c35a2/1-basic/dubbo-samples-api/src/main/java/org/apache/dubbo/samples/api/GreetingsService.java) on GitHub.*
|
||||
|
||||
### Implement service interface for the provider
|
||||
|
||||
```java
|
||||
package org.apache.dubbo.samples.provider;
|
||||
|
||||
import org.apache.dubbo.samples.api.GreetingsService;
|
||||
|
||||
public class GreetingsServiceImpl implements GreetingsService {
|
||||
@Override
|
||||
public String sayHi(String name) {
|
||||
return "hi, " + name;
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
*See [provider/GreetingsServiceImpl.java](https://github.com/apache/dubbo-samples/blob/389cd612f1ea57ee6e575005b32f195c442c35a2/1-basic/dubbo-samples-api/src/main/java/org/apache/dubbo/samples/provider/GreetingsServiceImpl.java) on GitHub.*
|
||||
|
||||
### Start service provider
|
||||
|
||||
```java
|
||||
package org.apache.dubbo.samples.provider;
|
||||
Dubbo supports building RPC services with only a few lines of code while depending only on a lightweight SDK (<10MB). The protocol on the wire can be [Triple](https://dubbo.apache.org/zh-cn/overview/reference/protocols/triple/)(fully gRPC compatible and HTTP-friendly), Dubbo2(TCP), REST, or any protocol of your choice.
|
||||
|
||||
|
||||
import org.apache.dubbo.config.ApplicationConfig;
|
||||
import org.apache.dubbo.config.RegistryConfig;
|
||||
import org.apache.dubbo.config.ServiceConfig;
|
||||
import org.apache.dubbo.samples.api.GreetingsService;
|
||||
### Building a microservice application with Spring Boot
|
||||
[5 minutes step-by-step guide](https://dubbo.apache.org/zh-cn/overview/quickstart/microservice)
|
||||
|
||||
import java.util.concurrent.CountDownLatch;
|
||||
It's highly recommended to start your microservice application with the Spring Boot Starter `dubbo-spring-boot-starter` provided by Dubbo. With only a single dependency and yaml file, and optionally a bunch of other useful spring boot starters, you can enable all of the Dubo features like service discovery, observability, tracing, etc.
|
||||
|
||||
public class Application {
|
||||
private static String zookeeperHost = System.getProperty("zookeeper.address", "127.0.0.1");
|
||||
Next, learn how to [deploy](https://dubbo.apache.org/zh-cn/overview/tasks/deploy/), [monitor](https://dubbo.apache.org/zh-cn/overview/tasks/observability/), and [manage the traffic](https://dubbo.apache.org/zh-cn/overview/tasks/traffic-management/) of your Dubbo application and cluster.
|
||||
|
||||
public static void main(String[] args) throws Exception {
|
||||
ServiceConfig<GreetingsService> service = new ServiceConfig<>();
|
||||
service.setApplication(new ApplicationConfig("first-dubbo-provider"));
|
||||
service.setRegistry(new RegistryConfig("zookeeper://" + zookeeperHost + ":2181"));
|
||||
service.setInterface(GreetingsService.class);
|
||||
service.setRef(new GreetingsServiceImpl());
|
||||
service.export();
|
||||
## More Features
|
||||
Get more details by visiting the links below to get your hands dirty with some well-designed tasks on our website.
|
||||
|
||||
System.out.println("dubbo service started");
|
||||
new CountDownLatch(1).await();
|
||||
}
|
||||
}
|
||||
```
|
||||
* [Launch a Dubbo project](https://dubbo.apache.org/zh-cn/overview/tasks/develop/template/)
|
||||
* [RPC protocols](https://dubbo.apache.org/zh-cn/overview/core-features/protocols/)
|
||||
* [Traffic management](https://dubbo.apache.org/zh-cn/overview/core-features/traffic/)
|
||||
* [Service discovery](https://dubbo.apache.org/zh-cn/overview/core-features/service-discovery/)
|
||||
* [Observability](https://dubbo.apache.org/zh-cn/overview/core-features/observability/)
|
||||
* [Extensibility](https://dubbo.apache.org/zh-cn/overview/core-features/extensibility/)
|
||||
* [Security](https://dubbo.apache.org/zh-cn/overview/core-features/security/)
|
||||
* [Visualized console and control plane](https://dubbo.apache.org/zh-cn/overview/reference/admin/)
|
||||
* [Kubernetes and Service mesh](https://dubbo.apache.org/zh-cn/overview/core-features/service-mesh/)
|
||||
|
||||
*See [provider/Application.java](https://github.com/apache/dubbo-samples/blob/389cd612f1ea57ee6e575005b32f195c442c35a2/1-basic/dubbo-samples-spring-xml/src/main/java/org/apache/dubbo/samples/provider/Application.java) on GitHub.*
|
||||
## Which Dubbo version should I use?
|
||||
| **Dubbo3** | **JDK** | **Dependencies** | **Description** |
|
||||
| --- | --- | --- | --- |
|
||||
| 3.3.0-beta| 1.8 ~ 17 | [dependency list](https://github.com/apache/dubbo/blob/3.3/dubbo-dependencies-bom/pom.xml#L94) | **- Unstable version** <br/> **- Features** <br/> - Triple - gRPC and cURL compatible.<br/> - Rest-style programming support.<br/> - Spring Boot Starters. |
|
||||
| 3.2.5 | 1.8 ~ 17 | [dependency list](https://github.com/apache/dubbo/blob/dubbo-3.2.5/dubbo-dependencies-bom/pom.xml#L94) | **- Stable version (active)** <br/> **- Features** <br/> - Out-of-box metrics and tracing support.<br/> - Threadpool Isolation<br/> - 30% performance<br/> - Native Image|
|
||||
| 3.1.11 | 1.8 ~ 11 | [dependency list](https://github.com/apache/dubbo/blob/dubbo-3.2.11/dubbo-dependencies-bom/pom.xml#L94) | **Stable version (not active)** |
|
||||
|
||||
### Build and run the provider
|
||||
|
||||
```bash
|
||||
mvn clean package
|
||||
mvn -Djava.net.preferIPv4Stack=true -Dexec.mainClass=org.apache.dubbo.samples.provider.Application exec:java
|
||||
```
|
||||
|
||||
### Call remote service in the consumer
|
||||
|
||||
```java
|
||||
package org.apache.dubbo.samples.client;
|
||||
|
||||
|
||||
import org.apache.dubbo.config.ApplicationConfig;
|
||||
import org.apache.dubbo.config.ReferenceConfig;
|
||||
import org.apache.dubbo.config.RegistryConfig;
|
||||
import org.apache.dubbo.samples.api.GreetingsService;
|
||||
|
||||
public class Application {
|
||||
private static String zookeeperHost = System.getProperty("zookeeper.address", "127.0.0.1");
|
||||
|
||||
public static void main(String[] args) {
|
||||
ReferenceConfig<GreetingsService> reference = new ReferenceConfig<>();
|
||||
reference.setApplication(new ApplicationConfig("first-dubbo-consumer"));
|
||||
reference.setRegistry(new RegistryConfig("zookeeper://" + zookeeperHost + ":2181"));
|
||||
reference.setInterface(GreetingsService.class);
|
||||
GreetingsService service = reference.get();
|
||||
String message = service.sayHi("dubbo");
|
||||
System.out.println(message);
|
||||
}
|
||||
}
|
||||
```
|
||||
*See [client/Application.java](https://github.com/apache/dubbo-samples/blob/389cd612f1ea57ee6e575005b32f195c442c35a2/1-basic/dubbo-samples-api/src/main/java/org/apache/dubbo/samples/client/Application.java) on GitHub.*
|
||||
|
||||
### Build and run the consumer
|
||||
|
||||
```bash
|
||||
mvn clean package
|
||||
mvn -Djava.net.preferIPv4Stack=true -Dexec.mainClass=org.apache.dubbo.samples.client.Application exec:java
|
||||
```
|
||||
|
||||
The consumer will print out `hi, dubbo` on the screen.
|
||||
|
||||
|
||||
### Next steps
|
||||
|
||||
* [Your first Dubbo application](https://dubbo.apache.org/en/blog/2018/08/07/dubbo-101/) - A 101 tutorial to reveal more details, with the same code above.
|
||||
* [Dubbo user manual](https://dubbo.apache.org/en/overview/what/) - How to use Dubbo and all its features.
|
||||
* [Dubbo developer guide](https://dubbo.apache.org/en/docs3-v2/java-sdk/) - How to involve in Dubbo development.
|
||||
* [Dubbo admin manual](https://dubbo.apache.org/en/docs/v2.7/admin/ops/) - How to admin and manage Dubbo services.
|
||||
|
||||
## Building
|
||||
|
||||
If you want to try out the cutting-edge features, you can build with the following commands. (Java 1.8 is needed to build the master branch)
|
||||
|
||||
```
|
||||
mvn clean install
|
||||
```
|
||||
|
||||
## Recommended Test Environment
|
||||
To avoid intermittent test failures (i.e., flaky tests), it is recommended to have a machine or virtual machine with the following specifications:
|
||||
|
||||
* Minimum of 2CPUs.
|
||||
* Minimum of 2Gb of RAM.
|
||||
|
||||
## Contact
|
||||
|
||||
* Mailing list:
|
||||
* dev list: for dev/user discussion. [subscribe](mailto:dev-subscribe@dubbo.apache.org), [unsubscribe](mailto:dev-unsubscribe@dubbo.apache.org), [archive](https://lists.apache.org/list.html?dev@dubbo.apache.org), [guide](https://github.com/apache/dubbo/wiki/Mailing-list-subscription-guide)
|
||||
|
||||
* Bugs: [Issues](https://github.com/apache/dubbo/issues/new?template=dubbo-issue-report-template.md)
|
||||
* Gitter: [Gitter channel](https://gitter.im/alibaba/dubbo)
|
||||
* Twitter: [@ApacheDubbo](https://twitter.com/ApacheDubbo)
|
||||
| **Dubbo2** | **JDK** | **Dependencies** | **Description** |
|
||||
| --- | --- | --- | --- |
|
||||
| 2.7.23 | 1.8 | [dependency list](https://github.com/apache/dubbo/blob/dubbo-2.7.23/dubbo-dependencies-bom/pom.xml#L92) | EOL |
|
||||
| 2.6.x, 2.5.x | 1.6 ~ 1.7 | | EOL |
|
||||
|
||||
## Contributing
|
||||
See [CONTRIBUTING](https://github.com/apache/dubbo/blob/master/CONTRIBUTING.md) for details on submitting patches and the contribution workflow.
|
||||
|
||||
See [CONTRIBUTING](https://github.com/apache/dubbo/blob/master/CONTRIBUTING.md) for details on submitting patches and the contribution workflow.
|
||||
|
||||
### How can I contribute?
|
||||
|
||||
* Take a look at issues with tags marked [`Good first issue`](https://github.com/apache/dubbo/issues?q=is%3Aopen+is%3Aissue+label%3A%22good+first+issue%22) or [`Help wanted`](https://github.com/apache/dubbo/issues?q=is%3Aopen+is%3Aissue+label%3A%22help+wanted%22).
|
||||
* Join the discussion on the mailing list, subscription [guide](https://github.com/apache/dubbo/wiki/Mailing-list-subscription-guide).
|
||||
* Answer questions on [issues](https://github.com/apache/dubbo/issues).
|
||||
* Fix bugs reported on [issues](https://github.com/apache/dubbo/issues), and send us a pull request.
|
||||
* Review the existing [pull request](https://github.com/apache/dubbo/pulls).
|
||||
* Improve the [website](https://github.com/apache/dubbo-website), typically we need
|
||||
* blog post
|
||||
* translation on documentation
|
||||
* use cases around the integration of Dubbo in enterprise systems.
|
||||
* Improve the [dubbo-admin/dubbo-monitor](https://github.com/apache/dubbo-admin).
|
||||
* Contribute to the projects listed in [ecosystem](https://github.com/dubbo).
|
||||
* Other forms of contribution not explicitly enumerated above.
|
||||
* If you would like to contribute, please send an email to dev@dubbo.apache.org to let us know!
|
||||
|
||||
## Reporting bugs
|
||||
|
||||
Please follow the [template](https://github.com/apache/dubbo/issues/new?template=dubbo-issue-report-template.md) for reporting any issues.
|
||||
|
||||
## Reporting a security vulnerability
|
||||
|
||||
Please report security vulnerabilities to [us](mailto:security@dubbo.apache.org) privately.
|
||||
|
||||
## Dubbo ecosystem
|
||||
|
||||
* [Dubbo Ecosystem Entry](https://github.com/apache?utf8=%E2%9C%93&q=dubbo&type=&language=) - A GitHub group `dubbo` to gather all Dubbo relevant projects not appropriate in [apache](https://github.com/apache) group yet
|
||||
* [Dubbo Website](https://github.com/apache/dubbo-website) - Apache Dubbo official website
|
||||
* [Dubbo Samples](https://github.com/apache/dubbo-samples) - samples for Apache Dubbo
|
||||
* [Dubbo Spring Boot](https://github.com/apache/dubbo-spring-boot-project) - Spring Boot Project for Dubbo
|
||||
* [Dubbo Admin](https://github.com/apache/dubbo-admin) - The reference implementation for Dubbo admin
|
||||
* [Dubbo Awesome](https://github.com/apache/dubbo-awesome) - Dubbo's slides and video links in Meetup
|
||||
|
||||
#### Language
|
||||
|
||||
* [Go](https://github.com/dubbo/dubbo-go) (recommended)
|
||||
* [Node.js](https://github.com/apache/dubbo-js)
|
||||
* [Python](https://github.com/dubbo/py-client-for-apache-dubbo)
|
||||
* [PHP](https://github.com/apache/dubbo-php-framework)
|
||||
* [Erlang](https://github.com/apache/dubbo-erlang)
|
||||
## Contact
|
||||
* WeChat: apachedubbo
|
||||
* DingTalk group: 37290003945
|
||||
* Mailing list: [guide](https://dubbo.apache.org/zh-cn/contact/)
|
||||
* Twitter: [@ApacheDubbo](https://twitter.com/ApacheDubbo)
|
||||
* Security issues: please mail to [us](mailto:security@dubbo.apache.org) privately.
|
||||
|
||||
## License
|
||||
|
||||
Apache Dubbo software is licensed under the Apache License Version 2.0. See the [LICENSE](https://github.com/apache/dubbo/blob/master/LICENSE) file for details.
|
||||
Apache Dubbo is licensed under the Apache License Version 2.0. See the [LICENSE](https://github.com/apache/dubbo/blob/master/LICENSE) file for details.
|
||||
|
|
|
|||
|
|
@ -29,7 +29,6 @@ ignore:
|
|||
- "**/dubbo-test/**"
|
||||
- "**/dubbo-compatible/**"
|
||||
- "**/dubbo-native/**"
|
||||
- "**/dubbo-native-plugin/**"
|
||||
- "**/dubbo-common/src/main/java/org/apache/dubbo/common/json/*.java" # internal JSON impl is deprecate, ignore test coverage for them
|
||||
- "**/dubbo-config/dubbo-config-spring/src/main/java/org/apache/dubbo/config/spring/AnnotationBean.java" # Deprecated
|
||||
- "**/dubbo-rpc/dubbo-rpc-thrift/**"
|
||||
|
|
|
|||
|
|
@ -0,0 +1,165 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
|
||||
<!--
|
||||
Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
contributor license agreements. See the NOTICE file distributed with
|
||||
this work for additional information regarding copyright ownership.
|
||||
The ASF licenses this file to You under the Apache License, Version 2.0
|
||||
(the "License"); you may not use this file except in compliance with
|
||||
the License. You may obtain a copy of the License at
|
||||
|
||||
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.
|
||||
-->
|
||||
|
||||
<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">
|
||||
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
||||
<groupId>org.apache.dubbo</groupId>
|
||||
<artifactId>dubbo-annotation-processor</artifactId>
|
||||
<version>1.0.0</version>
|
||||
|
||||
<properties>
|
||||
<maven.compiler.source>8</maven.compiler.source>
|
||||
<maven.compiler.target>8</maven.compiler.target>
|
||||
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
|
||||
|
||||
<!-- System dependencies may cause problems in checkstyle. -->
|
||||
<checkstyle.skip>true</checkstyle.skip>
|
||||
<checkstyle_unix.skip>true</checkstyle_unix.skip>
|
||||
<rat.skip>true</rat.skip>
|
||||
<jacoco.skip>true</jacoco.skip>
|
||||
|
||||
<maven.deploy.skip>true</maven.deploy.skip>
|
||||
|
||||
<junit_jupiter_version>5.9.0</junit_jupiter_version>
|
||||
<javassist_version>3.29.2-GA</javassist_version>
|
||||
</properties>
|
||||
|
||||
<packaging>jar</packaging>
|
||||
|
||||
<dependencies>
|
||||
<!-- JUnit Jupiter Engine to depend on the JUnit5 engine and JUnit 5 API -->
|
||||
<dependency>
|
||||
<groupId>org.junit.jupiter</groupId>
|
||||
<artifactId>junit-jupiter-engine</artifactId>
|
||||
<version>${junit_jupiter_version}</version>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>org.junit.jupiter</groupId>
|
||||
<artifactId>junit-jupiter-api</artifactId>
|
||||
<version>${junit_jupiter_version}</version>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>org.junit.jupiter</groupId>
|
||||
<artifactId>junit-jupiter-params</artifactId>
|
||||
<version>${junit_jupiter_version}</version>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>org.javassist</groupId>
|
||||
<artifactId>javassist</artifactId>
|
||||
<version>${javassist_version}</version>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
|
||||
<build>
|
||||
<plugins>
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-compiler-plugin</artifactId>
|
||||
<version>3.10.1</version>
|
||||
<configuration>
|
||||
<proc>none</proc>
|
||||
<fork>true</fork>
|
||||
</configuration>
|
||||
</plugin>
|
||||
</plugins>
|
||||
</build>
|
||||
|
||||
<profiles>
|
||||
<profile>
|
||||
<id>default-profile-in-jdk-8</id>
|
||||
<activation>
|
||||
<file>
|
||||
<exists>${java.home}/../lib/tools.jar</exists>
|
||||
</file>
|
||||
<jdk>(, 9)</jdk>
|
||||
</activation>
|
||||
<properties>
|
||||
<toolsjar>${java.home}/../lib/tools.jar</toolsjar>
|
||||
</properties>
|
||||
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>javac</groupId>
|
||||
<artifactId>javac</artifactId>
|
||||
<version>1.0</version>
|
||||
<scope>system</scope>
|
||||
<systemPath>${toolsjar}</systemPath>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
</profile>
|
||||
|
||||
<profile>
|
||||
<id>legacy-apple-jdk-profile</id>
|
||||
<activation>
|
||||
<activeByDefault>false</activeByDefault>
|
||||
<file>
|
||||
<exists>${java.home}/../Classes/classes.jar</exists>
|
||||
</file>
|
||||
<jdk>(, 9)</jdk>
|
||||
</activation>
|
||||
|
||||
<properties>
|
||||
<toolsjar>${java.home}/../Classes/classes.jar</toolsjar>
|
||||
</properties>
|
||||
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>javac</groupId>
|
||||
<artifactId>javac</artifactId>
|
||||
<version>1.0</version>
|
||||
<scope>system</scope>
|
||||
<systemPath>${toolsjar}</systemPath>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
</profile>
|
||||
|
||||
<profile>
|
||||
<id>add-export-greater-than-9</id>
|
||||
<activation>
|
||||
<activeByDefault>false</activeByDefault>
|
||||
<jdk>[9, )</jdk>
|
||||
</activation>
|
||||
|
||||
<build>
|
||||
<plugins>
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-compiler-plugin</artifactId>
|
||||
<version>3.10.1</version>
|
||||
<configuration>
|
||||
<fork>true</fork>
|
||||
<proc>none</proc>
|
||||
</configuration>
|
||||
</plugin>
|
||||
</plugins>
|
||||
</build>
|
||||
</profile>
|
||||
</profiles>
|
||||
|
||||
</project>
|
||||
|
|
@ -0,0 +1,44 @@
|
|||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
* contributor license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright ownership.
|
||||
* The ASF licenses this file to You under the Apache License, Version 2.0
|
||||
* (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.apache.dubbo.annotation;
|
||||
|
||||
import javax.lang.model.element.Element;
|
||||
import java.lang.annotation.Annotation;
|
||||
import java.util.Set;
|
||||
|
||||
/**
|
||||
* Represents an annotation processing handler, which is invoked by DispatchingAnnotationProcessor.
|
||||
*/
|
||||
public interface AnnotationProcessingHandler {
|
||||
|
||||
/**
|
||||
* Set the annotations that this handler will handle.
|
||||
*
|
||||
* @return annotations to handle
|
||||
*/
|
||||
Set<Class<? extends Annotation>> getAnnotationsToHandle();
|
||||
|
||||
/**
|
||||
* Formal processing method.
|
||||
*
|
||||
* @param elements the elements that annotated by the annotations of getAnnotationsToHandle()
|
||||
* @param annotationProcessorContext the annotation processor context object (Javac object encapsulation)
|
||||
*/
|
||||
void process(Set<Element> elements,
|
||||
AnnotationProcessorContext annotationProcessorContext);
|
||||
}
|
||||
|
|
@ -0,0 +1,139 @@
|
|||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
* contributor license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright ownership.
|
||||
* The ASF licenses this file to You under the Apache License, Version 2.0
|
||||
* (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.apache.dubbo.annotation;
|
||||
|
||||
import com.sun.source.util.Trees;
|
||||
import com.sun.tools.javac.api.JavacTrees;
|
||||
import com.sun.tools.javac.processing.JavacProcessingEnvironment;
|
||||
import com.sun.tools.javac.tree.TreeMaker;
|
||||
import com.sun.tools.javac.util.Context;
|
||||
import com.sun.tools.javac.util.Names;
|
||||
|
||||
import javax.annotation.processing.ProcessingEnvironment;
|
||||
import java.lang.reflect.Method;
|
||||
import java.util.Objects;
|
||||
|
||||
/**
|
||||
* The Context Object of Annotation Processor, which stores objects related to javac.
|
||||
*/
|
||||
public class AnnotationProcessorContext {
|
||||
private JavacProcessingEnvironment javacProcessingEnvironment;
|
||||
private JavacTrees javacTrees;
|
||||
private TreeMaker treeMaker;
|
||||
private Names names;
|
||||
private Context javacContext;
|
||||
private Trees trees;
|
||||
|
||||
private AnnotationProcessorContext() { }
|
||||
|
||||
private static <T> T jbUnwrap(Class<? extends T> iface, T wrapper) {
|
||||
T unwrapped = null;
|
||||
try {
|
||||
final Class<?> apiWrappers = wrapper.getClass().getClassLoader().loadClass("org.jetbrains.jps.javac.APIWrappers");
|
||||
final Method unwrapMethod = apiWrappers.getDeclaredMethod("unwrap", Class.class, Object.class);
|
||||
unwrapped = iface.cast(unwrapMethod.invoke(null, iface, wrapper));
|
||||
} catch (Throwable ignored) {
|
||||
}
|
||||
|
||||
return unwrapped != null ? unwrapped : wrapper;
|
||||
}
|
||||
|
||||
public static AnnotationProcessorContext fromProcessingEnvironment(ProcessingEnvironment processingEnv) {
|
||||
AnnotationProcessorContext apContext = new AnnotationProcessorContext();
|
||||
|
||||
Object procEnvToUnwrap = processingEnv.getClass() == JavacProcessingEnvironment.class ?
|
||||
processingEnv : jbUnwrap(JavacProcessingEnvironment.class, processingEnv);
|
||||
|
||||
JavacProcessingEnvironment jcProcessingEnvironment = (JavacProcessingEnvironment) procEnvToUnwrap;
|
||||
|
||||
Context context = jcProcessingEnvironment.getContext();
|
||||
|
||||
apContext.javacProcessingEnvironment = jcProcessingEnvironment;
|
||||
|
||||
apContext.javacContext = context;
|
||||
apContext.javacTrees = JavacTrees.instance(jcProcessingEnvironment);
|
||||
apContext.treeMaker = TreeMaker.instance(context);
|
||||
apContext.names = Names.instance(context);
|
||||
|
||||
apContext.trees = Trees.instance(jcProcessingEnvironment);
|
||||
|
||||
return apContext;
|
||||
}
|
||||
|
||||
// Auto-generated methods.
|
||||
|
||||
public JavacTrees getJavacTrees() {
|
||||
return javacTrees;
|
||||
}
|
||||
|
||||
public TreeMaker getTreeMaker() {
|
||||
return treeMaker;
|
||||
}
|
||||
|
||||
public Names getNames() {
|
||||
return names;
|
||||
}
|
||||
|
||||
public Context getJavacContext() {
|
||||
return javacContext;
|
||||
}
|
||||
|
||||
public Trees getTrees() {
|
||||
return trees;
|
||||
}
|
||||
|
||||
public JavacProcessingEnvironment getJavacProcessingEnvironment() {
|
||||
return javacProcessingEnvironment;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object o) {
|
||||
if (this == o) return true;
|
||||
if (o == null || getClass() != o.getClass()) return false;
|
||||
|
||||
AnnotationProcessorContext context = (AnnotationProcessorContext) o;
|
||||
|
||||
if (!Objects.equals(javacTrees, context.javacTrees)) return false;
|
||||
if (!Objects.equals(treeMaker, context.treeMaker)) return false;
|
||||
if (!Objects.equals(names, context.names)) return false;
|
||||
if (!Objects.equals(javacContext, context.javacContext))
|
||||
return false;
|
||||
return Objects.equals(trees, context.trees);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
int result = javacTrees != null ? javacTrees.hashCode() : 0;
|
||||
result = 31 * result + (treeMaker != null ? treeMaker.hashCode() : 0);
|
||||
result = 31 * result + (names != null ? names.hashCode() : 0);
|
||||
result = 31 * result + (javacContext != null ? javacContext.hashCode() : 0);
|
||||
result = 31 * result + (trees != null ? trees.hashCode() : 0);
|
||||
return result;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "AnnotationProcessorContext{" +
|
||||
"javacTrees=" + javacTrees +
|
||||
", treeMaker=" + treeMaker +
|
||||
", names=" + names +
|
||||
", javacContext=" + javacContext +
|
||||
", trees=" + trees +
|
||||
'}';
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,162 @@
|
|||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
* contributor license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright ownership.
|
||||
* The ASF licenses this file to You under the Apache License, Version 2.0
|
||||
* (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.apache.dubbo.annotation;
|
||||
|
||||
import org.apache.dubbo.annotation.permit.Permit;
|
||||
import org.apache.dubbo.annotation.util.FileUtils;
|
||||
|
||||
import com.sun.tools.javac.code.Symbol;
|
||||
import com.sun.tools.javac.processing.JavacRoundEnvironment;
|
||||
|
||||
import javax.annotation.processing.AbstractProcessor;
|
||||
import javax.annotation.processing.ProcessingEnvironment;
|
||||
import javax.annotation.processing.RoundEnvironment;
|
||||
import javax.annotation.processing.SupportedAnnotationTypes;
|
||||
import javax.lang.model.SourceVersion;
|
||||
import javax.lang.model.element.Element;
|
||||
import javax.lang.model.element.TypeElement;
|
||||
import javax.tools.Diagnostic;
|
||||
import java.lang.annotation.Annotation;
|
||||
import java.lang.reflect.Constructor;
|
||||
import java.lang.reflect.InvocationTargetException;
|
||||
import java.lang.reflect.Method;
|
||||
import java.util.Collections;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
/**
|
||||
* Dispatching annotation processor, which uses a file to locate handlers and invoke them.
|
||||
*/
|
||||
@SupportedAnnotationTypes("*")
|
||||
public class DispatchingAnnotationProcessor extends AbstractProcessor {
|
||||
|
||||
private static Set<AnnotationProcessingHandler> handlers;
|
||||
|
||||
private static Set<AnnotationProcessingHandler> loadHandlers() {
|
||||
List<String> classNames = FileUtils.loadConfigurationFileInResources("handlers.cfg");
|
||||
Set<AnnotationProcessingHandler> tempHandlers = new HashSet<>();
|
||||
|
||||
for (String clsName : classNames) {
|
||||
try {
|
||||
Class<? extends AnnotationProcessingHandler> cls = (Class<? extends AnnotationProcessingHandler>) Class.forName(clsName);
|
||||
AnnotationProcessingHandler r = cls.getConstructor().newInstance();
|
||||
|
||||
tempHandlers.add(r);
|
||||
|
||||
} catch (InstantiationException | NoSuchMethodException | InvocationTargetException |
|
||||
IllegalAccessException | ClassNotFoundException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
|
||||
return Collections.unmodifiableSet(tempHandlers);
|
||||
}
|
||||
|
||||
private AnnotationProcessorContext apContext;
|
||||
|
||||
@Override
|
||||
public synchronized void init(ProcessingEnvironment processingEnv) {
|
||||
Permit.addOpens();
|
||||
super.init(processingEnv);
|
||||
|
||||
if (processingEnv.getClass().getName().startsWith("org.eclipse.jdt.")) {
|
||||
// Don't run on ECJ, since this processor is javac based.
|
||||
processingEnv
|
||||
.getMessager()
|
||||
.printMessage(Diagnostic.Kind.WARNING, "The Annotation processor doesn't support ECJ.");
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
if (handlers == null) {
|
||||
handlers = loadHandlers();
|
||||
}
|
||||
|
||||
apContext = AnnotationProcessorContext.fromProcessingEnvironment(processingEnv);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean process(Set<? extends TypeElement> annotations, RoundEnvironment roundEnv) {
|
||||
|
||||
if (processingEnv.getClass().getName().startsWith("org.eclipse.jdt.")) {
|
||||
// Don't run on ECJ, since this processor is javac based.
|
||||
return false;
|
||||
}
|
||||
|
||||
for (AnnotationProcessingHandler i : handlers) {
|
||||
Set<Element> elements = new HashSet<>(16);
|
||||
|
||||
for (Class<? extends Annotation> annotationClass : i.getAnnotationsToHandle()) {
|
||||
elements.addAll(getElementsAnnotatedWith(annotationClass, roundEnv));
|
||||
}
|
||||
|
||||
i.process(elements, apContext);
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* A hack to make comment only .java file pass the compilation by skipping package symbol scan.
|
||||
*
|
||||
* @param annotationClass the annotation class to find
|
||||
* @param roundEnvironment the javac's round environment
|
||||
* @return the elements annotated with specified annotation
|
||||
*/
|
||||
private Set<? extends Element> getElementsAnnotatedWith(Class<? extends Annotation> annotationClass, RoundEnvironment roundEnvironment) {
|
||||
|
||||
TypeElement a = processingEnv.getElementUtils().getTypeElement(annotationClass.getCanonicalName());
|
||||
|
||||
// Detect the Javac's version.
|
||||
if (Integer.parseInt(SourceVersion.latest().name().split("_")[1]) > 8) {
|
||||
return roundEnvironment.getElementsAnnotatedWith(a);
|
||||
}
|
||||
|
||||
Set<Element> result = Collections.emptySet();
|
||||
|
||||
try {
|
||||
Class annotationSetScannerClass = Class.forName("com.sun.tools.javac.processing.JavacRoundEnvironment$AnnotationSetScanner");
|
||||
Constructor scannerConstructor = Permit.getConstructor(annotationSetScannerClass, JavacRoundEnvironment.class, Set.class);
|
||||
Object scanner = scannerConstructor.newInstance(roundEnvironment, result);
|
||||
|
||||
Set<? extends Element> rootElements1 = roundEnvironment
|
||||
.getRootElements()
|
||||
.stream()
|
||||
.filter(x -> x.getClass() != Symbol.PackageSymbol.class)
|
||||
.collect(Collectors.toSet());
|
||||
|
||||
for (Element element : rootElements1) {
|
||||
Method scanningMethod = Permit.getMethod(annotationSetScannerClass, "scan", Element.class, TypeElement.class);
|
||||
result = (Set<Element>) scanningMethod.invoke(scanner, element, a);
|
||||
}
|
||||
|
||||
} catch (InstantiationException | NoSuchMethodException | ClassNotFoundException | InvocationTargetException |
|
||||
IllegalAccessException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
@Override
|
||||
public SourceVersion getSupportedSourceVersion() {
|
||||
return SourceVersion.latestSupported();
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,110 @@
|
|||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
* contributor license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright ownership.
|
||||
* The ASF licenses this file to You under the Apache License, Version 2.0
|
||||
* (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.apache.dubbo.annotation.handler;
|
||||
|
||||
import org.apache.dubbo.annotation.AnnotationProcessingHandler;
|
||||
import org.apache.dubbo.annotation.AnnotationProcessorContext;
|
||||
import org.apache.dubbo.annotation.util.ASTUtils;
|
||||
|
||||
import com.sun.tools.javac.code.Symbol;
|
||||
import com.sun.tools.javac.tree.JCTree;
|
||||
import com.sun.tools.javac.tree.TreeTranslator;
|
||||
|
||||
import javax.lang.model.element.Element;
|
||||
import java.lang.annotation.Annotation;
|
||||
import java.util.Collections;
|
||||
import java.util.HashSet;
|
||||
import java.util.Set;
|
||||
|
||||
/**
|
||||
* Handles @Deprecated annotation and adds logger warn call to the methods that are annotated with it.
|
||||
*/
|
||||
public class DeprecatedHandler implements AnnotationProcessingHandler {
|
||||
|
||||
@Override
|
||||
public Set<Class<? extends Annotation>> getAnnotationsToHandle() {
|
||||
return new HashSet<>(
|
||||
Collections.singletonList(Deprecated.class)
|
||||
);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void process(Set<Element> elements, AnnotationProcessorContext apContext) {
|
||||
for (Element element : elements) {
|
||||
// Only interested in methods.
|
||||
if (!(element instanceof Symbol.MethodSymbol)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
Symbol.ClassSymbol classSymbol = (Symbol.ClassSymbol) element.getEnclosingElement();
|
||||
|
||||
ASTUtils.addImportStatement(apContext, classSymbol, "org.apache.dubbo.common", "DeprecatedMethodInvocationCounter");
|
||||
|
||||
JCTree methodTree = apContext.getJavacTrees().getTree(element);
|
||||
|
||||
methodTree.accept(new TreeTranslator() {
|
||||
@Override
|
||||
public void visitMethodDef(JCTree.JCMethodDecl jcMethodDecl) {
|
||||
|
||||
JCTree.JCBlock block = jcMethodDecl.body;
|
||||
|
||||
if (block == null) {
|
||||
// No method body. (i.e. interface method declaration.)
|
||||
return;
|
||||
}
|
||||
|
||||
ASTUtils.insertStatementToHeadOfMethod(block, jcMethodDecl, generateCounterStatement(apContext, classSymbol, jcMethodDecl));
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Generate an expression statement like this:
|
||||
* <code>DeprecatedMethodInvocationCounter.onDeprecatedMethodCalled("....");
|
||||
*
|
||||
* @param originalMethodDecl the method declaration that will add logger statement
|
||||
* @param apContext annotation processor context
|
||||
* @param classSymbol the enclosing class that will be the logger's name
|
||||
* @return generated expression statement
|
||||
*/
|
||||
private JCTree.JCExpressionStatement generateCounterStatement(AnnotationProcessorContext apContext,
|
||||
Symbol.ClassSymbol classSymbol,
|
||||
JCTree.JCMethodDecl originalMethodDecl) {
|
||||
|
||||
JCTree.JCExpression fullStatement = apContext.getTreeMaker().Apply(
|
||||
com.sun.tools.javac.util.List.nil(),
|
||||
|
||||
apContext.getTreeMaker().Select(
|
||||
apContext.getTreeMaker().Ident(apContext.getNames().fromString("DeprecatedMethodInvocationCounter")),
|
||||
apContext.getNames().fromString("onDeprecatedMethodCalled")
|
||||
),
|
||||
|
||||
com.sun.tools.javac.util.List.of(
|
||||
apContext.getTreeMaker().Literal(getMethodDefinition(classSymbol, originalMethodDecl))
|
||||
)
|
||||
);
|
||||
|
||||
return apContext.getTreeMaker().Exec(fullStatement);
|
||||
}
|
||||
|
||||
private String getMethodDefinition(Symbol.ClassSymbol classSymbol, JCTree.JCMethodDecl originalMethodDecl) {
|
||||
return classSymbol.getQualifiedName() + "."
|
||||
+ originalMethodDecl.name.toString() + "(" + originalMethodDecl.params.toString() + ")";
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,429 @@
|
|||
/*
|
||||
* Authored by Project Lombok and licensed by MIT License, which is attached below:
|
||||
*
|
||||
* Copyright (C) 2018-2021 The Project Lombok Authors.
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
*/
|
||||
|
||||
package org.apache.dubbo.annotation.permit;
|
||||
|
||||
import org.apache.dubbo.annotation.permit.dummy.Parent;
|
||||
|
||||
import sun.misc.Unsafe;
|
||||
|
||||
import java.lang.reflect.AccessibleObject;
|
||||
import java.lang.reflect.Constructor;
|
||||
import java.lang.reflect.Field;
|
||||
import java.lang.reflect.InvocationTargetException;
|
||||
import java.lang.reflect.Method;
|
||||
|
||||
// sunapi suppresses javac's warning about using Unsafe; 'all' suppresses eclipse's warning about the unspecified 'sunapi' key. Leave them both.
|
||||
// Yes, javac's definition of the word 'all' is quite contrary to what the dictionary says it means. 'all' does NOT include 'sunapi' according to javac.
|
||||
@SuppressWarnings({"sunapi", "all"})
|
||||
public class Permit {
|
||||
private Permit() {
|
||||
}
|
||||
|
||||
|
||||
private static final long ACCESSIBLE_OVERRIDE_FIELD_OFFSET;
|
||||
private static final IllegalAccessException INIT_ERROR;
|
||||
private static final sun.misc.Unsafe UNSAFE = (sun.misc.Unsafe) reflectiveStaticFieldAccess(sun.misc.Unsafe.class, "theUnsafe");
|
||||
|
||||
static {
|
||||
Field f;
|
||||
long g;
|
||||
Throwable ex;
|
||||
|
||||
try {
|
||||
g = getOverrideFieldOffset();
|
||||
ex = null;
|
||||
} catch (Throwable t) {
|
||||
f = null;
|
||||
g = -1L;
|
||||
ex = t;
|
||||
}
|
||||
|
||||
ACCESSIBLE_OVERRIDE_FIELD_OFFSET = g;
|
||||
if (ex == null) INIT_ERROR = null;
|
||||
else if (ex instanceof IllegalAccessException) INIT_ERROR = (IllegalAccessException) ex;
|
||||
else {
|
||||
INIT_ERROR = new IllegalAccessException("Cannot initialize Unsafe-based permit");
|
||||
INIT_ERROR.initCause(ex);
|
||||
}
|
||||
}
|
||||
|
||||
public static <T extends AccessibleObject> T setAccessible(T accessor) {
|
||||
if (INIT_ERROR == null) {
|
||||
UNSAFE.putBoolean(accessor, ACCESSIBLE_OVERRIDE_FIELD_OFFSET, true);
|
||||
} else {
|
||||
accessor.setAccessible(true);
|
||||
}
|
||||
|
||||
return accessor;
|
||||
}
|
||||
|
||||
private static long getOverrideFieldOffset() throws Throwable {
|
||||
Field f = null;
|
||||
Throwable saved = null;
|
||||
try {
|
||||
f = AccessibleObject.class.getDeclaredField("override");
|
||||
} catch (Throwable t) {
|
||||
saved = t;
|
||||
}
|
||||
|
||||
if (f != null) {
|
||||
return UNSAFE.objectFieldOffset(f);
|
||||
}
|
||||
// The below seems very risky, but for all AccessibleObjects in java today it does work, and starting with JDK12, making the field accessible is no longer possible.
|
||||
try {
|
||||
return UNSAFE.objectFieldOffset(Fake.class.getDeclaredField("override"));
|
||||
} catch (Throwable t) {
|
||||
throw saved;
|
||||
}
|
||||
}
|
||||
|
||||
static class Fake {
|
||||
boolean override;
|
||||
Object accessCheckCache;
|
||||
}
|
||||
|
||||
public static Method getMethod(Class<?> c, String mName, Class<?>... parameterTypes) throws NoSuchMethodException {
|
||||
Method m = null;
|
||||
Class<?> oc = c;
|
||||
while (c != null) {
|
||||
try {
|
||||
m = c.getDeclaredMethod(mName, parameterTypes);
|
||||
break;
|
||||
} catch (NoSuchMethodException e) {
|
||||
}
|
||||
c = c.getSuperclass();
|
||||
}
|
||||
|
||||
if (m == null) throw new NoSuchMethodException(oc.getName() + " :: " + mName + "(args)");
|
||||
return setAccessible(m);
|
||||
}
|
||||
|
||||
public static Method permissiveGetMethod(Class<?> c, String mName, Class<?>... parameterTypes) {
|
||||
try {
|
||||
return getMethod(c, mName, parameterTypes);
|
||||
} catch (Exception ignore) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
public static Field getField(Class<?> c, String fName) throws NoSuchFieldException {
|
||||
Field f = null;
|
||||
Class<?> oc = c;
|
||||
while (c != null) {
|
||||
try {
|
||||
f = c.getDeclaredField(fName);
|
||||
break;
|
||||
} catch (NoSuchFieldException e) {
|
||||
}
|
||||
c = c.getSuperclass();
|
||||
}
|
||||
|
||||
if (f == null) throw new NoSuchFieldException(oc.getName() + " :: " + fName);
|
||||
|
||||
return setAccessible(f);
|
||||
}
|
||||
|
||||
public static Field permissiveGetField(Class<?> c, String fName) {
|
||||
try {
|
||||
return getField(c, fName);
|
||||
} catch (Exception ignore) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
public static <T> T permissiveReadField(Class<T> type, Field f, Object instance) {
|
||||
try {
|
||||
return type.cast(f.get(instance));
|
||||
} catch (Exception ignore) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
public static <T> Constructor<T> getConstructor(Class<T> c, Class<?>... parameterTypes) throws NoSuchMethodException {
|
||||
return setAccessible(c.getDeclaredConstructor(parameterTypes));
|
||||
}
|
||||
|
||||
private static Object reflectiveStaticFieldAccess(Class<?> c, String fName) {
|
||||
try {
|
||||
Field f = c.getDeclaredField(fName);
|
||||
f.setAccessible(true);
|
||||
return f.get(null);
|
||||
} catch (Exception e) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
public static boolean isDebugReflection() {
|
||||
return !"false".equals(System.getProperty("lombok.debug.reflection", "false"));
|
||||
}
|
||||
|
||||
public static void handleReflectionDebug(Throwable t, Throwable initError) {
|
||||
if (!isDebugReflection()) return;
|
||||
|
||||
System.err.println("** LOMBOK REFLECTION exception: " + t.getClass() + ": " + (t.getMessage() == null ? "(no message)" : t.getMessage()));
|
||||
t.printStackTrace(System.err);
|
||||
if (initError != null) {
|
||||
System.err.println("*** ADDITIONALLY, exception occurred setting up reflection: ");
|
||||
initError.printStackTrace(System.err);
|
||||
}
|
||||
}
|
||||
|
||||
public static Object invoke(Method m, Object receiver, Object... args) throws IllegalAccessException, InvocationTargetException {
|
||||
return invoke(null, m, receiver, args);
|
||||
}
|
||||
|
||||
public static Object invoke(Throwable initError, Method m, Object receiver, Object... args) throws IllegalAccessException, InvocationTargetException {
|
||||
try {
|
||||
return m.invoke(receiver, args);
|
||||
} catch (IllegalAccessException e) {
|
||||
handleReflectionDebug(e, initError);
|
||||
throw e;
|
||||
} catch (RuntimeException e) {
|
||||
handleReflectionDebug(e, initError);
|
||||
throw e;
|
||||
} catch (Error e) {
|
||||
handleReflectionDebug(e, initError);
|
||||
throw e;
|
||||
}
|
||||
}
|
||||
|
||||
public static Object invokeSneaky(Method m, Object receiver, Object... args) {
|
||||
return invokeSneaky(null, m, receiver, args);
|
||||
}
|
||||
|
||||
public static Object invokeSneaky(Throwable initError, Method m, Object receiver, Object... args) {
|
||||
try {
|
||||
return m.invoke(receiver, args);
|
||||
} catch (NoClassDefFoundError e) {
|
||||
handleReflectionDebug(e, initError);
|
||||
//ignore, we don't have access to the correct ECJ classes, so lombok can't possibly
|
||||
//do anything useful here.
|
||||
return null;
|
||||
} catch (NullPointerException e) {
|
||||
handleReflectionDebug(e, initError);
|
||||
//ignore, we don't have access to the correct ECJ classes, so lombok can't possibly
|
||||
//do anything useful here.
|
||||
return null;
|
||||
} catch (IllegalAccessException e) {
|
||||
handleReflectionDebug(e, initError);
|
||||
throw sneakyThrow(e);
|
||||
} catch (InvocationTargetException e) {
|
||||
throw sneakyThrow(e.getCause());
|
||||
} catch (RuntimeException e) {
|
||||
handleReflectionDebug(e, initError);
|
||||
throw e;
|
||||
} catch (Error e) {
|
||||
handleReflectionDebug(e, initError);
|
||||
throw e;
|
||||
}
|
||||
}
|
||||
|
||||
public static <T> T newInstance(Constructor<T> c, Object... args) throws IllegalAccessException, InvocationTargetException, InstantiationException {
|
||||
return newInstance(null, c, args);
|
||||
}
|
||||
|
||||
public static <T> T newInstance(Throwable initError, Constructor<T> c, Object... args) throws IllegalAccessException, InvocationTargetException, InstantiationException {
|
||||
try {
|
||||
return c.newInstance(args);
|
||||
} catch (IllegalAccessException e) {
|
||||
handleReflectionDebug(e, initError);
|
||||
throw e;
|
||||
} catch (InstantiationException e) {
|
||||
handleReflectionDebug(e, initError);
|
||||
throw e;
|
||||
} catch (RuntimeException e) {
|
||||
handleReflectionDebug(e, initError);
|
||||
throw e;
|
||||
} catch (Error e) {
|
||||
handleReflectionDebug(e, initError);
|
||||
throw e;
|
||||
}
|
||||
}
|
||||
|
||||
public static <T> T newInstanceSneaky(Constructor<T> c, Object... args) {
|
||||
return newInstanceSneaky(null, c, args);
|
||||
}
|
||||
|
||||
public static <T> T newInstanceSneaky(Throwable initError, Constructor<T> c, Object... args) {
|
||||
try {
|
||||
return c.newInstance(args);
|
||||
} catch (NoClassDefFoundError e) {
|
||||
handleReflectionDebug(e, initError);
|
||||
//ignore, we don't have access to the correct ECJ classes, so lombok can't possibly
|
||||
//do anything useful here.
|
||||
return null;
|
||||
} catch (NullPointerException e) {
|
||||
handleReflectionDebug(e, initError);
|
||||
//ignore, we don't have access to the correct ECJ classes, so lombok can't possibly
|
||||
//do anything useful here.
|
||||
return null;
|
||||
} catch (IllegalAccessException e) {
|
||||
handleReflectionDebug(e, initError);
|
||||
throw sneakyThrow(e);
|
||||
} catch (InstantiationException e) {
|
||||
handleReflectionDebug(e, initError);
|
||||
throw sneakyThrow(e);
|
||||
} catch (InvocationTargetException e) {
|
||||
throw sneakyThrow(e.getCause());
|
||||
} catch (RuntimeException e) {
|
||||
handleReflectionDebug(e, initError);
|
||||
throw e;
|
||||
} catch (Error e) {
|
||||
handleReflectionDebug(e, initError);
|
||||
throw e;
|
||||
}
|
||||
}
|
||||
|
||||
public static Object get(Field f, Object receiver) throws IllegalAccessException {
|
||||
try {
|
||||
return f.get(receiver);
|
||||
} catch (IllegalAccessException e) {
|
||||
handleReflectionDebug(e, null);
|
||||
throw e;
|
||||
} catch (RuntimeException e) {
|
||||
handleReflectionDebug(e, null);
|
||||
throw e;
|
||||
} catch (Error e) {
|
||||
handleReflectionDebug(e, null);
|
||||
throw e;
|
||||
}
|
||||
}
|
||||
|
||||
public static void set(Field f, Object receiver, Object newValue) throws IllegalAccessException {
|
||||
try {
|
||||
f.set(receiver, newValue);
|
||||
} catch (IllegalAccessException e) {
|
||||
handleReflectionDebug(e, null);
|
||||
throw e;
|
||||
} catch (RuntimeException e) {
|
||||
handleReflectionDebug(e, null);
|
||||
throw e;
|
||||
} catch (Error e) {
|
||||
handleReflectionDebug(e, null);
|
||||
throw e;
|
||||
}
|
||||
}
|
||||
|
||||
public static void reportReflectionProblem(Throwable initError, String msg) {
|
||||
if (!isDebugReflection()) return;
|
||||
System.err.println("** LOMBOK REFLECTION issue: " + msg);
|
||||
if (initError != null) {
|
||||
System.err.println("*** ADDITIONALLY, exception occurred setting up reflection: ");
|
||||
initError.printStackTrace(System.err);
|
||||
}
|
||||
}
|
||||
|
||||
public static RuntimeException sneakyThrow(Throwable t) {
|
||||
if (t == null) throw new NullPointerException("t");
|
||||
return Permit.<RuntimeException>sneakyThrow0(t);
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
private static <T extends Throwable> T sneakyThrow0(Throwable t) throws T {
|
||||
throw (T) t;
|
||||
}
|
||||
|
||||
private static Object getJdkCompilerModule() {
|
||||
/* call public api: ModuleLayer.boot().findModule("jdk.compiler").get();
|
||||
but use reflection because we don't want this code to crash on jdk1.7 and below.
|
||||
In that case, none of this stuff was needed in the first place, so we just exit via
|
||||
the catch block and do nothing.
|
||||
*/
|
||||
|
||||
try {
|
||||
Class<?> cModuleLayer = Class.forName("java.lang.ModuleLayer");
|
||||
Method mBoot = cModuleLayer.getDeclaredMethod("boot");
|
||||
Object bootLayer = mBoot.invoke(null);
|
||||
Class<?> cOptional = Class.forName("java.util.Optional");
|
||||
Method mFindModule = cModuleLayer.getDeclaredMethod("findModule", String.class);
|
||||
Object oCompilerO = mFindModule.invoke(bootLayer, "jdk.compiler");
|
||||
return cOptional.getDeclaredMethod("get").invoke(oCompilerO);
|
||||
} catch (Exception e) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
private static Object getOwnModule() {
|
||||
try {
|
||||
Method m = Permit.getMethod(Class.class, "getModule");
|
||||
return m.invoke(Permit.class);
|
||||
} catch (Exception e) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
private static long getFirstFieldOffset(Unsafe unsafe) {
|
||||
try {
|
||||
return unsafe.objectFieldOffset(Parent.class.getDeclaredField("first"));
|
||||
} catch (NoSuchFieldException e) {
|
||||
// can't happen.
|
||||
throw new RuntimeException(e);
|
||||
} catch (SecurityException e) {
|
||||
// can't happen
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
|
||||
public static void addOpens() {
|
||||
Class<?> cModule;
|
||||
try {
|
||||
cModule = Class.forName("java.lang.Module");
|
||||
} catch (ClassNotFoundException e) {
|
||||
return; //jdk8-; this is not needed.
|
||||
}
|
||||
|
||||
Unsafe unsafe = UNSAFE;
|
||||
|
||||
Object jdkCompilerModule = getJdkCompilerModule();
|
||||
Object ownModule = getOwnModule();
|
||||
String[] allPkgs = {
|
||||
"com.sun.tools.javac.code",
|
||||
"com.sun.tools.javac.comp",
|
||||
"com.sun.tools.javac.file",
|
||||
"com.sun.tools.javac.main",
|
||||
"com.sun.tools.javac.model",
|
||||
"com.sun.tools.javac.parser",
|
||||
"com.sun.tools.javac.processing",
|
||||
"com.sun.tools.javac.tree",
|
||||
"com.sun.tools.javac.util",
|
||||
"com.sun.tools.javac.jvm",
|
||||
"com.sun.tools.javac.api"
|
||||
};
|
||||
|
||||
try {
|
||||
Method m = cModule.getDeclaredMethod("implAddOpens", String.class, cModule);
|
||||
long firstFieldOffset = getFirstFieldOffset(unsafe);
|
||||
unsafe.putBooleanVolatile(m, firstFieldOffset, true);
|
||||
for (String p : allPkgs) m.invoke(jdkCompilerModule, p, ownModule);
|
||||
} catch (Exception ignore) {}
|
||||
|
||||
try {
|
||||
Method m = cModule.getDeclaredMethod("implAddExports", String.class, cModule);
|
||||
long firstFieldOffset = getFirstFieldOffset(unsafe);
|
||||
unsafe.putBooleanVolatile(m, firstFieldOffset, true);
|
||||
for (String p : allPkgs) m.invoke(jdkCompilerModule, p, ownModule);
|
||||
} catch (Exception ignore) {}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,33 @@
|
|||
/*
|
||||
* Authored by Project Lombok and licensed by MIT License, which is attached below:
|
||||
*
|
||||
* Copyright (C) 2018-2021 The Project Lombok Authors.
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
*/
|
||||
|
||||
package org.apache.dubbo.annotation.permit.dummy;
|
||||
|
||||
@SuppressWarnings("all")
|
||||
public abstract class Child extends Parent {
|
||||
private transient volatile boolean foo;
|
||||
private transient volatile Object[] bar;
|
||||
private transient volatile Object baz;
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,43 @@
|
|||
/*
|
||||
* Authored by Project Lombok and licensed by MIT License, which is attached below:
|
||||
*
|
||||
* Copyright (C) 2018-2021 The Project Lombok Authors.
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
*/
|
||||
|
||||
package org.apache.dubbo.annotation.permit.dummy;
|
||||
|
||||
@SuppressWarnings("all")
|
||||
public final class GrandChild extends Child {
|
||||
private Class<?> a;
|
||||
private int b;
|
||||
private String c;
|
||||
private Class<?> d;
|
||||
private Class<?>[] e;
|
||||
private Class<?>[] f;
|
||||
private int g;
|
||||
private transient String h;
|
||||
private transient Object i;
|
||||
private byte[] j;
|
||||
private byte[] k;
|
||||
private byte[] l;
|
||||
private volatile Object m;
|
||||
private Object n;
|
||||
}
|
||||
|
|
@ -0,0 +1,36 @@
|
|||
/*
|
||||
* Authored by Project Lombok and licensed by MIT License, which is attached below:
|
||||
*
|
||||
* Copyright (C) 2018-2021 The Project Lombok Authors.
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
*/
|
||||
|
||||
package org.apache.dubbo.annotation.permit.dummy;
|
||||
|
||||
import java.io.OutputStream;
|
||||
|
||||
@SuppressWarnings("all")
|
||||
public class Parent {
|
||||
boolean first;
|
||||
static final Object staticObj = OutputStream.class;
|
||||
volatile Object second;
|
||||
private static volatile boolean staticSecond;
|
||||
private static volatile boolean staticThird;
|
||||
}
|
||||
|
|
@ -0,0 +1,32 @@
|
|||
/*
|
||||
* Authored by Project Lombok and licensed by MIT License, which is attached below:
|
||||
*
|
||||
* Copyright (C) 2018-2021 The Project Lombok Authors.
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
*/
|
||||
|
||||
/**
|
||||
* This package recreates the type hierarchy of {@code java.lang.reflect.AccessibleObject} and friends (such as {@code java.lang.reflect.Method});
|
||||
* its purpose is to allow us to ask {@code sun.misc.internal.Unsafe} about the exact offset of the {@code override} field of {@code AccessibleObject};
|
||||
* asking about that field directly doesn't work after jdk14, presumably because the fields of AO are expressly hidden somehow.
|
||||
* <p>
|
||||
* NB: It's usually 12, on the vast majority of OS, VM, and architecture combos.
|
||||
*/
|
||||
package org.apache.dubbo.annotation.permit.dummy;
|
||||
|
|
@ -0,0 +1,32 @@
|
|||
/*
|
||||
* Authored by Project Lombok and licensed by MIT License, which is attached below:
|
||||
*
|
||||
* Copyright (C) 2018-2021 The Project Lombok Authors.
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
*/
|
||||
|
||||
/**
|
||||
* This is a reduced copy of the nqzero Permit-reflect project.
|
||||
* https://github.com/nqzero/permit-reflect
|
||||
* <p>
|
||||
* Many thanks to nqzero. The permit-reflect project is, like lombok itself, licensed under the MIT license.
|
||||
* See https://github.com/nqzero/permit-reflect/blob/master/License for license info.
|
||||
*/
|
||||
package org.apache.dubbo.annotation.permit;
|
||||
|
|
@ -0,0 +1,111 @@
|
|||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
* contributor license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright ownership.
|
||||
* The ASF licenses this file to You under the Apache License, Version 2.0
|
||||
* (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.apache.dubbo.annotation.util;
|
||||
|
||||
import org.apache.dubbo.annotation.AnnotationProcessorContext;
|
||||
|
||||
import com.sun.source.util.TreePath;
|
||||
import com.sun.tools.javac.code.Symbol;
|
||||
import com.sun.tools.javac.tree.JCTree;
|
||||
import com.sun.tools.javac.util.ListBuffer;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* Some utils about AST manipulating.
|
||||
*/
|
||||
public final class ASTUtils {
|
||||
|
||||
private ASTUtils() {
|
||||
throw new UnsupportedOperationException("No instance of 'ASTUtils' for you! ");
|
||||
}
|
||||
|
||||
public static void addImportStatement(AnnotationProcessorContext apContext,
|
||||
Symbol.ClassSymbol classSymbol,
|
||||
String packageName,
|
||||
String className) {
|
||||
|
||||
JCTree.JCImport jcImport = apContext.getTreeMaker().Import(
|
||||
apContext.getTreeMaker().Select(
|
||||
apContext.getTreeMaker().Ident(apContext.getNames().fromString(packageName)),
|
||||
apContext.getNames().fromString(className)
|
||||
), false);
|
||||
|
||||
TreePath treePath = apContext.getTrees().getPath(classSymbol);
|
||||
TreePath parentPath = treePath.getParentPath();
|
||||
JCTree.JCCompilationUnit compilationUnit = (JCTree.JCCompilationUnit) parentPath.getCompilationUnit();
|
||||
|
||||
List<JCTree.JCImport> imports = compilationUnit.getImports();
|
||||
if (imports.stream().noneMatch(x -> x.qualid.toString().contains(packageName + "." + className))) {
|
||||
|
||||
compilationUnit.accept(new JCTree.Visitor() {
|
||||
@Override
|
||||
public void visitTopLevel(JCTree.JCCompilationUnit that) {
|
||||
|
||||
List<JCTree> defs = compilationUnit.defs;
|
||||
|
||||
ListBuffer<JCTree> newDefs = new ListBuffer<>();
|
||||
|
||||
newDefs.add(defs.get(0));
|
||||
newDefs.add(jcImport);
|
||||
newDefs.addAll(defs.subList(1, defs.size()));
|
||||
|
||||
compilationUnit.defs = newDefs.toList();
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Insert statement to head of the method.
|
||||
*
|
||||
* @param block the method body
|
||||
* @param originalMethodDecl the method declaration that will add logger statement
|
||||
* @param fullExpressionStatement the statement to insert.
|
||||
*/
|
||||
public static void insertStatementToHeadOfMethod(JCTree.JCBlock block,
|
||||
JCTree.JCMethodDecl originalMethodDecl,
|
||||
JCTree.JCStatement fullExpressionStatement) {
|
||||
|
||||
boolean isConstructor = originalMethodDecl.name.toString().equals("<init>");
|
||||
ListBuffer<JCTree.JCStatement> statements = new ListBuffer<>();
|
||||
|
||||
// In constructor, super(...) or this(...) should be the first statement.
|
||||
|
||||
if (isConstructor && !block.stats.isEmpty()) {
|
||||
|
||||
boolean startsWithSuper = block.stats.get(0).toString().startsWith("super(");
|
||||
boolean startsWithThis = block.stats.get(0).toString().startsWith("this(");
|
||||
|
||||
if (startsWithSuper || startsWithThis) {
|
||||
statements.add(block.stats.get(0));
|
||||
statements.add(fullExpressionStatement);
|
||||
statements.addAll(block.stats.subList(1, block.stats.size()));
|
||||
} else {
|
||||
statements.add(fullExpressionStatement);
|
||||
statements.addAll(block.stats);
|
||||
}
|
||||
|
||||
} else {
|
||||
statements.add(fullExpressionStatement);
|
||||
statements.addAll(block.stats);
|
||||
}
|
||||
|
||||
block.stats = statements.toList();
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,155 @@
|
|||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
* contributor license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright ownership.
|
||||
* The ASF licenses this file to You under the Apache License, Version 2.0
|
||||
* (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.apache.dubbo.annotation.util;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.nio.ByteBuffer;
|
||||
import java.nio.channels.Channels;
|
||||
import java.nio.channels.FileChannel;
|
||||
import java.nio.channels.ReadableByteChannel;
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.Path;
|
||||
import java.nio.file.Paths;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.Objects;
|
||||
import java.util.Scanner;
|
||||
import java.util.regex.Pattern;
|
||||
import java.util.stream.Collectors;
|
||||
import java.util.stream.Stream;
|
||||
|
||||
/**
|
||||
* Utilities of iterating file.
|
||||
*/
|
||||
public final class FileUtils {
|
||||
|
||||
private static final Pattern WINDOWS_PATH_PATTERN = Pattern.compile("file:/\\w:/.*");
|
||||
|
||||
|
||||
private FileUtils() {
|
||||
throw new UnsupportedOperationException("No instance of FileUtils for you! ");
|
||||
}
|
||||
|
||||
public static List<Path> getAllClassFilePaths(String rootPath) {
|
||||
List<Path> targetFolders;
|
||||
|
||||
try (Stream<Path> filesStream = Files.walk(Paths.get(rootPath))) {
|
||||
targetFolders = filesStream.filter(x -> !x.toFile().isFile())
|
||||
.filter(x -> x.toString().contains("classes") && !x.toString().contains("test-classes"))
|
||||
.filter(x -> x.toString().contains("\\org\\apache\\dubbo".replace('\\', File.separatorChar)))
|
||||
.collect(Collectors.toList());
|
||||
|
||||
return targetFolders;
|
||||
|
||||
} catch (IOException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
|
||||
public static byte[] openFileAsByteArray(String filePath) {
|
||||
try (FileChannel fileChannel = FileChannel.open(Paths.get(filePath))) {
|
||||
|
||||
ByteBuffer byteBuffer = ByteBuffer.allocate((int) fileChannel.size());
|
||||
fileChannel.read(byteBuffer);
|
||||
|
||||
return byteBuffer.array();
|
||||
|
||||
} catch (IOException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
|
||||
public static String openFileAsString(String filePath) {
|
||||
return new String(openFileAsByteArray(filePath));
|
||||
}
|
||||
|
||||
public static String getSourceFilePathFromClassFilePath(String classFilePath) {
|
||||
|
||||
String classesPathString = "\\target\\classes\\".replace("\\", File.separator);
|
||||
String sourcesPathString = "\\src\\main\\java\\".replace("\\", File.separator);
|
||||
|
||||
String sourceFilePathByReplace = classFilePath.replace(classesPathString, sourcesPathString)
|
||||
.replace(".class", ".java");
|
||||
|
||||
// Inner classes.
|
||||
if (sourceFilePathByReplace.lastIndexOf('$') != -1) {
|
||||
int dollarCharIndex = sourceFilePathByReplace.lastIndexOf('$');
|
||||
String outerClassPath = sourceFilePathByReplace.substring(0, dollarCharIndex);
|
||||
|
||||
return outerClassPath + ".java";
|
||||
}
|
||||
|
||||
return sourceFilePathByReplace;
|
||||
}
|
||||
|
||||
public static List<String> loadConfigurationFileInResources(String path) {
|
||||
|
||||
ReadableByteChannel resourceReadableByteChannel = Channels.newChannel(
|
||||
Objects.requireNonNull(FileUtils.class.getClassLoader().getResourceAsStream(path)));
|
||||
|
||||
List<String> lines = new ArrayList<>();
|
||||
|
||||
try (Scanner scanner = new Scanner(resourceReadableByteChannel)) {
|
||||
|
||||
while (scanner.hasNextLine()) {
|
||||
String line = scanner.nextLine().trim();
|
||||
|
||||
if (!line.startsWith("#") && !line.isEmpty()) {
|
||||
lines.add(line);
|
||||
}
|
||||
}
|
||||
|
||||
return lines;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* <p>Get absolute path of resource.
|
||||
*
|
||||
* <p>Retained for testing. It won't work in JAR.
|
||||
*
|
||||
* @param path relative path of resources folder.
|
||||
* @return absolute path of resource
|
||||
*/
|
||||
public static String getResourceFilePath(String path) {
|
||||
String resourceFilePath = FileUtils.class.getClassLoader().getResource(path).toString();
|
||||
|
||||
if (WINDOWS_PATH_PATTERN.matcher(resourceFilePath).matches()) {
|
||||
resourceFilePath = resourceFilePath.replace("file:/", "");
|
||||
} else {
|
||||
resourceFilePath = resourceFilePath.replace("file:", "");
|
||||
}
|
||||
|
||||
return resourceFilePath;
|
||||
}
|
||||
|
||||
public static List<Path> getAllFilesInDirectory(Path targetFolder) {
|
||||
|
||||
try (Stream<Path> classFilesStream = Files.walk(targetFolder)) {
|
||||
|
||||
return classFilesStream
|
||||
.filter(x -> x.toFile().isFile())
|
||||
.collect(Collectors.toList());
|
||||
|
||||
} catch (IOException e) {
|
||||
return Collections.emptyList();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1 @@
|
|||
org.apache.dubbo.annotation.DispatchingAnnotationProcessor
|
||||
|
|
@ -0,0 +1,17 @@
|
|||
#
|
||||
# Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
# contributor license agreements. See the NOTICE file distributed with
|
||||
# this work for additional information regarding copyright ownership.
|
||||
# The ASF licenses this file to You under the Apache License, Version 2.0
|
||||
# (the "License"); you may not use this file except in compliance with
|
||||
# the License. You may obtain a copy of the License at
|
||||
#
|
||||
# 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.
|
||||
|
||||
org.apache.dubbo.annotation.handler.DeprecatedHandler
|
||||
|
|
@ -0,0 +1,64 @@
|
|||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
* contributor license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright ownership.
|
||||
* The ASF licenses this file to You under the Apache License, Version 2.0
|
||||
* (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.apache.dubbo.annotation;
|
||||
|
||||
import org.apache.dubbo.annotation.util.FileUtils;
|
||||
import org.apache.dubbo.eci.extractor.JavassistUtils;
|
||||
|
||||
import javassist.bytecode.ClassFile;
|
||||
import org.junit.jupiter.api.Assertions;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* Real invocation test of DispatchingAnnotationProcessor (and DeprecatedHandler).
|
||||
*/
|
||||
class RealInvocationTest {
|
||||
|
||||
/**
|
||||
* [File name, Should the counter exist in the class file? ]
|
||||
*/
|
||||
private static final Map<String, Boolean> FILES = new HashMap<>(5, 1);
|
||||
|
||||
static {
|
||||
FILES.put("TestConstructorMethod.java", true);
|
||||
FILES.put("TestDeprecatedMethod.java", true);
|
||||
FILES.put("TestInterfaceDeprecatedMethod.java", false);
|
||||
FILES.put("TestConstructorMethodParentClass.java", false);
|
||||
FILES.put("TestConstructorMethodSubClass.java", true);
|
||||
}
|
||||
|
||||
@Test
|
||||
void test() {
|
||||
|
||||
for (Map.Entry<String, Boolean> i : FILES.entrySet()) {
|
||||
String filePath = FileUtils.getResourceFilePath("org/testing/dm/" + i.getKey());
|
||||
|
||||
Assertions.assertTrue(TestingCommons.compileTheSource(filePath), "Compile failed! ");
|
||||
|
||||
String classFilePath = filePath.replace(".java", ".class");
|
||||
ClassFile classFile = JavassistUtils.openClassFile(classFilePath);
|
||||
List<String> stringItems = JavassistUtils.getConstPoolStringItems(classFile.getConstPool());
|
||||
|
||||
Assertions.assertEquals(i.getValue(), stringItems.contains("org/apache/dubbo/common/DeprecatedMethodInvocationCounter"));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,71 @@
|
|||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
* contributor license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright ownership.
|
||||
* The ASF licenses this file to You under the Apache License, Version 2.0
|
||||
* (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.apache.dubbo.annotation;
|
||||
|
||||
import javax.tools.JavaCompiler;
|
||||
import javax.tools.JavaFileObject;
|
||||
import javax.tools.StandardJavaFileManager;
|
||||
import javax.tools.ToolProvider;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.util.Collections;
|
||||
import java.util.Locale;
|
||||
|
||||
import static java.util.Arrays.asList;
|
||||
|
||||
/**
|
||||
* Common code of annotation processor testing.
|
||||
*/
|
||||
public final class TestingCommons {
|
||||
private TestingCommons() {
|
||||
throw new UnsupportedOperationException("No instance of TestingCommons for you! ");
|
||||
}
|
||||
|
||||
private static class ObjectHolders {
|
||||
static final JavaCompiler javaCompiler = ToolProvider.getSystemJavaCompiler();
|
||||
|
||||
static final StandardJavaFileManager javaFileManager = javaCompiler.getStandardFileManager(
|
||||
null,
|
||||
Locale.ROOT,
|
||||
StandardCharsets.UTF_8
|
||||
);
|
||||
}
|
||||
|
||||
public static boolean compileTheSource(String filePath) {
|
||||
|
||||
|
||||
JavaCompiler.CompilationTask compilationTask = ObjectHolders.javaCompiler.getTask(
|
||||
null,
|
||||
ObjectHolders.javaFileManager,
|
||||
null,
|
||||
asList("-parameters", "-Xlint:unchecked", "-nowarn", "-Xlint:deprecation"),
|
||||
null,
|
||||
getSourceFileJavaFileObject(filePath)
|
||||
);
|
||||
|
||||
compilationTask.setProcessors(
|
||||
Collections.singletonList(new DispatchingAnnotationProcessor())
|
||||
);
|
||||
|
||||
return compilationTask.call();
|
||||
}
|
||||
|
||||
private static Iterable<? extends JavaFileObject> getSourceFileJavaFileObject(String filePath) {
|
||||
|
||||
return ObjectHolders.javaFileManager.getJavaFileObjects(filePath);
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,36 @@
|
|||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
* contributor license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright ownership.
|
||||
* The ASF licenses this file to You under the Apache License, Version 2.0
|
||||
* (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.apache.dubbo.common;
|
||||
|
||||
/**
|
||||
* Reduced mock of Deprecated method invocation counter.
|
||||
*/
|
||||
public final class DeprecatedMethodInvocationCounter {
|
||||
private DeprecatedMethodInvocationCounter() {
|
||||
throw new UnsupportedOperationException("No instance of DeprecatedMethodInvocationCounter for you! ");
|
||||
}
|
||||
|
||||
/**
|
||||
* Invoked by (modified) deprecated method.
|
||||
*
|
||||
* @param methodDefinition filled by annotation processor. (like 'org.apache.dubbo.common.URL.getServiceName()')
|
||||
*/
|
||||
public static void onDeprecatedMethodCalled(String methodDefinition) {
|
||||
// Intended to be empty.
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,151 @@
|
|||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
* contributor license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright ownership.
|
||||
* The ASF licenses this file to You under the Apache License, Version 2.0
|
||||
* (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.apache.dubbo.eci.extractor;
|
||||
|
||||
import org.apache.dubbo.annotation.util.FileUtils;
|
||||
|
||||
import javassist.bytecode.ClassFile;
|
||||
import javassist.bytecode.ConstPool;
|
||||
|
||||
import java.io.ByteArrayInputStream;
|
||||
import java.io.DataInputStream;
|
||||
import java.io.IOException;
|
||||
import java.lang.reflect.Field;
|
||||
import java.lang.reflect.InvocationTargetException;
|
||||
import java.lang.reflect.Method;
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* Utilities of Javassist.
|
||||
*/
|
||||
public class JavassistUtils {
|
||||
private static final Map<Class, Field> stringFieldCache = new HashMap<>(2, 1);
|
||||
|
||||
private static Method getItemMethodCache = null;
|
||||
|
||||
private JavassistUtils() {
|
||||
throw new UnsupportedOperationException("No instance of JavassistUtils for you! ");
|
||||
}
|
||||
|
||||
public static ClassFile openClassFile(String classFilePath) {
|
||||
try {
|
||||
byte[] clsB = FileUtils.openFileAsByteArray(classFilePath);
|
||||
return new ClassFile(new DataInputStream(new ByteArrayInputStream(clsB)));
|
||||
} catch (IOException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
|
||||
static List<Object> getConstPoolItems(ConstPool cp) {
|
||||
List<Object> objects = new ArrayList<>(cp.getSize());
|
||||
|
||||
for (int i = 0; i < cp.getSize(); i++) {
|
||||
objects.add(getConstPoolItem(cp, i));
|
||||
}
|
||||
|
||||
return objects;
|
||||
}
|
||||
|
||||
/**
|
||||
* Calls ConstPool.getItem() method reflectively.
|
||||
*
|
||||
* @param cp The ConstPool object.
|
||||
* @param index The index of items.
|
||||
* @return The XXXInfo Object. Since it's invisible, return Object instead.
|
||||
*/
|
||||
static Object getConstPoolItem(ConstPool cp, int index) {
|
||||
|
||||
if (getItemMethodCache == null) {
|
||||
Class<ConstPool> cpc = ConstPool.class;
|
||||
Method getItemMethod;
|
||||
try {
|
||||
getItemMethod = cpc.getDeclaredMethod("getItem", int.class);
|
||||
getItemMethod.setAccessible(true);
|
||||
|
||||
getItemMethodCache = getItemMethod;
|
||||
|
||||
} catch (NoSuchMethodException e) {
|
||||
throw new RuntimeException("Javassist internal method changed.", e);
|
||||
}
|
||||
}
|
||||
|
||||
try {
|
||||
return getItemMethodCache.invoke(cp, index);
|
||||
} catch (IllegalAccessException | InvocationTargetException e) {
|
||||
throw new RuntimeException("Javassist internal method changed.", e);
|
||||
}
|
||||
}
|
||||
|
||||
public static List<String> getConstPoolStringItems(ConstPool cp) {
|
||||
List<Object> objects = getConstPoolItems(cp);
|
||||
List<String> stringItems = new ArrayList<>(cp.getSize());
|
||||
|
||||
for (Object item : objects) {
|
||||
|
||||
Field stringField;
|
||||
|
||||
if (item != null) {
|
||||
stringField = getStringFieldInConstPoolItems(item);
|
||||
|
||||
if (stringField == null) {
|
||||
continue;
|
||||
}
|
||||
|
||||
Object fieldData;
|
||||
|
||||
try {
|
||||
fieldData = stringField.get(item);
|
||||
} catch (IllegalAccessException e) {
|
||||
throw new RuntimeException("Javassist internal field changed.", e);
|
||||
}
|
||||
|
||||
if (fieldData.getClass() == String.class) {
|
||||
stringItems.add((String) fieldData);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return stringItems;
|
||||
}
|
||||
|
||||
/**
|
||||
* Obtain the 'string' field in Utf8Info and StringInfo.
|
||||
*
|
||||
* @param item The instance of Utf8Info and StringInfo.
|
||||
* @return 'string' field's value
|
||||
*/
|
||||
static Field getStringFieldInConstPoolItems(Object item) {
|
||||
if (stringFieldCache.containsKey(item.getClass())) {
|
||||
return stringFieldCache.get(item.getClass());
|
||||
} else {
|
||||
try {
|
||||
Field stringField = item.getClass().getDeclaredField("string");
|
||||
stringField.setAccessible(true);
|
||||
stringFieldCache.put(item.getClass(), stringField);
|
||||
|
||||
return stringField;
|
||||
} catch (NoSuchFieldException ignored) {
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,51 @@
|
|||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
* contributor license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright ownership.
|
||||
* The ASF licenses this file to You under the Apache License, Version 2.0
|
||||
* (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.apache.dubbo.eci.util;
|
||||
|
||||
import java.lang.reflect.Field;
|
||||
|
||||
/**
|
||||
* Tools of reflective operations.
|
||||
*/
|
||||
public final class ReflectUtils {
|
||||
private ReflectUtils() {
|
||||
throw new UnsupportedOperationException("No instance of ReflectUtils for you! ");
|
||||
}
|
||||
|
||||
/**
|
||||
* Searches (a private) field in super classes recursively.
|
||||
*
|
||||
* @param cls the actual type
|
||||
* @param name the field name
|
||||
* @return the corresponding Field object, or null if the field does not exist.
|
||||
*/
|
||||
public static Field getDeclaredFieldRecursively(Class cls, String name) {
|
||||
try {
|
||||
Field indexField = cls.getDeclaredField(name);
|
||||
indexField.setAccessible(true);
|
||||
|
||||
return indexField;
|
||||
} catch (NoSuchFieldException e) {
|
||||
if (cls == Object.class) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return getDeclaredFieldRecursively(cls.getSuperclass(), name);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,28 @@
|
|||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
* contributor license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright ownership.
|
||||
* The ASF licenses this file to You under the Apache License, Version 2.0
|
||||
* (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.testing.dm;
|
||||
|
||||
public class TestConstructorMethod {
|
||||
@Deprecated
|
||||
TestConstructorMethod() {
|
||||
this("1");
|
||||
}
|
||||
|
||||
TestConstructorMethod(String s) {
|
||||
}
|
||||
}
|
||||
|
|
@ -15,14 +15,13 @@
|
|||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.apache.dubbo.common.utils;
|
||||
package org.testing.dm;
|
||||
|
||||
import static org.apache.dubbo.common.constants.CommonConstants.NATIVE;
|
||||
public class TestConstructorMethodParentClass {
|
||||
|
||||
public abstract class NativeUtils {
|
||||
|
||||
public static boolean isNative() {
|
||||
return Boolean.parseBoolean(System.getProperty(NATIVE, "false"));
|
||||
public TestConstructorMethodParentClass() {
|
||||
}
|
||||
|
||||
public TestConstructorMethodParentClass(String s) {
|
||||
}
|
||||
}
|
||||
|
|
@ -15,16 +15,16 @@
|
|||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.apache.dubbo.maven.plugin;
|
||||
package org.testing.dm;
|
||||
|
||||
import java.util.Set;
|
||||
public class TestConstructorMethodSubClass extends TestConstructorMethodParentClass {
|
||||
|
||||
public class Test {
|
||||
@Deprecated
|
||||
public TestConstructorMethodSubClass(int i) {
|
||||
super();
|
||||
}
|
||||
|
||||
public static void main(String[] args) {
|
||||
ClassFinder finder = new ClassFinder();
|
||||
Set<String> set = finder.findClassSet("org.apache.dubbo", msg -> {
|
||||
});
|
||||
System.out.println(set.size());
|
||||
public TestConstructorMethodSubClass(String s) {
|
||||
super(s);
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,26 @@
|
|||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
* contributor license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright ownership.
|
||||
* The ASF licenses this file to You under the Apache License, Version 2.0
|
||||
* (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.testing.dm;
|
||||
|
||||
public class TestDeprecatedMethod {
|
||||
|
||||
@Deprecated
|
||||
public void m1() {
|
||||
System.out.println("M1! ");
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,24 @@
|
|||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
* contributor license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright ownership.
|
||||
* The ASF licenses this file to You under the Apache License, Version 2.0
|
||||
* (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.testing.dm;
|
||||
|
||||
public interface TestInterfaceDeprecatedMethod {
|
||||
|
||||
@Deprecated
|
||||
public void m1();
|
||||
}
|
||||
|
|
@ -13,8 +13,8 @@
|
|||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
-->
|
||||
<project xmlns="http://maven.apache.org/POM/4.0.0"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
<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">
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
||||
|
|
|
|||
|
|
@ -86,10 +86,5 @@
|
|||
<version>${project.parent.version}</version>
|
||||
<optional>true</optional>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>io.micrometer</groupId>
|
||||
<artifactId>micrometer-tracing-integration-test</artifactId>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
</project>
|
||||
|
|
|
|||
|
|
@ -0,0 +1,68 @@
|
|||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
* contributor license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright ownership.
|
||||
* The ASF licenses this file to You under the Apache License, Version 2.0
|
||||
* (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.apache.dubbo.config.validator;
|
||||
|
||||
import org.apache.dubbo.common.extension.Activate;
|
||||
import org.apache.dubbo.common.utils.CollectionUtils;
|
||||
import org.apache.dubbo.config.AbstractInterfaceConfig;
|
||||
import org.apache.dubbo.config.MethodConfig;
|
||||
import org.apache.dubbo.config.context.ConfigValidator;
|
||||
import org.apache.dubbo.config.utils.ConfigValidationUtils;
|
||||
import org.apache.dubbo.rpc.Filter;
|
||||
import org.apache.dubbo.rpc.ProxyFactory;
|
||||
import org.apache.dubbo.rpc.cluster.Cluster;
|
||||
import org.apache.dubbo.rpc.cluster.filter.ClusterFilter;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
|
||||
import static org.apache.dubbo.common.constants.CommonConstants.CLUSTER_KEY;
|
||||
import static org.apache.dubbo.common.constants.CommonConstants.FILTER_KEY;
|
||||
import static org.apache.dubbo.config.Constants.LAYER_KEY;
|
||||
import static org.apache.dubbo.rpc.Constants.LOCAL_KEY;
|
||||
import static org.apache.dubbo.rpc.Constants.PROXY_KEY;
|
||||
|
||||
@Activate
|
||||
public class InterfaceConfigValidator implements ConfigValidator<AbstractInterfaceConfig> {
|
||||
|
||||
public static void validateAbstractInterfaceConfig(AbstractInterfaceConfig config) {
|
||||
ConfigValidationUtils.checkName(LOCAL_KEY, config.getLocal());
|
||||
ConfigValidationUtils.checkName("stub", config.getStub());
|
||||
ConfigValidationUtils.checkMultiName("owner", config.getOwner());
|
||||
|
||||
ConfigValidationUtils.checkExtension(config.getScopeModel(), ProxyFactory.class, PROXY_KEY, config.getProxy());
|
||||
ConfigValidationUtils.checkExtension(config.getScopeModel(), Cluster.class, CLUSTER_KEY, config.getCluster());
|
||||
ConfigValidationUtils.checkMultiExtension(config.getScopeModel(), Arrays.asList(Filter.class, ClusterFilter.class), FILTER_KEY, config.getFilter());
|
||||
ConfigValidationUtils.checkNameHasSymbol(LAYER_KEY, config.getLayer());
|
||||
|
||||
List<MethodConfig> methods = config.getMethods();
|
||||
if (CollectionUtils.isNotEmpty(methods)) {
|
||||
methods.forEach(MethodConfig::validate);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean validate(AbstractInterfaceConfig config) {
|
||||
validateAbstractInterfaceConfig(config);
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isSupport(Class<?> configClass) {
|
||||
return AbstractInterfaceConfig.class.isAssignableFrom(configClass);
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,63 @@
|
|||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
* contributor license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright ownership.
|
||||
* The ASF licenses this file to You under the Apache License, Version 2.0
|
||||
* (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.apache.dubbo.config.validator;
|
||||
|
||||
import org.apache.dubbo.common.extension.Activate;
|
||||
import org.apache.dubbo.config.MethodConfig;
|
||||
import org.apache.dubbo.config.context.ConfigValidator;
|
||||
import org.apache.dubbo.config.utils.ConfigValidationUtils;
|
||||
import org.apache.dubbo.rpc.cluster.LoadBalance;
|
||||
|
||||
import static org.apache.dubbo.common.constants.CommonConstants.LOADBALANCE_KEY;
|
||||
import static org.apache.dubbo.common.utils.StringUtils.isNotEmpty;
|
||||
import static org.apache.dubbo.rpc.Constants.FAIL_PREFIX;
|
||||
import static org.apache.dubbo.rpc.Constants.FORCE_PREFIX;
|
||||
import static org.apache.dubbo.rpc.Constants.MOCK_KEY;
|
||||
import static org.apache.dubbo.rpc.Constants.RETURN_PREFIX;
|
||||
import static org.apache.dubbo.rpc.Constants.THROW_PREFIX;
|
||||
|
||||
@Activate
|
||||
public class MethodConfigValidator implements ConfigValidator<MethodConfig> {
|
||||
|
||||
public static void validateMethodConfig(MethodConfig config) {
|
||||
ConfigValidationUtils.checkExtension(config.getScopeModel(), LoadBalance.class, LOADBALANCE_KEY, config.getLoadbalance());
|
||||
ConfigValidationUtils.checkParameterName(config.getParameters());
|
||||
ConfigValidationUtils.checkMethodName("name", config.getName());
|
||||
|
||||
String mock = config.getMock();
|
||||
if (isNotEmpty(mock)) {
|
||||
if (mock.startsWith(RETURN_PREFIX) || mock.startsWith(THROW_PREFIX + " ")) {
|
||||
ConfigValidationUtils.checkLength(MOCK_KEY, mock);
|
||||
} else if (mock.startsWith(FAIL_PREFIX) || mock.startsWith(FORCE_PREFIX)) {
|
||||
ConfigValidationUtils.checkNameHasSymbol(MOCK_KEY, mock);
|
||||
} else {
|
||||
ConfigValidationUtils.checkName(MOCK_KEY, mock);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean validate(MethodConfig config) {
|
||||
validateMethodConfig(config);
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isSupport(Class<?> configClass) {
|
||||
return MethodConfig.class.equals(configClass);
|
||||
}
|
||||
}
|
||||
|
|
@ -24,6 +24,8 @@ import org.apache.dubbo.rpc.RpcException;
|
|||
import org.apache.dubbo.rpc.model.ScopeModel;
|
||||
import org.apache.dubbo.rpc.model.ScopeModelUtil;
|
||||
|
||||
import static org.apache.dubbo.rpc.cluster.Constants.DEFAULT_CLUSTER;
|
||||
|
||||
/**
|
||||
* Cluster. (SPI, Singleton, ThreadSafe)
|
||||
* <p>
|
||||
|
|
@ -31,11 +33,9 @@ import org.apache.dubbo.rpc.model.ScopeModelUtil;
|
|||
* <a href="http://en.wikipedia.org/wiki/Fault-tolerant_system">Fault-Tolerant</a>
|
||||
*
|
||||
*/
|
||||
@SPI(Cluster.DEFAULT)
|
||||
@SPI(DEFAULT_CLUSTER)
|
||||
public interface Cluster {
|
||||
|
||||
String DEFAULT = "failover";
|
||||
|
||||
/**
|
||||
* Merge the directory invokers to a virtual invoker.
|
||||
*
|
||||
|
|
@ -53,7 +53,7 @@ public interface Cluster {
|
|||
|
||||
static Cluster getCluster(ScopeModel scopeModel, String name, boolean wrap) {
|
||||
if (StringUtils.isEmpty(name)) {
|
||||
name = Cluster.DEFAULT;
|
||||
name = DEFAULT_CLUSTER;
|
||||
}
|
||||
return ScopeModelUtil.getApplicationModel(scopeModel).getExtensionLoader(Cluster.class).getExtension(name, wrap);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -17,10 +17,9 @@
|
|||
package org.apache.dubbo.rpc.cluster;
|
||||
|
||||
import org.apache.dubbo.common.beans.factory.ScopeBeanFactory;
|
||||
import org.apache.dubbo.rpc.AdaptiveMetrics;
|
||||
import org.apache.dubbo.rpc.cluster.merger.MergerFactory;
|
||||
import org.apache.dubbo.rpc.cluster.factory.DefaultClusterInvokerFactory;
|
||||
import org.apache.dubbo.rpc.cluster.factory.StaticDirectoryStrategy;
|
||||
import org.apache.dubbo.rpc.cluster.router.RouterSnapshotSwitcher;
|
||||
import org.apache.dubbo.rpc.cluster.router.mesh.route.MeshRuleManager;
|
||||
import org.apache.dubbo.rpc.cluster.support.ClusterUtils;
|
||||
import org.apache.dubbo.rpc.model.ApplicationModel;
|
||||
import org.apache.dubbo.rpc.model.FrameworkModel;
|
||||
|
|
@ -28,23 +27,22 @@ import org.apache.dubbo.rpc.model.ModuleModel;
|
|||
import org.apache.dubbo.rpc.model.ScopeModelInitializer;
|
||||
|
||||
public class ClusterScopeModelInitializer implements ScopeModelInitializer {
|
||||
|
||||
@Override
|
||||
public void initializeFrameworkModel(FrameworkModel frameworkModel) {
|
||||
ScopeBeanFactory beanFactory = frameworkModel.getBeanFactory();
|
||||
beanFactory.registerBean(RouterSnapshotSwitcher.class);
|
||||
beanFactory.registerBean(StaticDirectoryStrategy.class);
|
||||
beanFactory.registerBean(DefaultClusterInvokerFactory.class);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void initializeApplicationModel(ApplicationModel applicationModel) {
|
||||
ScopeBeanFactory beanFactory = applicationModel.getBeanFactory();
|
||||
beanFactory.registerBean(MergerFactory.class);
|
||||
beanFactory.registerBean(ClusterUtils.class);
|
||||
beanFactory.registerBean(AdaptiveMetrics.class);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void initializeModuleModel(ModuleModel moduleModel) {
|
||||
ScopeBeanFactory beanFactory = moduleModel.getBeanFactory();
|
||||
beanFactory.registerBean(MeshRuleManager.class);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -0,0 +1,56 @@
|
|||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
* contributor license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright ownership.
|
||||
* The ASF licenses this file to You under the Apache License, Version 2.0
|
||||
* (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.apache.dubbo.rpc.cluster.factory;
|
||||
|
||||
|
||||
import org.apache.dubbo.rpc.Invoker;
|
||||
import org.apache.dubbo.rpc.cluster.ClusterInvokerFactory;
|
||||
import org.apache.dubbo.rpc.cluster.Directory;
|
||||
import org.apache.dubbo.rpc.model.ScopeModel;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import static org.apache.dubbo.rpc.cluster.Cluster.getCluster;
|
||||
|
||||
public class DefaultClusterInvokerFactory implements ClusterInvokerFactory {
|
||||
|
||||
private final List<DirectoryStrategy> strategies;
|
||||
|
||||
public DefaultClusterInvokerFactory(ScopeModel scopeModel) {
|
||||
this.strategies = scopeModel.getBeanFactory().getBeansOfType(DirectoryStrategy.class);
|
||||
}
|
||||
|
||||
/**
|
||||
* Build an Invoker with StaticDirectory.
|
||||
*
|
||||
* @param config config
|
||||
* @return ClusterInvoker
|
||||
*/
|
||||
@Override
|
||||
public Invoker<?> getInvoker(ClusterInvokerConfig config) {
|
||||
Directory<?> directory = null;
|
||||
for (DirectoryStrategy strategy : strategies) {
|
||||
if (strategy.name().equals(config.getDirectoryName())) {
|
||||
directory = strategy.createDirectory(config);
|
||||
break;
|
||||
}
|
||||
}
|
||||
return getCluster(config.getScopeModel(), config.getClusterName(), config.isWrappedCluster())
|
||||
.join(directory,config.isWrappedInvoker());
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,27 @@
|
|||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
* contributor license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright ownership.
|
||||
* The ASF licenses this file to You under the Apache License, Version 2.0
|
||||
* (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.apache.dubbo.rpc.cluster.factory;
|
||||
|
||||
import org.apache.dubbo.rpc.cluster.ClusterInvokerFactory;
|
||||
import org.apache.dubbo.rpc.cluster.Directory;
|
||||
|
||||
public interface DirectoryStrategy {
|
||||
|
||||
ClusterInvokerFactory.DirectoryNames name();
|
||||
|
||||
<T> Directory<T> createDirectory(ClusterInvokerFactory.ClusterInvokerConfig clusterInvokerConfig);
|
||||
}
|
||||
|
|
@ -0,0 +1,34 @@
|
|||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
* contributor license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright ownership.
|
||||
* The ASF licenses this file to You under the Apache License, Version 2.0
|
||||
* (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.apache.dubbo.rpc.cluster.factory;
|
||||
|
||||
import org.apache.dubbo.rpc.cluster.ClusterInvokerFactory;
|
||||
import org.apache.dubbo.rpc.cluster.Directory;
|
||||
import org.apache.dubbo.rpc.cluster.directory.StaticDirectory;
|
||||
|
||||
public class StaticDirectoryStrategy implements DirectoryStrategy {
|
||||
|
||||
@Override
|
||||
public ClusterInvokerFactory.DirectoryNames name() {
|
||||
return ClusterInvokerFactory.DirectoryNames.STATIC;
|
||||
}
|
||||
|
||||
@Override
|
||||
public <T> Directory<T> createDirectory(ClusterInvokerFactory.ClusterInvokerConfig clusterInvokerConfig) {
|
||||
return new StaticDirectory(clusterInvokerConfig.getServiceUrl(),clusterInvokerConfig.getInvokersToJoin());
|
||||
}
|
||||
}
|
||||
|
|
@ -23,8 +23,6 @@ import org.apache.dubbo.rpc.cluster.support.wrapper.AbstractCluster;
|
|||
|
||||
public class ZoneAwareCluster extends AbstractCluster {
|
||||
|
||||
public final static String NAME = "zone-aware";
|
||||
|
||||
@Override
|
||||
protected <T> AbstractClusterInvoker<T> doJoin(Directory<T> directory) throws RpcException {
|
||||
return new ZoneAwareClusterInvoker<T>(directory);
|
||||
|
|
|
|||
|
|
@ -49,6 +49,7 @@ import static org.apache.dubbo.rpc.Constants.LOCAL_PROTOCOL;
|
|||
import static org.apache.dubbo.rpc.Constants.SCOPE_KEY;
|
||||
import static org.apache.dubbo.rpc.Constants.SCOPE_LOCAL;
|
||||
import static org.apache.dubbo.rpc.Constants.SCOPE_REMOTE;
|
||||
import static org.apache.dubbo.rpc.cluster.Constants.DEFAULT_CLUSTER;
|
||||
import static org.apache.dubbo.rpc.cluster.Constants.PEER_KEY;
|
||||
|
||||
/**
|
||||
|
|
@ -291,7 +292,7 @@ public class ScopeClusterInvoker<T> implements ClusterInvoker<T>, ExporterChange
|
|||
Invoker<?> invoker = protocolSPI.refer(getInterface(), consumerUrl);
|
||||
List<Invoker<?>> invokers = new ArrayList<>();
|
||||
invokers.add(invoker);
|
||||
injvmInvoker = Cluster.getCluster(url.getScopeModel(), Cluster.DEFAULT, false).join(new StaticDirectory(url, invokers), true);
|
||||
injvmInvoker = Cluster.getCluster(url.getScopeModel(), DEFAULT_CLUSTER, false).join(new StaticDirectory(url, invokers), true);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -0,0 +1,2 @@
|
|||
interface=org.apache.dubbo.config.validator.InterfaceConfigValidator
|
||||
method=org.apache.dubbo.config.validator.MethodConfigValidator
|
||||
|
|
@ -1,4 +1,3 @@
|
|||
mock=org.apache.dubbo.rpc.cluster.support.wrapper.MockClusterWrapper
|
||||
scope=org.apache.dubbo.rpc.cluster.support.wrapper.ScopeClusterWrapper
|
||||
failover=org.apache.dubbo.rpc.cluster.support.FailoverCluster
|
||||
failfast=org.apache.dubbo.rpc.cluster.support.FailfastCluster
|
||||
|
|
@ -6,6 +5,5 @@ failsafe=org.apache.dubbo.rpc.cluster.support.FailsafeCluster
|
|||
failback=org.apache.dubbo.rpc.cluster.support.FailbackCluster
|
||||
forking=org.apache.dubbo.rpc.cluster.support.ForkingCluster
|
||||
available=org.apache.dubbo.rpc.cluster.support.AvailableCluster
|
||||
mergeable=org.apache.dubbo.rpc.cluster.support.MergeableCluster
|
||||
broadcast=org.apache.dubbo.rpc.cluster.support.BroadcastCluster
|
||||
zone-aware=org.apache.dubbo.rpc.cluster.support.registry.ZoneAwareCluster
|
||||
|
|
@ -3,4 +3,3 @@ roundrobin=org.apache.dubbo.rpc.cluster.loadbalance.RoundRobinLoadBalance
|
|||
leastactive=org.apache.dubbo.rpc.cluster.loadbalance.LeastActiveLoadBalance
|
||||
consistenthash=org.apache.dubbo.rpc.cluster.loadbalance.ConsistentHashLoadBalance
|
||||
shortestresponse=org.apache.dubbo.rpc.cluster.loadbalance.ShortestResponseLoadBalance
|
||||
adaptive=org.apache.dubbo.rpc.cluster.loadbalance.AdaptiveLoadBalance
|
||||
|
|
|
|||
|
|
@ -1,6 +1,2 @@
|
|||
consumercontext=org.apache.dubbo.rpc.cluster.filter.support.ConsumerContextFilter
|
||||
consumer-classloader=org.apache.dubbo.rpc.cluster.filter.support.ConsumerClassLoaderFilter
|
||||
router-snapshot=org.apache.dubbo.rpc.cluster.router.RouterSnapshotFilter
|
||||
observationsender=org.apache.dubbo.rpc.cluster.filter.support.ObservationSenderFilter
|
||||
metricsClusterFilter=org.apache.dubbo.rpc.cluster.filter.support.MetricsClusterFilter
|
||||
metricsConsumerFilter=org.apache.dubbo.rpc.cluster.filter.support.MetricsConsumerFilter
|
||||
|
|
|
|||
|
|
@ -1,253 +1,253 @@
|
|||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
* contributor license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright ownership.
|
||||
* The ASF licenses this file to You under the Apache License, Version 2.0
|
||||
* (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.apache.dubbo.rpc.cluster;
|
||||
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
|
||||
import org.apache.dubbo.common.URL;
|
||||
import org.apache.dubbo.common.config.configcenter.ConfigChangeType;
|
||||
import org.apache.dubbo.common.config.configcenter.ConfigChangedEvent;
|
||||
import org.apache.dubbo.common.config.configcenter.DynamicConfiguration;
|
||||
import org.apache.dubbo.common.url.component.ServiceConfigURL;
|
||||
import org.apache.dubbo.common.utils.CollectionUtils;
|
||||
import org.apache.dubbo.rpc.Invoker;
|
||||
import org.apache.dubbo.rpc.RpcContext;
|
||||
import org.apache.dubbo.rpc.RpcInvocation;
|
||||
import org.apache.dubbo.rpc.cluster.filter.DemoService;
|
||||
import org.apache.dubbo.rpc.cluster.router.RouterSnapshotSwitcher;
|
||||
import org.apache.dubbo.rpc.cluster.router.condition.config.AppStateRouter;
|
||||
import org.apache.dubbo.rpc.cluster.router.condition.config.ListenableStateRouter;
|
||||
import org.apache.dubbo.rpc.cluster.router.condition.config.ServiceStateRouter;
|
||||
import org.apache.dubbo.rpc.cluster.router.mesh.route.MeshAppRuleListener;
|
||||
import org.apache.dubbo.rpc.cluster.router.mesh.route.MeshRuleManager;
|
||||
import org.apache.dubbo.rpc.cluster.router.state.BitList;
|
||||
import org.apache.dubbo.rpc.model.FrameworkModel;
|
||||
import org.junit.jupiter.api.Assertions;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.mockito.Mockito;
|
||||
|
||||
import static org.apache.dubbo.common.constants.CommonConstants.INTERFACE_KEY;
|
||||
import static org.apache.dubbo.common.constants.CommonConstants.TAG_KEY;
|
||||
import static org.apache.dubbo.rpc.cluster.router.mesh.route.MeshRuleConstants.MESH_RULE_DATA_ID_SUFFIX;
|
||||
import static org.mockito.Mockito.when;
|
||||
|
||||
class RouterChainTest {
|
||||
|
||||
/**
|
||||
* verify the router and state router loaded by default
|
||||
*/
|
||||
@Test
|
||||
void testBuildRouterChain() {
|
||||
RouterChain<DemoService> routerChain = createRouterChanin();
|
||||
Assertions.assertEquals(0, routerChain.getRouters().size());
|
||||
Assertions.assertEquals(7, routerChain.getStateRouters().size());
|
||||
}
|
||||
|
||||
private RouterChain<DemoService> createRouterChanin() {
|
||||
Map<String, String> parameters = new HashMap<>();
|
||||
parameters.put(INTERFACE_KEY, DemoService.class.getName());
|
||||
parameters.put("registry", "zookeeper");
|
||||
URL url = new ServiceConfigURL("dubbo",
|
||||
"127.0.0.1",
|
||||
20881,
|
||||
DemoService.class.getName(),
|
||||
parameters);
|
||||
|
||||
RouterChain<DemoService> routerChain = RouterChain.buildChain(DemoService.class, url);
|
||||
return routerChain;
|
||||
}
|
||||
|
||||
@Test
|
||||
void testRoute() {
|
||||
RouterChain<DemoService> routerChain = createRouterChanin();
|
||||
|
||||
// mockInvoker will be filtered out by MockInvokersSelector
|
||||
Invoker<DemoService> mockInvoker = createMockInvoker();
|
||||
|
||||
// invoker1 will be filtered out by MeshStateRouter
|
||||
Map<String, String> map1 = new HashMap<>();
|
||||
map1.put("env-sign", "yyyyyyy");
|
||||
Invoker<DemoService> invoker1 = createNormalInvoker(map1);
|
||||
|
||||
// invoker2 will be filtered out by TagStateRouter
|
||||
Map<String, String> map2 = new HashMap<>();
|
||||
map2.put("env-sign", "xxx");
|
||||
map2.put("tag1", "hello");
|
||||
Invoker<DemoService> invoker2 = createNormalInvoker(map2);
|
||||
|
||||
// invoker3 will be filtered out by AppStateRouter
|
||||
Map<String, String> map3 = new HashMap<>();
|
||||
map3.put("env-sign", "xxx");
|
||||
map3.put("tag1", "hello");
|
||||
map3.put(TAG_KEY, "TAG_");
|
||||
Invoker<DemoService> invoker3 = createNormalInvoker(map3);
|
||||
|
||||
// invoker4 will be filtered out by ServiceStateRouter
|
||||
Map<String, String> map4 = new HashMap<>();
|
||||
map4.put("env-sign", "xxx");
|
||||
map4.put("tag1", "hello");
|
||||
map4.put(TAG_KEY, "TAG_");
|
||||
map4.put("timeout", "5000");
|
||||
Invoker<DemoService> invoker4 = createNormalInvoker(map4);
|
||||
|
||||
// invoker5 is the only one returned at the end that is not filtered out
|
||||
Map<String, String> map5 = new HashMap<>();
|
||||
map5.put("env-sign", "xxx");
|
||||
map5.put("tag1", "hello");
|
||||
map5.put(TAG_KEY, "TAG_");
|
||||
map5.put("timeout", "5000");
|
||||
map5.put("serialization", "hessian2");
|
||||
Invoker<DemoService> invoker5 = createNormalInvoker(map5);
|
||||
|
||||
BitList<Invoker<DemoService>> invokers = new BitList<>(Arrays.asList(mockInvoker, invoker1, invoker2, invoker3, invoker4, invoker5));
|
||||
routerChain.setInvokers(invokers, () -> {});
|
||||
|
||||
// mesh rule for MeshStateRouter
|
||||
MeshRuleManager meshRuleManager = mockInvoker.getUrl().getOrDefaultModuleModel().getBeanFactory().getBean(MeshRuleManager.class);
|
||||
ConcurrentHashMap<String, MeshAppRuleListener> appRuleListeners = meshRuleManager.getAppRuleListeners();
|
||||
MeshAppRuleListener meshAppRuleListener = appRuleListeners.get(invoker1.getUrl().getRemoteApplication());
|
||||
ConfigChangedEvent configChangedEvent = new ConfigChangedEvent("demo-route" + MESH_RULE_DATA_ID_SUFFIX, DynamicConfiguration.DEFAULT_GROUP,
|
||||
MESH_RULE1 + "---\n" + MESH_RULE2, ConfigChangeType.ADDED);
|
||||
meshAppRuleListener.process(configChangedEvent);
|
||||
|
||||
|
||||
// condition rule for AppStateRouter&ServiceStateRouter
|
||||
ListenableStateRouter serviceRouter = routerChain.getStateRouters().stream().filter(s -> s instanceof ServiceStateRouter).map(s -> (ListenableStateRouter) s).findAny().orElse(null);
|
||||
ConfigChangedEvent serviceConditionEvent = new ConfigChangedEvent(DynamicConfiguration.getRuleKey(mockInvoker.getUrl()) + ".condition-router", DynamicConfiguration.DEFAULT_GROUP,
|
||||
SERVICE_CONDITION_RULE, ConfigChangeType.ADDED);
|
||||
serviceRouter.process(serviceConditionEvent);
|
||||
|
||||
ListenableStateRouter appRouter = routerChain.getStateRouters().stream().filter(s -> s instanceof AppStateRouter).map(s -> (ListenableStateRouter) s).findAny().orElse(null);
|
||||
ConfigChangedEvent appConditionEvent = new ConfigChangedEvent("app.condition-router", DynamicConfiguration.DEFAULT_GROUP,
|
||||
APP_CONDITION_RULE, ConfigChangeType.ADDED);
|
||||
appRouter.process(appConditionEvent);
|
||||
|
||||
// prepare consumerUrl and RpcInvocation
|
||||
URL consumerUrl = URL.valueOf("consumer://localhost/DemoInterface?remote.application=app1");
|
||||
RpcInvocation rpcInvocation = new RpcInvocation();
|
||||
rpcInvocation.setServiceName("DemoService");
|
||||
rpcInvocation.setObjectAttachment("trafficLabel", "xxx");
|
||||
rpcInvocation.setObjectAttachment(TAG_KEY, "TAG_");
|
||||
|
||||
RpcContext.getServiceContext().setNeedPrintRouterSnapshot(true);
|
||||
RouterSnapshotSwitcher routerSnapshotSwitcher = FrameworkModel.defaultModel().getBeanFactory().getBean(RouterSnapshotSwitcher.class);
|
||||
routerSnapshotSwitcher.addEnabledService("org.apache.dubbo.demo.DemoService");
|
||||
// route
|
||||
List<Invoker<DemoService>> result = routerChain.getSingleChain(consumerUrl, invokers, rpcInvocation)
|
||||
.route(consumerUrl, invokers, rpcInvocation);
|
||||
Assertions.assertEquals(result.size(), 1);
|
||||
Assertions.assertTrue(result.contains(invoker5));
|
||||
|
||||
String snapshotLog =
|
||||
"[ Parent (Input: 6) (Current Node Output: 6) (Chain Node Output: 1) ] Input: localhost:9103,localhost:9103,localhost:9103,localhost:9103,localhost:9103 -> Chain Node Output: localhost:9103...\n" +
|
||||
" [ MockInvokersSelector (Input: 6) (Current Node Output: 5) (Chain Node Output: 1) Router message: invocation.need.mock not set. Return normal Invokers. ] Current Node Output: localhost:9103,localhost:9103,localhost:9103,localhost:9103,localhost:9103\n" +
|
||||
" [ StandardMeshRuleRouter (Input: 5) (Current Node Output: 4) (Chain Node Output: 1) Router message: Match App: app Subset: isolation ] Current Node Output: localhost:9103,localhost:9103,localhost:9103,localhost:9103\n" +
|
||||
" [ TagStateRouter (Input: 4) (Current Node Output: 3) (Chain Node Output: 1) Router message: Disable Tag Router. Reason: tagRouterRule is invalid or disabled ] Current Node Output: localhost:9103,localhost:9103,localhost:9103\n" +
|
||||
" [ ServiceStateRouter (Input: 3) (Current Node Output: 3) (Chain Node Output: 1) Router message: null ] Current Node Output: localhost:9103,localhost:9103,localhost:9103\n" +
|
||||
" [ ConditionStateRouter (Input: 3) (Current Node Output: 2) (Chain Node Output: 2) Router message: Match return. ] Current Node Output: localhost:9103,localhost:9103\n" +
|
||||
" [ ProviderAppStateRouter (Input: 2) (Current Node Output: 2) (Chain Node Output: 1) Router message: Directly return. Reason: Invokers from previous router is empty or conditionRouters is empty. ] Current Node Output: localhost:9103,localhost:9103\n" +
|
||||
" [ AppStateRouter (Input: 2) (Current Node Output: 2) (Chain Node Output: 1) Router message: null ] Current Node Output: localhost:9103,localhost:9103\n" +
|
||||
" [ ConditionStateRouter (Input: 2) (Current Node Output: 1) (Chain Node Output: 1) Router message: Match return. ] Current Node Output: localhost:9103\n" +
|
||||
" [ AppScriptStateRouter (Input: 1) (Current Node Output: 1) (Chain Node Output: 1) Router message: Directly return from script router. Reason: Invokers from previous router is empty or script is not enabled. Script rule is: null ] Current Node Output: localhost:9103";
|
||||
String[] snapshot = routerSnapshotSwitcher.cloneSnapshot();
|
||||
Assertions.assertTrue(snapshot[0].contains(snapshotLog));
|
||||
|
||||
RpcContext.getServiceContext().setNeedPrintRouterSnapshot(false);
|
||||
result = routerChain.getSingleChain(consumerUrl, invokers, rpcInvocation)
|
||||
.route(consumerUrl, invokers, rpcInvocation);
|
||||
Assertions.assertEquals(result.size(), 1);
|
||||
Assertions.assertTrue(result.contains(invoker5));
|
||||
|
||||
routerChain.destroy();
|
||||
Assertions.assertEquals(routerChain.getRouters().size(), 0);
|
||||
Assertions.assertEquals(routerChain.getStateRouters().size(), 0);
|
||||
|
||||
}
|
||||
|
||||
private Invoker<DemoService> createMockInvoker() {
|
||||
URL url = URL.valueOf("mock://localhost:9103/DemoInterface?remote.application=app");
|
||||
Invoker<DemoService> invoker = Mockito.mock(Invoker.class);
|
||||
when(invoker.getUrl()).thenReturn(url);
|
||||
return invoker;
|
||||
}
|
||||
|
||||
private Invoker<DemoService> createNormalInvoker(Map<String, String> parameters) {
|
||||
URL url = URL.valueOf("dubbo://localhost:9103/DemoInterface?remote.application=app");
|
||||
if (CollectionUtils.isNotEmptyMap(parameters)) {
|
||||
url = url.addParameters(parameters);
|
||||
}
|
||||
Invoker<DemoService> invoker = Mockito.mock(Invoker.class);
|
||||
when(invoker.getUrl()).thenReturn(url);
|
||||
return invoker;
|
||||
}
|
||||
|
||||
|
||||
private final static String MESH_RULE1 = "apiVersion: service.dubbo.apache.org/v1alpha1\n" +
|
||||
"kind: DestinationRule\n" +
|
||||
"metadata: { name: demo-route }\n" +
|
||||
"spec:\n" +
|
||||
" host: demo\n" +
|
||||
" subsets:\n" +
|
||||
" - labels: { env-sign: xxx, tag1: hello }\n" +
|
||||
" name: isolation\n" +
|
||||
" - labels: { env-sign: yyy }\n" +
|
||||
" name: testing-trunk\n" +
|
||||
" - labels: { env-sign: zzz }\n" +
|
||||
" name: testing\n" +
|
||||
" trafficPolicy:\n" +
|
||||
" loadBalancer: { simple: ROUND_ROBIN }\n" +
|
||||
"\n";
|
||||
|
||||
private final static String MESH_RULE2 = "apiVersion: service.dubbo.apache.org/v1alpha1\n" +
|
||||
"kind: VirtualService\n" +
|
||||
"metadata: { name: demo-route }\n" +
|
||||
"spec:\n" +
|
||||
" dubbo:\n" +
|
||||
" - routedetail:\n" +
|
||||
" - match:\n" +
|
||||
" - attachments: \n" +
|
||||
" dubboContext: {trafficLabel: {regex: xxx}}\n" +
|
||||
" name: xxx-project\n" +
|
||||
" route:\n" +
|
||||
" - destination: {host: demo, subset: isolation}\n" +
|
||||
" services:\n" +
|
||||
" - {regex: DemoService}\n" +
|
||||
" hosts: [demo]\n";
|
||||
|
||||
private static final String APP_CONDITION_RULE = "scope: application\n" +
|
||||
"force: true\n" +
|
||||
"runtime: false\n" +
|
||||
"enabled: true\n" +
|
||||
"priority: 1\n" +
|
||||
"key: demo-consumer\n" +
|
||||
"conditions:\n" +
|
||||
"- => serialization=hessian2";
|
||||
|
||||
private static final String SERVICE_CONDITION_RULE = "scope: service\n" +
|
||||
"force: true\n" +
|
||||
"runtime: false\n" +
|
||||
"enabled: true\n" +
|
||||
"priority: 1\n" +
|
||||
"key: org.apache.dubbo.demo.DemoService\n" +
|
||||
"conditions:\n" +
|
||||
"- => timeout=5000";
|
||||
}
|
||||
///*
|
||||
// * Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
// * contributor license agreements. See the NOTICE file distributed with
|
||||
// * this work for additional information regarding copyright ownership.
|
||||
// * The ASF licenses this file to You under the Apache License, Version 2.0
|
||||
// * (the "License"); you may not use this file except in compliance with
|
||||
// * the License. You may obtain a copy of the License at
|
||||
// *
|
||||
// * http://www.apache.org/licenses/LICENSE-2.0
|
||||
// *
|
||||
// * Unless required by applicable law or agreed to in writing, software
|
||||
// * distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// * See the License for the specific language governing permissions and
|
||||
// * limitations under the License.
|
||||
// */
|
||||
//package org.apache.dubbo.rpc.cluster;
|
||||
//
|
||||
//
|
||||
//import java.util.Arrays;
|
||||
//import java.util.HashMap;
|
||||
//import java.util.List;
|
||||
//import java.util.Map;
|
||||
//import java.util.concurrent.ConcurrentHashMap;
|
||||
//
|
||||
//import org.apache.dubbo.common.URL;
|
||||
//import org.apache.dubbo.common.config.configcenter.ConfigChangeType;
|
||||
//import org.apache.dubbo.common.config.configcenter.ConfigChangedEvent;
|
||||
//import org.apache.dubbo.common.config.configcenter.DynamicConfiguration;
|
||||
//import org.apache.dubbo.common.url.component.ServiceConfigURL;
|
||||
//import org.apache.dubbo.common.utils.CollectionUtils;
|
||||
//import org.apache.dubbo.rpc.Invoker;
|
||||
//import org.apache.dubbo.rpc.RpcContext;
|
||||
//import org.apache.dubbo.rpc.RpcInvocation;
|
||||
//import org.apache.dubbo.rpc.cluster.filter.DemoService;
|
||||
//import org.apache.dubbo.rpc.cluster.router.RouterSnapshotSwitcher;
|
||||
//import org.apache.dubbo.rpc.cluster.router.condition.config.AppStateRouter;
|
||||
//import org.apache.dubbo.rpc.cluster.router.condition.config.ListenableStateRouter;
|
||||
//import org.apache.dubbo.rpc.cluster.router.condition.config.ServiceStateRouter;
|
||||
//import org.apache.dubbo.rpc.cluster.router.mesh.route.MeshAppRuleListener;
|
||||
//import org.apache.dubbo.rpc.cluster.router.mesh.route.MeshRuleManager;
|
||||
//import org.apache.dubbo.rpc.cluster.router.state.BitList;
|
||||
//import org.apache.dubbo.rpc.model.FrameworkModel;
|
||||
//import org.junit.jupiter.api.Assertions;
|
||||
//import org.junit.jupiter.api.Test;
|
||||
//import org.mockito.Mockito;
|
||||
//
|
||||
//import static org.apache.dubbo.common.constants.CommonConstants.INTERFACE_KEY;
|
||||
//import static org.apache.dubbo.common.constants.CommonConstants.TAG_KEY;
|
||||
//import static org.apache.dubbo.rpc.cluster.router.mesh.route.MeshRuleConstants.MESH_RULE_DATA_ID_SUFFIX;
|
||||
//import static org.mockito.Mockito.when;
|
||||
//
|
||||
//class RouterChainTest {
|
||||
//
|
||||
// /**
|
||||
// * verify the router and state router loaded by default
|
||||
// */
|
||||
// @Test
|
||||
// void testBuildRouterChain() {
|
||||
// RouterChain<DemoService> routerChain = createRouterChanin();
|
||||
// Assertions.assertEquals(0, routerChain.getRouters().size());
|
||||
// Assertions.assertEquals(7, routerChain.getStateRouters().size());
|
||||
// }
|
||||
//
|
||||
// private RouterChain<DemoService> createRouterChanin() {
|
||||
// Map<String, String> parameters = new HashMap<>();
|
||||
// parameters.put(INTERFACE_KEY, DemoService.class.getName());
|
||||
// parameters.put("registry", "zookeeper");
|
||||
// URL url = new ServiceConfigURL("dubbo",
|
||||
// "127.0.0.1",
|
||||
// 20881,
|
||||
// DemoService.class.getName(),
|
||||
// parameters);
|
||||
//
|
||||
// RouterChain<DemoService> routerChain = RouterChain.buildChain(DemoService.class, url);
|
||||
// return routerChain;
|
||||
// }
|
||||
//
|
||||
// @Test
|
||||
// void testRoute() {
|
||||
// RouterChain<DemoService> routerChain = createRouterChanin();
|
||||
//
|
||||
// // mockInvoker will be filtered out by MockInvokersSelector
|
||||
// Invoker<DemoService> mockInvoker = createMockInvoker();
|
||||
//
|
||||
// // invoker1 will be filtered out by MeshStateRouter
|
||||
// Map<String, String> map1 = new HashMap<>();
|
||||
// map1.put("env-sign", "yyyyyyy");
|
||||
// Invoker<DemoService> invoker1 = createNormalInvoker(map1);
|
||||
//
|
||||
// // invoker2 will be filtered out by TagStateRouter
|
||||
// Map<String, String> map2 = new HashMap<>();
|
||||
// map2.put("env-sign", "xxx");
|
||||
// map2.put("tag1", "hello");
|
||||
// Invoker<DemoService> invoker2 = createNormalInvoker(map2);
|
||||
//
|
||||
// // invoker3 will be filtered out by AppStateRouter
|
||||
// Map<String, String> map3 = new HashMap<>();
|
||||
// map3.put("env-sign", "xxx");
|
||||
// map3.put("tag1", "hello");
|
||||
// map3.put(TAG_KEY, "TAG_");
|
||||
// Invoker<DemoService> invoker3 = createNormalInvoker(map3);
|
||||
//
|
||||
// // invoker4 will be filtered out by ServiceStateRouter
|
||||
// Map<String, String> map4 = new HashMap<>();
|
||||
// map4.put("env-sign", "xxx");
|
||||
// map4.put("tag1", "hello");
|
||||
// map4.put(TAG_KEY, "TAG_");
|
||||
// map4.put("timeout", "5000");
|
||||
// Invoker<DemoService> invoker4 = createNormalInvoker(map4);
|
||||
//
|
||||
// // invoker5 is the only one returned at the end that is not filtered out
|
||||
// Map<String, String> map5 = new HashMap<>();
|
||||
// map5.put("env-sign", "xxx");
|
||||
// map5.put("tag1", "hello");
|
||||
// map5.put(TAG_KEY, "TAG_");
|
||||
// map5.put("timeout", "5000");
|
||||
// map5.put("serialization", "hessian2");
|
||||
// Invoker<DemoService> invoker5 = createNormalInvoker(map5);
|
||||
//
|
||||
// BitList<Invoker<DemoService>> invokers = new BitList<>(Arrays.asList(mockInvoker, invoker1, invoker2, invoker3, invoker4, invoker5));
|
||||
// routerChain.setInvokers(invokers, () -> {});
|
||||
//
|
||||
// // mesh rule for MeshStateRouter
|
||||
// MeshRuleManager meshRuleManager = mockInvoker.getUrl().getOrDefaultModuleModel().getBeanFactory().getBean(MeshRuleManager.class);
|
||||
// ConcurrentHashMap<String, MeshAppRuleListener> appRuleListeners = meshRuleManager.getAppRuleListeners();
|
||||
// MeshAppRuleListener meshAppRuleListener = appRuleListeners.get(invoker1.getUrl().getRemoteApplication());
|
||||
// ConfigChangedEvent configChangedEvent = new ConfigChangedEvent("demo-route" + MESH_RULE_DATA_ID_SUFFIX, DynamicConfiguration.DEFAULT_GROUP,
|
||||
// MESH_RULE1 + "---\n" + MESH_RULE2, ConfigChangeType.ADDED);
|
||||
// meshAppRuleListener.process(configChangedEvent);
|
||||
//
|
||||
//
|
||||
// // condition rule for AppStateRouter&ServiceStateRouter
|
||||
// ListenableStateRouter serviceRouter = routerChain.getStateRouters().stream().filter(s -> s instanceof ServiceStateRouter).map(s -> (ListenableStateRouter) s).findAny().orElse(null);
|
||||
// ConfigChangedEvent serviceConditionEvent = new ConfigChangedEvent(DynamicConfiguration.getRuleKey(mockInvoker.getUrl()) + ".condition-router", DynamicConfiguration.DEFAULT_GROUP,
|
||||
// SERVICE_CONDITION_RULE, ConfigChangeType.ADDED);
|
||||
// serviceRouter.process(serviceConditionEvent);
|
||||
//
|
||||
// ListenableStateRouter appRouter = routerChain.getStateRouters().stream().filter(s -> s instanceof AppStateRouter).map(s -> (ListenableStateRouter) s).findAny().orElse(null);
|
||||
// ConfigChangedEvent appConditionEvent = new ConfigChangedEvent("app.condition-router", DynamicConfiguration.DEFAULT_GROUP,
|
||||
// APP_CONDITION_RULE, ConfigChangeType.ADDED);
|
||||
// appRouter.process(appConditionEvent);
|
||||
//
|
||||
// // prepare consumerUrl and RpcInvocation
|
||||
// URL consumerUrl = URL.valueOf("consumer://localhost/DemoInterface?remote.application=app1");
|
||||
// RpcInvocation rpcInvocation = new RpcInvocation();
|
||||
// rpcInvocation.setServiceName("DemoService");
|
||||
// rpcInvocation.setObjectAttachment("trafficLabel", "xxx");
|
||||
// rpcInvocation.setObjectAttachment(TAG_KEY, "TAG_");
|
||||
//
|
||||
// RpcContext.getServiceContext().setNeedPrintRouterSnapshot(true);
|
||||
// RouterSnapshotSwitcher routerSnapshotSwitcher = FrameworkModel.defaultModel().getBeanFactory().getBean(RouterSnapshotSwitcher.class);
|
||||
// routerSnapshotSwitcher.addEnabledService("org.apache.dubbo.demo.DemoService");
|
||||
// // route
|
||||
// List<Invoker<DemoService>> result = routerChain.getSingleChain(consumerUrl, invokers, rpcInvocation)
|
||||
// .route(consumerUrl, invokers, rpcInvocation);
|
||||
// Assertions.assertEquals(result.size(), 1);
|
||||
// Assertions.assertTrue(result.contains(invoker5));
|
||||
//
|
||||
// String snapshotLog =
|
||||
// "[ Parent (Input: 6) (Current Node Output: 6) (Chain Node Output: 1) ] Input: localhost:9103,localhost:9103,localhost:9103,localhost:9103,localhost:9103 -> Chain Node Output: localhost:9103...\n" +
|
||||
// " [ MockInvokersSelector (Input: 6) (Current Node Output: 5) (Chain Node Output: 1) Router message: invocation.need.mock not set. Return normal Invokers. ] Current Node Output: localhost:9103,localhost:9103,localhost:9103,localhost:9103,localhost:9103\n" +
|
||||
// " [ StandardMeshRuleRouter (Input: 5) (Current Node Output: 4) (Chain Node Output: 1) Router message: Match App: app Subset: isolation ] Current Node Output: localhost:9103,localhost:9103,localhost:9103,localhost:9103\n" +
|
||||
// " [ TagStateRouter (Input: 4) (Current Node Output: 3) (Chain Node Output: 1) Router message: Disable Tag Router. Reason: tagRouterRule is invalid or disabled ] Current Node Output: localhost:9103,localhost:9103,localhost:9103\n" +
|
||||
// " [ ServiceStateRouter (Input: 3) (Current Node Output: 3) (Chain Node Output: 1) Router message: null ] Current Node Output: localhost:9103,localhost:9103,localhost:9103\n" +
|
||||
// " [ ConditionStateRouter (Input: 3) (Current Node Output: 2) (Chain Node Output: 2) Router message: Match return. ] Current Node Output: localhost:9103,localhost:9103\n" +
|
||||
// " [ ProviderAppStateRouter (Input: 2) (Current Node Output: 2) (Chain Node Output: 1) Router message: Directly return. Reason: Invokers from previous router is empty or conditionRouters is empty. ] Current Node Output: localhost:9103,localhost:9103\n" +
|
||||
// " [ AppStateRouter (Input: 2) (Current Node Output: 2) (Chain Node Output: 1) Router message: null ] Current Node Output: localhost:9103,localhost:9103\n" +
|
||||
// " [ ConditionStateRouter (Input: 2) (Current Node Output: 1) (Chain Node Output: 1) Router message: Match return. ] Current Node Output: localhost:9103\n" +
|
||||
// " [ AppScriptStateRouter (Input: 1) (Current Node Output: 1) (Chain Node Output: 1) Router message: Directly return from script router. Reason: Invokers from previous router is empty or script is not enabled. Script rule is: null ] Current Node Output: localhost:9103";
|
||||
// String[] snapshot = routerSnapshotSwitcher.cloneSnapshot();
|
||||
// Assertions.assertTrue(snapshot[0].contains(snapshotLog));
|
||||
//
|
||||
// RpcContext.getServiceContext().setNeedPrintRouterSnapshot(false);
|
||||
// result = routerChain.getSingleChain(consumerUrl, invokers, rpcInvocation)
|
||||
// .route(consumerUrl, invokers, rpcInvocation);
|
||||
// Assertions.assertEquals(result.size(), 1);
|
||||
// Assertions.assertTrue(result.contains(invoker5));
|
||||
//
|
||||
// routerChain.destroy();
|
||||
// Assertions.assertEquals(routerChain.getRouters().size(), 0);
|
||||
// Assertions.assertEquals(routerChain.getStateRouters().size(), 0);
|
||||
//
|
||||
// }
|
||||
//
|
||||
// private Invoker<DemoService> createMockInvoker() {
|
||||
// URL url = URL.valueOf("mock://localhost:9103/DemoInterface?remote.application=app");
|
||||
// Invoker<DemoService> invoker = Mockito.mock(Invoker.class);
|
||||
// when(invoker.getUrl()).thenReturn(url);
|
||||
// return invoker;
|
||||
// }
|
||||
//
|
||||
// private Invoker<DemoService> createNormalInvoker(Map<String, String> parameters) {
|
||||
// URL url = URL.valueOf("dubbo://localhost:9103/DemoInterface?remote.application=app");
|
||||
// if (CollectionUtils.isNotEmptyMap(parameters)) {
|
||||
// url = url.addParameters(parameters);
|
||||
// }
|
||||
// Invoker<DemoService> invoker = Mockito.mock(Invoker.class);
|
||||
// when(invoker.getUrl()).thenReturn(url);
|
||||
// return invoker;
|
||||
// }
|
||||
//
|
||||
//
|
||||
// private final static String MESH_RULE1 = "apiVersion: service.dubbo.apache.org/v1alpha1\n" +
|
||||
// "kind: DestinationRule\n" +
|
||||
// "metadata: { name: demo-route }\n" +
|
||||
// "spec:\n" +
|
||||
// " host: demo\n" +
|
||||
// " subsets:\n" +
|
||||
// " - labels: { env-sign: xxx, tag1: hello }\n" +
|
||||
// " name: isolation\n" +
|
||||
// " - labels: { env-sign: yyy }\n" +
|
||||
// " name: testing-trunk\n" +
|
||||
// " - labels: { env-sign: zzz }\n" +
|
||||
// " name: testing\n" +
|
||||
// " trafficPolicy:\n" +
|
||||
// " loadBalancer: { simple: ROUND_ROBIN }\n" +
|
||||
// "\n";
|
||||
//
|
||||
// private final static String MESH_RULE2 = "apiVersion: service.dubbo.apache.org/v1alpha1\n" +
|
||||
// "kind: VirtualService\n" +
|
||||
// "metadata: { name: demo-route }\n" +
|
||||
// "spec:\n" +
|
||||
// " dubbo:\n" +
|
||||
// " - routedetail:\n" +
|
||||
// " - match:\n" +
|
||||
// " - attachments: \n" +
|
||||
// " dubboContext: {trafficLabel: {regex: xxx}}\n" +
|
||||
// " name: xxx-project\n" +
|
||||
// " route:\n" +
|
||||
// " - destination: {host: demo, subset: isolation}\n" +
|
||||
// " services:\n" +
|
||||
// " - {regex: DemoService}\n" +
|
||||
// " hosts: [demo]\n";
|
||||
//
|
||||
// private static final String APP_CONDITION_RULE = "scope: application\n" +
|
||||
// "force: true\n" +
|
||||
// "runtime: false\n" +
|
||||
// "enabled: true\n" +
|
||||
// "priority: 1\n" +
|
||||
// "key: demo-consumer\n" +
|
||||
// "conditions:\n" +
|
||||
// "- => serialization=hessian2";
|
||||
//
|
||||
// private static final String SERVICE_CONDITION_RULE = "scope: service\n" +
|
||||
// "force: true\n" +
|
||||
// "runtime: false\n" +
|
||||
// "enabled: true\n" +
|
||||
// "priority: 1\n" +
|
||||
// "key: org.apache.dubbo.demo.DemoService\n" +
|
||||
// "conditions:\n" +
|
||||
// "- => timeout=5000";
|
||||
//}
|
||||
|
|
|
|||
|
|
@ -1,84 +0,0 @@
|
|||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
* contributor license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright ownership.
|
||||
* The ASF licenses this file to You under the Apache License, Version 2.0
|
||||
* (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.apache.dubbo.rpc.cluster.filter;
|
||||
|
||||
import org.apache.dubbo.config.ApplicationConfig;
|
||||
import org.apache.dubbo.config.TracingConfig;
|
||||
import org.apache.dubbo.rpc.AppResponse;
|
||||
import org.apache.dubbo.rpc.BaseFilter;
|
||||
import org.apache.dubbo.rpc.Invoker;
|
||||
import org.apache.dubbo.rpc.RpcInvocation;
|
||||
import org.apache.dubbo.rpc.model.ApplicationModel;
|
||||
|
||||
import io.micrometer.tracing.test.SampleTestRunner;
|
||||
import org.junit.jupiter.api.AfterEach;
|
||||
|
||||
import static org.mockito.BDDMockito.given;
|
||||
import static org.mockito.Mockito.mock;
|
||||
|
||||
abstract class AbstractObservationFilterTest extends SampleTestRunner {
|
||||
|
||||
ApplicationModel applicationModel;
|
||||
RpcInvocation invocation;
|
||||
|
||||
BaseFilter filter;
|
||||
|
||||
Invoker<?> invoker = mock(Invoker.class);
|
||||
|
||||
static final String INTERFACE_NAME = "org.apache.dubbo.MockInterface";
|
||||
static final String METHOD_NAME = "mockMethod";
|
||||
static final String GROUP = "mockGroup";
|
||||
static final String VERSION = "1.0.0";
|
||||
|
||||
@AfterEach
|
||||
public void teardown() {
|
||||
if (applicationModel != null) {
|
||||
applicationModel.destroy();
|
||||
}
|
||||
}
|
||||
|
||||
abstract BaseFilter createFilter(ApplicationModel applicationModel);
|
||||
|
||||
void setupConfig() {
|
||||
ApplicationConfig config = new ApplicationConfig();
|
||||
config.setName("MockObservations");
|
||||
|
||||
applicationModel = ApplicationModel.defaultModel();
|
||||
applicationModel.getApplicationConfigManager().setApplication(config);
|
||||
|
||||
invocation = new RpcInvocation(new MockInvocation());
|
||||
invocation.addInvokedInvoker(invoker);
|
||||
|
||||
applicationModel.getBeanFactory().registerBean(getObservationRegistry());
|
||||
TracingConfig tracingConfig = new TracingConfig();
|
||||
tracingConfig.setEnabled(true);
|
||||
applicationModel.getApplicationConfigManager().setTracing(tracingConfig);
|
||||
|
||||
filter = createFilter(applicationModel);
|
||||
|
||||
given(invoker.invoke(invocation)).willReturn(new AppResponse("success"));
|
||||
|
||||
initParam();
|
||||
}
|
||||
|
||||
private void initParam() {
|
||||
invocation.setTargetServiceUniqueName(GROUP + "/" + INTERFACE_NAME + ":" + VERSION);
|
||||
invocation.setMethodName(METHOD_NAME);
|
||||
invocation.setParameterTypes(new Class[] {String.class});
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -60,7 +60,6 @@ import static org.apache.dubbo.common.constants.CommonConstants.MONITOR_KEY;
|
|||
import static org.apache.dubbo.common.constants.CommonConstants.PATH_KEY;
|
||||
import static org.apache.dubbo.common.constants.CommonConstants.PROTOCOL_KEY;
|
||||
import static org.apache.dubbo.rpc.cluster.Constants.CLUSTER_AVAILABLE_CHECK_KEY;
|
||||
import static org.apache.dubbo.rpc.cluster.Constants.INVOCATION_NEED_MOCK;
|
||||
import static org.apache.dubbo.rpc.cluster.Constants.REFER_KEY;
|
||||
import static org.mockito.ArgumentMatchers.eq;
|
||||
import static org.mockito.ArgumentMatchers.same;
|
||||
|
|
@ -576,26 +575,6 @@ class AbstractClusterInvokerTest {
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Test mock invoker selector works as expected
|
||||
*/
|
||||
@Test
|
||||
void testMockedInvokerSelect() {
|
||||
initlistsize5();
|
||||
invokers.add(mockedInvoker1);
|
||||
|
||||
initDic();
|
||||
|
||||
RpcInvocation mockedInvocation = new RpcInvocation();
|
||||
mockedInvocation.setMethodName("sayHello");
|
||||
mockedInvocation.setAttachment(INVOCATION_NEED_MOCK, "true");
|
||||
List<Invoker<IHelloService>> mockedInvokers = dic.list(mockedInvocation);
|
||||
Assertions.assertEquals(1, mockedInvokers.size());
|
||||
|
||||
List<Invoker<IHelloService>> invokers = dic.list(invocation);
|
||||
Assertions.assertEquals(5, invokers.size());
|
||||
}
|
||||
|
||||
public static interface IHelloService {
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -0,0 +1,83 @@
|
|||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
* contributor license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright ownership.
|
||||
* The ASF licenses this file to You under the Apache License, Version 2.0
|
||||
* (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.apache.dubbo.common;
|
||||
|
||||
import org.apache.dubbo.common.constants.DeprecatedMethodInvocationCounterConstants;
|
||||
import org.apache.dubbo.common.logger.ErrorTypeAwareLogger;
|
||||
import org.apache.dubbo.common.logger.LoggerFactory;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
import java.util.concurrent.atomic.LongAdder;
|
||||
|
||||
/**
|
||||
* Deprecated method invocation counter, which is used by annotation processor.
|
||||
* <p>
|
||||
* If an IDE says it is unused, just ignore it.
|
||||
*/
|
||||
public final class DeprecatedMethodInvocationCounter {
|
||||
private DeprecatedMethodInvocationCounter() {
|
||||
throw new UnsupportedOperationException("No instance of DeprecatedMethodInvocationCounter for you! ");
|
||||
}
|
||||
|
||||
private static final ConcurrentHashMap<String, LongAdder> COUNTERS = new ConcurrentHashMap<>();
|
||||
|
||||
private static final ErrorTypeAwareLogger LOGGER = LoggerFactory.getErrorTypeAwareLogger(DeprecatedMethodInvocationCounter.class);
|
||||
|
||||
/**
|
||||
* Invoked by (modified) deprecated method.
|
||||
*
|
||||
* @param methodDefinition filled by annotation processor. (like 'org.apache.dubbo.common.URL.getServiceName()')
|
||||
*/
|
||||
public static void onDeprecatedMethodCalled(String methodDefinition) {
|
||||
if (!hasThisMethodInvoked(methodDefinition)) {
|
||||
LOGGER.warn(
|
||||
DeprecatedMethodInvocationCounterConstants.ERROR_CODE,
|
||||
DeprecatedMethodInvocationCounterConstants.POSSIBLE_CAUSE,
|
||||
DeprecatedMethodInvocationCounterConstants.EXTENDED_MESSAGE,
|
||||
DeprecatedMethodInvocationCounterConstants.LOGGER_MESSAGE_PREFIX + methodDefinition
|
||||
);
|
||||
}
|
||||
|
||||
increaseInvocationCount(methodDefinition);
|
||||
}
|
||||
|
||||
private static void increaseInvocationCount(String methodDefinition) {
|
||||
COUNTERS.computeIfAbsent(methodDefinition, k -> new LongAdder());
|
||||
LongAdder adder = COUNTERS.get(methodDefinition);
|
||||
|
||||
adder.increment();
|
||||
}
|
||||
|
||||
public static boolean hasThisMethodInvoked(String methodDefinition) {
|
||||
return COUNTERS.containsKey(methodDefinition);
|
||||
}
|
||||
|
||||
public static Map<String, Integer> getInvocationRecord() {
|
||||
// Perform a deep-copy to avoid concurrent issues.
|
||||
HashMap<String, Integer> copyOfCounters = new HashMap<>();
|
||||
|
||||
for (Map.Entry<String, LongAdder> entry : COUNTERS.entrySet()) {
|
||||
copyOfCounters.put(entry.getKey(), entry.getValue().intValue());
|
||||
}
|
||||
|
||||
return Collections.unmodifiableMap(copyOfCounters);
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,34 @@
|
|||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
* contributor license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright ownership.
|
||||
* The ASF licenses this file to You under the Apache License, Version 2.0
|
||||
* (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.apache.dubbo.common.aot;
|
||||
|
||||
|
||||
public abstract class NativeDetector {
|
||||
|
||||
/**
|
||||
* See https://github.com/oracle/graal/blob/master/sdk/src/org.graalvm.nativeimage/src/org/graalvm/nativeimage/ImageInfo.java
|
||||
*/
|
||||
private static final boolean IMAGE_CODE = (System.getProperty("org.graalvm.nativeimage.imagecode") != null);
|
||||
|
||||
/**
|
||||
* Returns {@code true} if invoked in the context of image building or during image runtime, else {@code false}.
|
||||
*/
|
||||
public static boolean inNativeImage() {
|
||||
return IMAGE_CODE;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -158,14 +158,6 @@ public class FileCacheStore {
|
|||
FileCacheStoreFactory.removeCache(cacheFilePath);
|
||||
}
|
||||
|
||||
/**
|
||||
* for unit test only
|
||||
*/
|
||||
@Deprecated
|
||||
protected String getCacheFilePath() {
|
||||
return cacheFilePath;
|
||||
}
|
||||
|
||||
public static Builder newBuilder() {
|
||||
return new Builder();
|
||||
}
|
||||
|
|
|
|||
|
|
@ -31,7 +31,6 @@ import java.nio.file.Files;
|
|||
import java.nio.file.Path;
|
||||
import java.util.Collections;
|
||||
import java.util.HashSet;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
import java.util.concurrent.ConcurrentMap;
|
||||
|
|
@ -197,14 +196,6 @@ public final class FileCacheStoreFactory {
|
|||
cacheMap.remove(cacheFileName);
|
||||
}
|
||||
|
||||
/**
|
||||
* for unit test only
|
||||
*/
|
||||
@Deprecated
|
||||
static Map<String, FileCacheStore> getCacheMap() {
|
||||
return cacheMap;
|
||||
}
|
||||
|
||||
private static class PathNotExclusiveException extends Exception {
|
||||
public PathNotExclusiveException(String msg) {
|
||||
super(msg);
|
||||
|
|
|
|||
|
|
@ -17,7 +17,6 @@
|
|||
package org.apache.dubbo.common.config.configcenter;
|
||||
|
||||
import org.apache.dubbo.common.URL;
|
||||
import org.apache.dubbo.common.config.configcenter.file.FileSystemDynamicConfiguration;
|
||||
import org.apache.dubbo.common.utils.StringUtils;
|
||||
|
||||
import java.util.Collection;
|
||||
|
|
@ -30,7 +29,7 @@ import static org.apache.dubbo.common.utils.PathUtils.normalize;
|
|||
/**
|
||||
* An abstract implementation of {@link DynamicConfiguration} is like "tree-structure" path :
|
||||
* <ul>
|
||||
* <li>{@link FileSystemDynamicConfiguration "file"}</li>
|
||||
* <li>{@link org.apache.dubbo.common.config.configcenter.file.FileSystemDynamicConfiguration "file"}</li>
|
||||
* <li>{@link org.apache.dubbo.configcenter.support.zookeeper.ZookeeperDynamicConfiguration "zookeeper"}</li>
|
||||
* <li>{@link org.apache.dubbo.configcenter.consul.ConsulDynamicConfiguration "consul"}</li>
|
||||
* </ul>
|
||||
|
|
|
|||
|
|
@ -128,6 +128,8 @@ public interface CommonConstants {
|
|||
|
||||
String THREAD_POOL_EXHAUSTED_LISTENERS_KEY = "thread-pool-exhausted-listeners";
|
||||
|
||||
String JSON_CHECK_LEVEL_KEY = "jsonCheckLevel";
|
||||
|
||||
String THREADS_KEY = "threads";
|
||||
|
||||
String QUEUES_KEY = "queues";
|
||||
|
|
@ -285,6 +287,7 @@ public interface CommonConstants {
|
|||
String MONITOR_KEY = "monitor";
|
||||
String BACKGROUND_KEY = "background";
|
||||
String CLUSTER_KEY = "cluster";
|
||||
String MERGEABLE_CLUSTER_NAME = "mergeable";
|
||||
String USERNAME_KEY = "username";
|
||||
String PASSWORD_KEY = "password";
|
||||
String HOST_KEY = "host";
|
||||
|
|
@ -334,6 +337,8 @@ public interface CommonConstants {
|
|||
|
||||
String REGISTRY_PROTOCOL_LISTENER_KEY = "registry.protocol.listener";
|
||||
|
||||
String REGISTRY_SERVICE_CLASS_NAME = "org.apache.dubbo.registry.RegistryService";
|
||||
|
||||
String DUBBO_VERSION_KEY = "dubbo";
|
||||
|
||||
String TAG_KEY = "dubbo.tag";
|
||||
|
|
@ -500,11 +505,6 @@ public interface CommonConstants {
|
|||
*/
|
||||
String URL_MERGE_PROCESSOR_KEY = "url-merge-processor";
|
||||
|
||||
/**
|
||||
* use native image to compile dubbo's identifier
|
||||
*/
|
||||
String NATIVE = "native";
|
||||
|
||||
String DUBBO_MONITOR_ADDRESS = "dubbo.monitor.address";
|
||||
|
||||
String SERVICE_NAME_MAPPING_KEY = "service-name-mapping";
|
||||
|
|
@ -618,9 +618,7 @@ public interface CommonConstants {
|
|||
|
||||
|
||||
/**
|
||||
*
|
||||
* used in JVMUtil.java ,Control stack print lines, default is 32 lines
|
||||
*
|
||||
*/
|
||||
String DUBBO_JSTACK_MAXLINE = "dubbo.jstack-dump.max-line";
|
||||
|
||||
|
|
@ -643,7 +641,11 @@ public interface CommonConstants {
|
|||
|
||||
String DUBBO_PACKABLE_METHOD_FACTORY = "dubbo.application.parameters." + PACKABLE_METHOD_FACTORY_KEY;
|
||||
|
||||
String RESTEASY_NETTY_HTTP_REQUEST_ATTRIBUTE_KEY = "resteasyNettyHttpRequest";
|
||||
String DUBBO_TAG_HEADER = "dubbo-tag";
|
||||
|
||||
String REST_SERVICE_DEPLOYER_URL_ATTRIBUTE_KEY = "restServiceDeployerAttributeKey";
|
||||
|
||||
String SERVICE_DEPLOYER_ATTRIBUTE_KEY = "serviceDeployer"; String RESTEASY_NETTY_HTTP_REQUEST_ATTRIBUTE_KEY = "resteasyNettyHttpRequest";
|
||||
|
||||
String DUBBO_MANUAL_REGISTER_KEY = "dubbo.application.manual-register";
|
||||
}
|
||||
|
|
|
|||
|
|
@ -0,0 +1,35 @@
|
|||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
* contributor license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright ownership.
|
||||
* The ASF licenses this file to You under the Apache License, Version 2.0
|
||||
* (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.apache.dubbo.common.constants;
|
||||
|
||||
/**
|
||||
* Constants of Deprecated Method Invocation Counter.
|
||||
*/
|
||||
public final class DeprecatedMethodInvocationCounterConstants {
|
||||
private DeprecatedMethodInvocationCounterConstants() {
|
||||
throw new UnsupportedOperationException("No instance of DeprecatedMethodInvocationCounterConstants for you! ");
|
||||
}
|
||||
|
||||
public static final String ERROR_CODE = LoggerCodeConstants.COMMON_DEPRECATED_METHOD_INVOKED;
|
||||
|
||||
public static final String POSSIBLE_CAUSE = "invocation of deprecated method";
|
||||
|
||||
public static final String EXTENDED_MESSAGE = "";
|
||||
|
||||
public static final String LOGGER_MESSAGE_PREFIX = "Deprecated method invoked. The method is ";
|
||||
}
|
||||
|
|
@ -92,6 +92,12 @@ public interface LoggerCodeConstants {
|
|||
|
||||
String VULNERABILITY_WARNING = "0-28";
|
||||
|
||||
String COMMON_NOT_FOUND_TRACER_DEPENDENCY = "0-29";
|
||||
|
||||
/**
|
||||
* Used in annotation processor to indicate a deprecated method is invoked.
|
||||
*/
|
||||
String COMMON_DEPRECATED_METHOD_INVOKED = "0-99";
|
||||
|
||||
// Registry module
|
||||
|
||||
|
|
|
|||
|
|
@ -47,6 +47,8 @@ public interface MetricsConstants {
|
|||
|
||||
String TAG_CHANGE_TYPE = "change.type";
|
||||
|
||||
String TAG_ERROR_CODE = "error";
|
||||
|
||||
String ENABLE_JVM_METRICS_KEY = "enable.jvm";
|
||||
|
||||
String AGGREGATION_COLLECTOR_KEY = "aggregation";
|
||||
|
|
|
|||
|
|
@ -22,6 +22,8 @@ import org.apache.dubbo.rpc.model.ScopeModel;
|
|||
|
||||
import java.util.List;
|
||||
import java.util.concurrent.CopyOnWriteArrayList;
|
||||
import java.util.concurrent.atomic.AtomicBoolean;
|
||||
import java.util.concurrent.atomic.AtomicReference;
|
||||
|
||||
import static org.apache.dubbo.common.constants.LoggerCodeConstants.COMMON_MONITOR_EXCEPTION;
|
||||
import static org.apache.dubbo.common.deploy.DeployState.FAILED;
|
||||
|
|
@ -35,14 +37,13 @@ public abstract class AbstractDeployer<E extends ScopeModel> implements Deployer
|
|||
|
||||
private static final ErrorTypeAwareLogger logger = LoggerFactory.getErrorTypeAwareLogger(AbstractDeployer.class);
|
||||
|
||||
private volatile DeployState state = PENDING;
|
||||
protected AtomicReference<DeployState> state = new AtomicReference<>(PENDING);
|
||||
|
||||
private volatile Throwable lastError;
|
||||
protected AtomicReference<Throwable> lastError = new AtomicReference<>();
|
||||
|
||||
protected volatile boolean initialized = false;
|
||||
protected AtomicBoolean initialized = new AtomicBoolean(false);
|
||||
|
||||
protected List<DeployListener<E>> listeners = new CopyOnWriteArrayList<>();
|
||||
|
||||
private E scopeModel;
|
||||
|
||||
public AbstractDeployer(E scopeModel) {
|
||||
|
|
@ -51,46 +52,47 @@ public abstract class AbstractDeployer<E extends ScopeModel> implements Deployer
|
|||
|
||||
@Override
|
||||
public boolean isPending() {
|
||||
return state == PENDING;
|
||||
return state.get().equals(PENDING);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isRunning() {
|
||||
return state == STARTING || state == STARTED;
|
||||
return state.get().equals(STARTING) || state.get().equals(STARTED);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isStarted() {
|
||||
return state == STARTED;
|
||||
return state.get().equals(STARTED);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isStarting() {
|
||||
return state == STARTING;
|
||||
return state.get().equals(STARTING);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isStopping() {
|
||||
return state == STOPPING;
|
||||
return state.get().equals(STOPPING);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isStopped() {
|
||||
return state == STOPPED;
|
||||
return state.get().equals(STOPPED);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isFailed() {
|
||||
return state == FAILED;
|
||||
return state.get().equals(FAILED);
|
||||
}
|
||||
|
||||
@Override
|
||||
public DeployState getState() {
|
||||
return state;
|
||||
return state.get();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void addDeployListener(DeployListener<E> listener) {
|
||||
scopeModel.getBeanFactory().registerBean(listener);
|
||||
listeners.add(listener);
|
||||
}
|
||||
|
||||
|
|
@ -100,11 +102,11 @@ public abstract class AbstractDeployer<E extends ScopeModel> implements Deployer
|
|||
}
|
||||
|
||||
public void setPending() {
|
||||
this.state = PENDING;
|
||||
this.state.set(PENDING);
|
||||
}
|
||||
|
||||
protected void setStarting() {
|
||||
this.state = STARTING;
|
||||
this.state.set(STARTING);
|
||||
for (DeployListener<E> listener : listeners) {
|
||||
try {
|
||||
listener.onStarting(scopeModel);
|
||||
|
|
@ -115,7 +117,7 @@ public abstract class AbstractDeployer<E extends ScopeModel> implements Deployer
|
|||
}
|
||||
|
||||
protected void setStarted() {
|
||||
this.state = STARTED;
|
||||
this.state.set(STARTED);
|
||||
for (DeployListener<E> listener : listeners) {
|
||||
try {
|
||||
listener.onStarted(scopeModel);
|
||||
|
|
@ -126,7 +128,7 @@ public abstract class AbstractDeployer<E extends ScopeModel> implements Deployer
|
|||
}
|
||||
|
||||
protected void setStopping() {
|
||||
this.state = STOPPING;
|
||||
this.state.set(STOPPING);
|
||||
for (DeployListener<E> listener : listeners) {
|
||||
try {
|
||||
listener.onStopping(scopeModel);
|
||||
|
|
@ -137,7 +139,7 @@ public abstract class AbstractDeployer<E extends ScopeModel> implements Deployer
|
|||
}
|
||||
|
||||
protected void setStopped() {
|
||||
this.state = STOPPED;
|
||||
this.state.set(STOPPED);
|
||||
for (DeployListener<E> listener : listeners) {
|
||||
try {
|
||||
listener.onStopped(scopeModel);
|
||||
|
|
@ -148,8 +150,8 @@ public abstract class AbstractDeployer<E extends ScopeModel> implements Deployer
|
|||
}
|
||||
|
||||
protected void setFailed(Throwable error) {
|
||||
this.state = FAILED;
|
||||
this.lastError = error;
|
||||
this.state.set(FAILED);
|
||||
this.lastError.set(error);
|
||||
for (DeployListener<E> listener : listeners) {
|
||||
try {
|
||||
listener.onFailure(scopeModel, error);
|
||||
|
|
@ -161,14 +163,26 @@ public abstract class AbstractDeployer<E extends ScopeModel> implements Deployer
|
|||
|
||||
@Override
|
||||
public Throwable getError() {
|
||||
return lastError;
|
||||
return lastError.get();
|
||||
}
|
||||
|
||||
public boolean isInitialized() {
|
||||
return initialized;
|
||||
return initialized.get();
|
||||
}
|
||||
|
||||
protected String getIdentifier() {
|
||||
return scopeModel.getDesc();
|
||||
}
|
||||
|
||||
public AtomicBoolean getInitialized() {
|
||||
return initialized;
|
||||
}
|
||||
|
||||
public AtomicReference<Throwable> getErrorRef() {
|
||||
return lastError;
|
||||
}
|
||||
|
||||
public AtomicReference<DeployState> getStateRef(){
|
||||
return state;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -18,6 +18,7 @@ package org.apache.dubbo.common.extension;
|
|||
|
||||
import org.apache.dubbo.common.Extension;
|
||||
import org.apache.dubbo.common.URL;
|
||||
import org.apache.dubbo.common.aot.NativeDetector;
|
||||
import org.apache.dubbo.common.beans.support.InstantiationStrategy;
|
||||
import org.apache.dubbo.common.context.Lifecycle;
|
||||
import org.apache.dubbo.common.extension.support.ActivateComparator;
|
||||
|
|
@ -33,7 +34,6 @@ import org.apache.dubbo.common.utils.CollectionUtils;
|
|||
import org.apache.dubbo.common.utils.ConcurrentHashSet;
|
||||
import org.apache.dubbo.common.utils.ConfigUtils;
|
||||
import org.apache.dubbo.common.utils.Holder;
|
||||
import org.apache.dubbo.common.utils.NativeUtils;
|
||||
import org.apache.dubbo.common.utils.ReflectUtils;
|
||||
import org.apache.dubbo.common.utils.StringUtils;
|
||||
import org.apache.dubbo.rpc.model.ApplicationModel;
|
||||
|
|
@ -1412,7 +1412,7 @@ public class ExtensionLoader<T> {
|
|||
// Adaptive Classes' ClassLoader should be the same with Real SPI interface classes' ClassLoader
|
||||
ClassLoader classLoader = type.getClassLoader();
|
||||
try {
|
||||
if (NativeUtils.isNative()) {
|
||||
if (NativeDetector.inNativeImage()) {
|
||||
return classLoader.loadClass(type.getName() + "$Adaptive");
|
||||
}
|
||||
} catch (Throwable ignore) {
|
||||
|
|
|
|||
|
|
@ -60,6 +60,17 @@ public class GsonUtils {
|
|||
}
|
||||
}
|
||||
|
||||
public static String toJson(Object obj) throws RuntimeException {
|
||||
if (!isSupportGson()) {
|
||||
throw new RuntimeException("Gson is not supported. Please import Gson in JVM env.");
|
||||
}
|
||||
try {
|
||||
return getGson().toJson(obj);
|
||||
} catch (JsonSyntaxException ex) {
|
||||
throw new RuntimeException(String.format("Generic serialization [%s] Json syntax exception thrown when parsing (object:%s ) error:%s", GENERIC_SERIALIZATION_GSON, obj, ex.getMessage()));
|
||||
}
|
||||
}
|
||||
|
||||
private static Gson getGson() {
|
||||
if (gsonCache == null || !(gsonCache instanceof Gson)) {
|
||||
synchronized (GsonUtils.class) {
|
||||
|
|
|
|||
|
|
@ -16,11 +16,14 @@
|
|||
*/
|
||||
package org.apache.dubbo.common.json;
|
||||
|
||||
import org.apache.dubbo.common.extension.SPI;
|
||||
|
||||
import java.lang.reflect.Type;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
public interface JSON {
|
||||
@SPI
|
||||
public interface JsonUtil {
|
||||
boolean isSupport();
|
||||
|
||||
<T> T toJavaObject(String json, Type type);
|
||||
|
|
@ -16,7 +16,7 @@
|
|||
*/
|
||||
package org.apache.dubbo.common.json.impl;
|
||||
|
||||
import org.apache.dubbo.common.json.JSON;
|
||||
import org.apache.dubbo.common.json.JsonUtil;
|
||||
import org.apache.dubbo.common.utils.CollectionUtils;
|
||||
|
||||
import java.util.HashMap;
|
||||
|
|
@ -24,7 +24,7 @@ import java.util.LinkedList;
|
|||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
public abstract class AbstractJSONImpl implements JSON {
|
||||
public abstract class AbstractJsonUtilImpl implements JsonUtil {
|
||||
@Override
|
||||
public boolean isSupport() {
|
||||
try {
|
||||
|
|
@ -21,7 +21,7 @@ import com.alibaba.fastjson2.JSONWriter;
|
|||
import java.lang.reflect.Type;
|
||||
import java.util.List;
|
||||
|
||||
public class FastJson2Impl extends AbstractJSONImpl {
|
||||
public class FastJson2Impl extends AbstractJsonUtilImpl {
|
||||
@Override
|
||||
public <T> T toJavaObject(String json, Type type) {
|
||||
return com.alibaba.fastjson2.JSON.parseObject(json, type);
|
||||
|
|
|
|||
|
|
@ -21,7 +21,7 @@ import com.alibaba.fastjson.serializer.SerializerFeature;
|
|||
import java.lang.reflect.Type;
|
||||
import java.util.List;
|
||||
|
||||
public class FastJsonImpl extends AbstractJSONImpl {
|
||||
public class FastJsonImpl extends AbstractJsonUtilImpl {
|
||||
|
||||
@Override
|
||||
public <T> T toJavaObject(String json, Type type) {
|
||||
|
|
|
|||
|
|
@ -22,7 +22,7 @@ import com.google.gson.reflect.TypeToken;
|
|||
import java.lang.reflect.Type;
|
||||
import java.util.List;
|
||||
|
||||
public class GsonImpl extends AbstractJSONImpl {
|
||||
public class GsonImpl extends AbstractJsonUtilImpl {
|
||||
// weak reference of com.google.gson.Gson, prevent throw exception when init
|
||||
private volatile Object gsonCache = null;
|
||||
|
||||
|
|
|
|||
|
|
@ -26,7 +26,7 @@ import com.fasterxml.jackson.datatype.jsr310.JavaTimeModule;
|
|||
import java.lang.reflect.Type;
|
||||
import java.util.List;
|
||||
|
||||
public class JacksonImpl extends AbstractJSONImpl {
|
||||
public class JacksonImpl extends AbstractJsonUtilImpl {
|
||||
private final ObjectMapper objectMapper = new ObjectMapper();
|
||||
|
||||
private volatile Object jacksonCache = null;
|
||||
|
|
|
|||
|
|
@ -0,0 +1,32 @@
|
|||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
* contributor license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright ownership.
|
||||
* The ASF licenses this file to You under the Apache License, Version 2.0
|
||||
* (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.apache.dubbo.common.logger;
|
||||
|
||||
/**
|
||||
* Loggers that can register to listen to log messages.
|
||||
*/
|
||||
public interface ListenableLogger extends ErrorTypeAwareLogger{
|
||||
|
||||
/**
|
||||
* Register a listener to this logger,and get notified when a log happens.
|
||||
*
|
||||
* @param listener log listener
|
||||
*/
|
||||
void registerListen(LogListener listener);
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,27 @@
|
|||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
* contributor license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright ownership.
|
||||
* The ASF licenses this file to You under the Apache License, Version 2.0
|
||||
* (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.apache.dubbo.common.logger;
|
||||
|
||||
/**
|
||||
* Log Listener, can registered to an {@link ListenableLogger}.
|
||||
*/
|
||||
public interface LogListener {
|
||||
|
||||
void onMessage(String code, String msg);
|
||||
|
||||
}
|
||||
|
|
@ -30,6 +30,14 @@ public interface Logger {
|
|||
*/
|
||||
void trace(String msg);
|
||||
|
||||
/**
|
||||
* Logs a message with trace log level.
|
||||
*
|
||||
* @param msg log this message
|
||||
* @param arguments a list of arguments
|
||||
*/
|
||||
void trace(String msg, Object... arguments);
|
||||
|
||||
/**
|
||||
* Logs an error with trace log level.
|
||||
*
|
||||
|
|
@ -52,6 +60,14 @@ public interface Logger {
|
|||
*/
|
||||
void debug(String msg);
|
||||
|
||||
/**
|
||||
* Logs a message with debug log level.
|
||||
*
|
||||
* @param msg log this message
|
||||
* @param arguments a list of arguments
|
||||
*/
|
||||
void debug(String msg, Object... arguments);
|
||||
|
||||
/**
|
||||
* Logs an error with debug log level.
|
||||
*
|
||||
|
|
@ -74,6 +90,14 @@ public interface Logger {
|
|||
*/
|
||||
void info(String msg);
|
||||
|
||||
/**
|
||||
* Logs a message with info log level.
|
||||
*
|
||||
* @param msg log this message
|
||||
* @param arguments a list of arguments
|
||||
*/
|
||||
void info(String msg, Object... arguments);
|
||||
|
||||
/**
|
||||
* Logs an error with info log level.
|
||||
*
|
||||
|
|
@ -96,6 +120,14 @@ public interface Logger {
|
|||
*/
|
||||
void warn(String msg);
|
||||
|
||||
/**
|
||||
* Logs a message with warn log level.
|
||||
*
|
||||
* @param msg log this message
|
||||
* @param arguments a list of arguments
|
||||
*/
|
||||
void warn(String msg, Object... arguments);
|
||||
|
||||
/**
|
||||
* Logs a message with warn log level.
|
||||
*
|
||||
|
|
@ -118,6 +150,14 @@ public interface Logger {
|
|||
*/
|
||||
void error(String msg);
|
||||
|
||||
/**
|
||||
* Logs a message with error log level.
|
||||
*
|
||||
* @param msg log this message
|
||||
* @param arguments a list of arguments
|
||||
*/
|
||||
void error(String msg, Object... arguments);
|
||||
|
||||
/**
|
||||
* Logs an error with error log level.
|
||||
*
|
||||
|
|
|
|||
|
|
@ -0,0 +1,63 @@
|
|||
/*
|
||||
* Copyright (c) 2004-2011 QOS.ch
|
||||
* All rights reserved.
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining
|
||||
* a copy of this software and associated documentation files (the
|
||||
* "Software"), to deal in the Software without restriction, including
|
||||
* without limitation the rights to use, copy, modify, merge, publish,
|
||||
* distribute, sublicense, and/or sell copies of the Software, and to
|
||||
* permit persons to whom the Software is furnished to do so, subject to
|
||||
* the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be
|
||||
* included in all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
||||
* LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
||||
* OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
||||
* WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
*
|
||||
*/
|
||||
package org.apache.dubbo.common.logger.helpers;
|
||||
|
||||
/**
|
||||
* Holds the results of formatting done by {@link MessageFormatter}.
|
||||
* This is a copy of org.slf4j.helpers.FormattingTuple from slf4j-api.
|
||||
*
|
||||
* @author Joern Huxhorn
|
||||
*/
|
||||
public class FormattingTuple {
|
||||
|
||||
static public FormattingTuple NULL = new FormattingTuple(null);
|
||||
|
||||
private String message;
|
||||
private Throwable throwable;
|
||||
private Object[] argArray;
|
||||
|
||||
public FormattingTuple(String message) {
|
||||
this(message, null, null);
|
||||
}
|
||||
|
||||
public FormattingTuple(String message, Object[] argArray, Throwable throwable) {
|
||||
this.message = message;
|
||||
this.throwable = throwable;
|
||||
this.argArray = argArray;
|
||||
}
|
||||
|
||||
public String getMessage() {
|
||||
return message;
|
||||
}
|
||||
|
||||
public Object[] getArgArray() {
|
||||
return argArray;
|
||||
}
|
||||
|
||||
public Throwable getThrowable() {
|
||||
return throwable;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,437 @@
|
|||
/*
|
||||
* Copyright (c) 2004-2011 QOS.ch
|
||||
* All rights reserved.
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining
|
||||
* a copy of this software and associated documentation files (the
|
||||
* "Software"), to deal in the Software without restriction, including
|
||||
* without limitation the rights to use, copy, modify, merge, publish,
|
||||
* distribute, sublicense, and/or sell copies of the Software, and to
|
||||
* permit persons to whom the Software is furnished to do so, subject to
|
||||
* the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be
|
||||
* included in all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
||||
* LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
||||
* OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
||||
* WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
*
|
||||
*/
|
||||
package org.apache.dubbo.common.logger.helpers;
|
||||
|
||||
import java.text.MessageFormat;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
// contributors: lizongbo: proposed special treatment of array parameter values
|
||||
// Joern Huxhorn: pointed out double[] omission, suggested deep array copy
|
||||
|
||||
/**
|
||||
* This is a copy of org.slf4j.helpers.MessageFormatter from slf4j-api.
|
||||
* Formats messages according to very simple substitution rules. Substitutions
|
||||
* can be made 1, 2 or more arguments.
|
||||
*
|
||||
* <p>
|
||||
* For example,
|
||||
*
|
||||
* <pre>
|
||||
* MessageFormatter.format("Hi {}.", "there")
|
||||
* </pre>
|
||||
* <p>
|
||||
* will return the string "Hi there.".
|
||||
* <p>
|
||||
* The {} pair is called the <em>formatting anchor</em>. It serves to designate
|
||||
* the location where arguments need to be substituted within the message
|
||||
* pattern.
|
||||
* <p>
|
||||
* In case your message contains the '{' or the '}' character, you do not have
|
||||
* to do anything special unless the '}' character immediately follows '{'. For
|
||||
* example,
|
||||
*
|
||||
* <pre>
|
||||
* MessageFormatter.format("Set {1,2,3} is not equal to {}.", "1,2");
|
||||
* </pre>
|
||||
* <p>
|
||||
* will return the string "Set {1,2,3} is not equal to 1,2.".
|
||||
*
|
||||
* <p>
|
||||
* If for whatever reason you need to place the string "{}" in the message
|
||||
* without its <em>formatting anchor</em> meaning, then you need to escape the
|
||||
* '{' character with '\', that is the backslash character. Only the '{'
|
||||
* character should be escaped. There is no need to escape the '}' character.
|
||||
* For example,
|
||||
*
|
||||
* <pre>
|
||||
* MessageFormatter.format("Set \\{} is not equal to {}.", "1,2");
|
||||
* </pre>
|
||||
* <p>
|
||||
* will return the string "Set {} is not equal to 1,2.".
|
||||
*
|
||||
* <p>
|
||||
* The escaping behavior just described can be overridden by escaping the escape
|
||||
* character '\'. Calling
|
||||
*
|
||||
* <pre>
|
||||
* MessageFormatter.format("File name is C:\\\\{}.", "file.zip");
|
||||
* </pre>
|
||||
* <p>
|
||||
* will return the string "File name is C:\file.zip".
|
||||
*
|
||||
* <p>
|
||||
* The formatting conventions are different than those of {@link MessageFormat}
|
||||
* which ships with the Java platform. This is justified by the fact that
|
||||
* SLF4J's implementation is 10 times faster than that of {@link MessageFormat}.
|
||||
* This local performance difference is both measurable and significant in the
|
||||
* larger context of the complete logging processing chain.
|
||||
*
|
||||
* <p>
|
||||
* See also {@link #format(String, Object)},
|
||||
* {@link #format(String, Object, Object)} and
|
||||
* {@link #arrayFormat(String, Object[])} methods for more details.
|
||||
*
|
||||
* @author Ceki Gülcü
|
||||
* @author Joern Huxhorn
|
||||
*/
|
||||
final public class MessageFormatter {
|
||||
static final char DELIM_START = '{';
|
||||
static final char DELIM_STOP = '}';
|
||||
static final String DELIM_STR = "{}";
|
||||
private static final char ESCAPE_CHAR = '\\';
|
||||
|
||||
/**
|
||||
* Performs single argument substitution for the 'messagePattern' passed as
|
||||
* parameter.
|
||||
* <p>
|
||||
* For example,
|
||||
*
|
||||
* <pre>
|
||||
* MessageFormatter.format("Hi {}.", "there");
|
||||
* </pre>
|
||||
* <p>
|
||||
* will return the string "Hi there.".
|
||||
* <p>
|
||||
*
|
||||
* @param messagePattern The message pattern which will be parsed and formatted
|
||||
* @param arg The argument to be substituted in place of the formatting anchor
|
||||
* @return The formatted message
|
||||
*/
|
||||
final public static FormattingTuple format(String messagePattern, Object arg) {
|
||||
return arrayFormat(messagePattern, new Object[]{arg});
|
||||
}
|
||||
|
||||
/**
|
||||
* Performs a two argument substitution for the 'messagePattern' passed as
|
||||
* parameter.
|
||||
* <p>
|
||||
* For example,
|
||||
*
|
||||
* <pre>
|
||||
* MessageFormatter.format("Hi {}. My name is {}.", "Alice", "Bob");
|
||||
* </pre>
|
||||
* <p>
|
||||
* will return the string "Hi Alice. My name is Bob.".
|
||||
*
|
||||
* @param messagePattern The message pattern which will be parsed and formatted
|
||||
* @param arg1 The argument to be substituted in place of the first formatting
|
||||
* anchor
|
||||
* @param arg2 The argument to be substituted in place of the second formatting
|
||||
* anchor
|
||||
* @return The formatted message
|
||||
*/
|
||||
final public static FormattingTuple format(final String messagePattern, Object arg1, Object arg2) {
|
||||
return arrayFormat(messagePattern, new Object[]{arg1, arg2});
|
||||
}
|
||||
|
||||
|
||||
final public static FormattingTuple arrayFormat(final String messagePattern, final Object[] argArray) {
|
||||
Throwable throwableCandidate = MessageFormatter.getThrowableCandidate(argArray);
|
||||
Object[] args = argArray;
|
||||
if (throwableCandidate != null) {
|
||||
args = MessageFormatter.trimmedCopy(argArray);
|
||||
}
|
||||
return arrayFormat(messagePattern, args, throwableCandidate);
|
||||
}
|
||||
|
||||
final public static FormattingTuple arrayFormat(final String messagePattern, final Object[] argArray, Throwable throwable) {
|
||||
|
||||
if (messagePattern == null) {
|
||||
return new FormattingTuple(null, argArray, throwable);
|
||||
}
|
||||
|
||||
if (argArray == null) {
|
||||
return new FormattingTuple(messagePattern);
|
||||
}
|
||||
|
||||
int i = 0;
|
||||
int j;
|
||||
// use string builder for better multicore performance
|
||||
StringBuilder sbuf = new StringBuilder(messagePattern.length() + 50);
|
||||
|
||||
int L;
|
||||
for (L = 0; L < argArray.length; L++) {
|
||||
|
||||
j = messagePattern.indexOf(DELIM_STR, i);
|
||||
|
||||
if (j == -1) {
|
||||
// no more variables
|
||||
if (i == 0) { // this is a simple string
|
||||
return new FormattingTuple(messagePattern, argArray, throwable);
|
||||
} else { // add the tail string which contains no variables and return
|
||||
// the result.
|
||||
sbuf.append(messagePattern, i, messagePattern.length());
|
||||
return new FormattingTuple(sbuf.toString(), argArray, throwable);
|
||||
}
|
||||
} else {
|
||||
if (isEscapedDelimeter(messagePattern, j)) {
|
||||
if (!isDoubleEscaped(messagePattern, j)) {
|
||||
L--; // DELIM_START was escaped, thus should not be incremented
|
||||
sbuf.append(messagePattern, i, j - 1);
|
||||
sbuf.append(DELIM_START);
|
||||
i = j + 1;
|
||||
} else {
|
||||
// The escape character preceding the delimiter start is
|
||||
// itself escaped: "abc x:\\{}"
|
||||
// we have to consume one backward slash
|
||||
sbuf.append(messagePattern, i, j - 1);
|
||||
deeplyAppendParameter(sbuf, argArray[L], new HashMap<Object[], Object>());
|
||||
i = j + 2;
|
||||
}
|
||||
} else {
|
||||
// normal case
|
||||
sbuf.append(messagePattern, i, j);
|
||||
deeplyAppendParameter(sbuf, argArray[L], new HashMap<Object[], Object>());
|
||||
i = j + 2;
|
||||
}
|
||||
}
|
||||
}
|
||||
// append the characters following the last {} pair.
|
||||
sbuf.append(messagePattern, i, messagePattern.length());
|
||||
return new FormattingTuple(sbuf.toString(), argArray, throwable);
|
||||
}
|
||||
|
||||
final static boolean isEscapedDelimeter(String messagePattern, int delimeterStartIndex) {
|
||||
|
||||
if (delimeterStartIndex == 0) {
|
||||
return false;
|
||||
}
|
||||
char potentialEscape = messagePattern.charAt(delimeterStartIndex - 1);
|
||||
if (potentialEscape == ESCAPE_CHAR) {
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
final static boolean isDoubleEscaped(String messagePattern, int delimeterStartIndex) {
|
||||
if (delimeterStartIndex >= 2 && messagePattern.charAt(delimeterStartIndex - 2) == ESCAPE_CHAR) {
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
// special treatment of array values was suggested by 'lizongbo'
|
||||
private static void deeplyAppendParameter(StringBuilder sbuf, Object o, Map<Object[], Object> seenMap) {
|
||||
if (o == null) {
|
||||
sbuf.append("null");
|
||||
return;
|
||||
}
|
||||
if (!o.getClass().isArray()) {
|
||||
safeObjectAppend(sbuf, o);
|
||||
} else {
|
||||
// check for primitive array types because they
|
||||
// unfortunately cannot be cast to Object[]
|
||||
if (o instanceof boolean[]) {
|
||||
booleanArrayAppend(sbuf, (boolean[]) o);
|
||||
} else if (o instanceof byte[]) {
|
||||
byteArrayAppend(sbuf, (byte[]) o);
|
||||
} else if (o instanceof char[]) {
|
||||
charArrayAppend(sbuf, (char[]) o);
|
||||
} else if (o instanceof short[]) {
|
||||
shortArrayAppend(sbuf, (short[]) o);
|
||||
} else if (o instanceof int[]) {
|
||||
intArrayAppend(sbuf, (int[]) o);
|
||||
} else if (o instanceof long[]) {
|
||||
longArrayAppend(sbuf, (long[]) o);
|
||||
} else if (o instanceof float[]) {
|
||||
floatArrayAppend(sbuf, (float[]) o);
|
||||
} else if (o instanceof double[]) {
|
||||
doubleArrayAppend(sbuf, (double[]) o);
|
||||
} else {
|
||||
objectArrayAppend(sbuf, (Object[]) o, seenMap);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static void safeObjectAppend(StringBuilder sbuf, Object o) {
|
||||
try {
|
||||
String oAsString = o.toString();
|
||||
sbuf.append(oAsString);
|
||||
} catch (Throwable t) {
|
||||
System.err.println("SLF4J: Failed toString() invocation on an object of type [" + o.getClass().getName() + "]");
|
||||
System.err.println("Reported exception:");
|
||||
StackTraceElement[] stackTrace = t.getStackTrace();
|
||||
StringBuilder stackBuilder = new StringBuilder();
|
||||
for (StackTraceElement traceElement : stackTrace) {
|
||||
stackBuilder.append("\tat ").append(traceElement).append("\n");
|
||||
}
|
||||
System.err.println(stackBuilder);
|
||||
sbuf.append("[FAILED toString()]");
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private static void objectArrayAppend(StringBuilder sbuf, Object[] a, Map<Object[], Object> seenMap) {
|
||||
sbuf.append('[');
|
||||
if (!seenMap.containsKey(a)) {
|
||||
seenMap.put(a, null);
|
||||
final int len = a.length;
|
||||
for (int i = 0; i < len; i++) {
|
||||
deeplyAppendParameter(sbuf, a[i], seenMap);
|
||||
if (i != len - 1)
|
||||
sbuf.append(", ");
|
||||
}
|
||||
// allow repeats in siblings
|
||||
seenMap.remove(a);
|
||||
} else {
|
||||
sbuf.append("...");
|
||||
}
|
||||
sbuf.append(']');
|
||||
}
|
||||
|
||||
private static void booleanArrayAppend(StringBuilder sbuf, boolean[] a) {
|
||||
sbuf.append('[');
|
||||
final int len = a.length;
|
||||
for (int i = 0; i < len; i++) {
|
||||
sbuf.append(a[i]);
|
||||
if (i != len - 1)
|
||||
sbuf.append(", ");
|
||||
}
|
||||
sbuf.append(']');
|
||||
}
|
||||
|
||||
private static void byteArrayAppend(StringBuilder sbuf, byte[] a) {
|
||||
sbuf.append('[');
|
||||
final int len = a.length;
|
||||
for (int i = 0; i < len; i++) {
|
||||
sbuf.append(a[i]);
|
||||
if (i != len - 1)
|
||||
sbuf.append(", ");
|
||||
}
|
||||
sbuf.append(']');
|
||||
}
|
||||
|
||||
private static void charArrayAppend(StringBuilder sbuf, char[] a) {
|
||||
sbuf.append('[');
|
||||
final int len = a.length;
|
||||
for (int i = 0; i < len; i++) {
|
||||
sbuf.append(a[i]);
|
||||
if (i != len - 1)
|
||||
sbuf.append(", ");
|
||||
}
|
||||
sbuf.append(']');
|
||||
}
|
||||
|
||||
private static void shortArrayAppend(StringBuilder sbuf, short[] a) {
|
||||
sbuf.append('[');
|
||||
final int len = a.length;
|
||||
for (int i = 0; i < len; i++) {
|
||||
sbuf.append(a[i]);
|
||||
if (i != len - 1)
|
||||
sbuf.append(", ");
|
||||
}
|
||||
sbuf.append(']');
|
||||
}
|
||||
|
||||
private static void intArrayAppend(StringBuilder sbuf, int[] a) {
|
||||
sbuf.append('[');
|
||||
final int len = a.length;
|
||||
for (int i = 0; i < len; i++) {
|
||||
sbuf.append(a[i]);
|
||||
if (i != len - 1)
|
||||
sbuf.append(", ");
|
||||
}
|
||||
sbuf.append(']');
|
||||
}
|
||||
|
||||
private static void longArrayAppend(StringBuilder sbuf, long[] a) {
|
||||
sbuf.append('[');
|
||||
final int len = a.length;
|
||||
for (int i = 0; i < len; i++) {
|
||||
sbuf.append(a[i]);
|
||||
if (i != len - 1)
|
||||
sbuf.append(", ");
|
||||
}
|
||||
sbuf.append(']');
|
||||
}
|
||||
|
||||
private static void floatArrayAppend(StringBuilder sbuf, float[] a) {
|
||||
sbuf.append('[');
|
||||
final int len = a.length;
|
||||
for (int i = 0; i < len; i++) {
|
||||
sbuf.append(a[i]);
|
||||
if (i != len - 1)
|
||||
sbuf.append(", ");
|
||||
}
|
||||
sbuf.append(']');
|
||||
}
|
||||
|
||||
private static void doubleArrayAppend(StringBuilder sbuf, double[] a) {
|
||||
sbuf.append('[');
|
||||
final int len = a.length;
|
||||
for (int i = 0; i < len; i++) {
|
||||
sbuf.append(a[i]);
|
||||
if (i != len - 1)
|
||||
sbuf.append(", ");
|
||||
}
|
||||
sbuf.append(']');
|
||||
}
|
||||
|
||||
/**
|
||||
* Helper method to determine if an {@link Object} array contains a {@link Throwable} as last element
|
||||
*
|
||||
* @param argArray The arguments off which we want to know if it contains a {@link Throwable} as last element
|
||||
* @return if the last {@link Object} in argArray is a {@link Throwable} this method will return it,
|
||||
* otherwise it returns null
|
||||
*/
|
||||
public static Throwable getThrowableCandidate(final Object[] argArray) {
|
||||
if (argArray == null || argArray.length == 0) {
|
||||
return null;
|
||||
}
|
||||
|
||||
final Object lastEntry = argArray[argArray.length - 1];
|
||||
if (lastEntry instanceof Throwable) {
|
||||
return (Throwable) lastEntry;
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Helper method to get all but the last element of an array
|
||||
*
|
||||
* @param argArray The arguments from which we want to remove the last element
|
||||
* @return a copy of the array without the last element
|
||||
*/
|
||||
public static Object[] trimmedCopy(final Object[] argArray) {
|
||||
if (argArray == null || argArray.length == 0) {
|
||||
throw new IllegalStateException("non-sensical empty or null argument array");
|
||||
}
|
||||
|
||||
final int trimmedLen = argArray.length - 1;
|
||||
|
||||
Object[] trimmed = new Object[trimmedLen];
|
||||
|
||||
if (trimmedLen > 0) {
|
||||
System.arraycopy(argArray, 0, trimmed, 0, trimmedLen);
|
||||
}
|
||||
|
||||
return trimmed;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -19,6 +19,8 @@ package org.apache.dubbo.common.logger.jcl;
|
|||
import org.apache.dubbo.common.logger.Logger;
|
||||
|
||||
import org.apache.commons.logging.Log;
|
||||
import org.slf4j.helpers.FormattingTuple;
|
||||
import org.slf4j.helpers.MessageFormatter;
|
||||
|
||||
/**
|
||||
* Adaptor to commons logging, depends on commons-logging.jar. For more information about commons logging, pls. refer to
|
||||
|
|
@ -37,6 +39,12 @@ public class JclLogger implements Logger {
|
|||
logger.trace(msg);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void trace(String msg, Object... arguments) {
|
||||
FormattingTuple ft = MessageFormatter.arrayFormat(msg, arguments);
|
||||
logger.trace(ft.getMessage(), ft.getThrowable());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void trace(Throwable e) {
|
||||
logger.trace(e);
|
||||
|
|
@ -52,6 +60,12 @@ public class JclLogger implements Logger {
|
|||
logger.debug(msg);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void debug(String msg, Object... arguments) {
|
||||
FormattingTuple ft = MessageFormatter.arrayFormat(msg, arguments);
|
||||
logger.debug(ft.getMessage(), ft.getThrowable());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void debug(Throwable e) {
|
||||
logger.debug(e);
|
||||
|
|
@ -67,6 +81,12 @@ public class JclLogger implements Logger {
|
|||
logger.info(msg);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void info(String msg, Object... arguments) {
|
||||
FormattingTuple ft = MessageFormatter.arrayFormat(msg, arguments);
|
||||
logger.info(ft.getMessage(), ft.getThrowable());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void info(Throwable e) {
|
||||
logger.info(e);
|
||||
|
|
@ -82,6 +102,12 @@ public class JclLogger implements Logger {
|
|||
logger.warn(msg);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void warn(String msg, Object... arguments) {
|
||||
FormattingTuple ft = MessageFormatter.arrayFormat(msg, arguments);
|
||||
logger.warn(ft.getMessage(), ft.getThrowable());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void warn(Throwable e) {
|
||||
logger.warn(e);
|
||||
|
|
@ -97,6 +123,12 @@ public class JclLogger implements Logger {
|
|||
logger.error(msg);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void error(String msg, Object... arguments) {
|
||||
FormattingTuple ft = MessageFormatter.arrayFormat(msg, arguments);
|
||||
logger.error(ft.getMessage(), ft.getThrowable());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void error(Throwable e) {
|
||||
logger.error(e);
|
||||
|
|
|
|||
|
|
@ -17,6 +17,8 @@
|
|||
package org.apache.dubbo.common.logger.jdk;
|
||||
|
||||
import org.apache.dubbo.common.logger.Logger;
|
||||
import org.slf4j.helpers.FormattingTuple;
|
||||
import org.slf4j.helpers.MessageFormatter;
|
||||
|
||||
import java.util.logging.Level;
|
||||
|
||||
|
|
@ -33,6 +35,12 @@ public class JdkLogger implements Logger {
|
|||
logger.log(Level.FINER, msg);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void trace(String msg, Object... arguments) {
|
||||
FormattingTuple ft = MessageFormatter.arrayFormat(msg, arguments);
|
||||
logger.log(Level.FINER, ft.getMessage(), ft.getThrowable());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void trace(Throwable e) {
|
||||
logger.log(Level.FINER, e.getMessage(), e);
|
||||
|
|
@ -48,6 +56,12 @@ public class JdkLogger implements Logger {
|
|||
logger.log(Level.FINE, msg);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void debug(String msg, Object... arguments) {
|
||||
FormattingTuple ft = MessageFormatter.arrayFormat(msg, arguments);
|
||||
logger.log(Level.FINE, ft.getMessage(), ft.getThrowable());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void debug(Throwable e) {
|
||||
logger.log(Level.FINE, e.getMessage(), e);
|
||||
|
|
@ -63,6 +77,12 @@ public class JdkLogger implements Logger {
|
|||
logger.log(Level.INFO, msg);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void info(String msg, Object... arguments) {
|
||||
FormattingTuple ft = MessageFormatter.arrayFormat(msg, arguments);
|
||||
logger.log(Level.INFO, ft.getMessage(), ft.getThrowable());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void info(String msg, Throwable e) {
|
||||
logger.log(Level.INFO, msg, e);
|
||||
|
|
@ -73,6 +93,12 @@ public class JdkLogger implements Logger {
|
|||
logger.log(Level.WARNING, msg);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void warn(String msg, Object... arguments) {
|
||||
FormattingTuple ft = MessageFormatter.arrayFormat(msg, arguments);
|
||||
logger.log(Level.WARNING, ft.getMessage(), ft.getThrowable());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void warn(String msg, Throwable e) {
|
||||
logger.log(Level.WARNING, msg, e);
|
||||
|
|
@ -83,6 +109,12 @@ public class JdkLogger implements Logger {
|
|||
logger.log(Level.SEVERE, msg);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void error(String msg, Object... arguments) {
|
||||
FormattingTuple ft = MessageFormatter.arrayFormat(msg, arguments);
|
||||
logger.log(Level.SEVERE, ft.getMessage(), ft.getThrowable());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void error(String msg, Throwable e) {
|
||||
logger.log(Level.SEVERE, msg, e);
|
||||
|
|
|
|||
|
|
@ -20,6 +20,8 @@ import org.apache.dubbo.common.logger.Logger;
|
|||
import org.apache.dubbo.common.logger.support.FailsafeLogger;
|
||||
|
||||
import org.apache.log4j.Level;
|
||||
import org.slf4j.helpers.FormattingTuple;
|
||||
import org.slf4j.helpers.MessageFormatter;
|
||||
|
||||
public class Log4jLogger implements Logger {
|
||||
|
||||
|
|
@ -36,6 +38,12 @@ public class Log4jLogger implements Logger {
|
|||
logger.log(FQCN, Level.TRACE, msg, null);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void trace(String msg, Object... arguments) {
|
||||
FormattingTuple ft = MessageFormatter.arrayFormat(msg, arguments);
|
||||
logger.log(FQCN, Level.TRACE, ft.getMessage(), ft.getThrowable());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void trace(Throwable e) {
|
||||
logger.log(FQCN, Level.TRACE, e == null ? null : e.getMessage(), e);
|
||||
|
|
@ -51,6 +59,12 @@ public class Log4jLogger implements Logger {
|
|||
logger.log(FQCN, Level.DEBUG, msg, null);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void debug(String msg, Object... arguments) {
|
||||
FormattingTuple ft = MessageFormatter.arrayFormat(msg, arguments);
|
||||
logger.log(FQCN, Level.DEBUG, ft.getMessage(), ft.getThrowable());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void debug(Throwable e) {
|
||||
logger.log(FQCN, Level.DEBUG, e == null ? null : e.getMessage(), e);
|
||||
|
|
@ -66,6 +80,12 @@ public class Log4jLogger implements Logger {
|
|||
logger.log(FQCN, Level.INFO, msg, null);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void info(String msg, Object... arguments) {
|
||||
FormattingTuple ft = MessageFormatter.arrayFormat(msg, arguments);
|
||||
logger.log(FQCN, Level.INFO, ft.getMessage(), ft.getThrowable());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void info(Throwable e) {
|
||||
logger.log(FQCN, Level.INFO, e == null ? null : e.getMessage(), e);
|
||||
|
|
@ -81,6 +101,12 @@ public class Log4jLogger implements Logger {
|
|||
logger.log(FQCN, Level.WARN, msg, null);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void warn(String msg, Object... arguments) {
|
||||
FormattingTuple ft = MessageFormatter.arrayFormat(msg, arguments);
|
||||
logger.log(FQCN, Level.WARN, ft.getMessage(), ft.getThrowable());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void warn(Throwable e) {
|
||||
logger.log(FQCN, Level.WARN, e == null ? null : e.getMessage(), e);
|
||||
|
|
@ -96,6 +122,12 @@ public class Log4jLogger implements Logger {
|
|||
logger.log(FQCN, Level.ERROR, msg, null);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void error(String msg, Object... arguments) {
|
||||
FormattingTuple ft = MessageFormatter.arrayFormat(msg, arguments);
|
||||
logger.log(FQCN, Level.ERROR, ft.getMessage(), ft.getThrowable());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void error(Throwable e) {
|
||||
logger.log(FQCN, Level.ERROR, e == null ? null : e.getMessage(), e);
|
||||
|
|
|
|||
|
|
@ -31,6 +31,11 @@ public class Log4j2Logger implements Logger {
|
|||
logger.trace(msg);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void trace(String msg, Object... arguments) {
|
||||
logger.trace(msg, arguments);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void trace(Throwable e) {
|
||||
logger.trace(e == null ? null : e.getMessage(), e);
|
||||
|
|
@ -46,6 +51,11 @@ public class Log4j2Logger implements Logger {
|
|||
logger.debug(msg);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void debug(String msg, Object... arguments) {
|
||||
logger.debug(msg, arguments);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void debug(Throwable e) {
|
||||
logger.debug(e == null ? null : e.getMessage(), e);
|
||||
|
|
@ -61,6 +71,11 @@ public class Log4j2Logger implements Logger {
|
|||
logger.info(msg);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void info(String msg, Object... arguments) {
|
||||
logger.info(msg, arguments);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void info(Throwable e) {
|
||||
logger.info(e == null ? null : e.getMessage(), e);
|
||||
|
|
@ -76,6 +91,11 @@ public class Log4j2Logger implements Logger {
|
|||
logger.warn(msg);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void warn(String msg, Object... arguments) {
|
||||
logger.warn(msg, arguments);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void warn(Throwable e) {
|
||||
logger.warn(e == null ? null : e.getMessage(), e);
|
||||
|
|
@ -91,6 +111,11 @@ public class Log4j2Logger implements Logger {
|
|||
logger.error(msg);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void error(String msg, Object... arguments) {
|
||||
logger.error(msg, arguments);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void error(Throwable e) {
|
||||
logger.error(e == null ? null : e.getMessage(), e);
|
||||
|
|
|
|||
|
|
@ -20,6 +20,8 @@ import org.apache.dubbo.common.logger.Level;
|
|||
import org.apache.dubbo.common.logger.Logger;
|
||||
import org.apache.dubbo.common.logger.support.FailsafeLogger;
|
||||
|
||||
import org.slf4j.helpers.FormattingTuple;
|
||||
import org.slf4j.helpers.MessageFormatter;
|
||||
import org.slf4j.spi.LocationAwareLogger;
|
||||
|
||||
public class Slf4jLogger implements Logger {
|
||||
|
|
@ -48,6 +50,16 @@ public class Slf4jLogger implements Logger {
|
|||
logger.trace(msg);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void trace(String msg, Object... arguments) {
|
||||
if (locationAwareLogger != null) {
|
||||
FormattingTuple ft = MessageFormatter.arrayFormat(msg, arguments);
|
||||
locationAwareLogger.log(null, FQCN, LocationAwareLogger.TRACE_INT, msg, ft.getArgArray(), ft.getThrowable());
|
||||
return;
|
||||
}
|
||||
logger.trace(msg, arguments);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void trace(Throwable e) {
|
||||
if (locationAwareLogger != null) {
|
||||
|
|
@ -75,6 +87,16 @@ public class Slf4jLogger implements Logger {
|
|||
logger.debug(msg);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void debug(String msg, Object... arguments) {
|
||||
if (locationAwareLogger != null) {
|
||||
FormattingTuple ft = MessageFormatter.arrayFormat(msg, arguments);
|
||||
locationAwareLogger.log(null, FQCN, LocationAwareLogger.DEBUG_INT, msg, ft.getArgArray(), ft.getThrowable());
|
||||
return;
|
||||
}
|
||||
logger.debug(msg, arguments);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void debug(Throwable e) {
|
||||
if (locationAwareLogger != null) {
|
||||
|
|
@ -102,6 +124,16 @@ public class Slf4jLogger implements Logger {
|
|||
logger.info(msg);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void info(String msg, Object... arguments) {
|
||||
if (locationAwareLogger != null) {
|
||||
FormattingTuple ft = MessageFormatter.arrayFormat(msg, arguments);
|
||||
locationAwareLogger.log(null, FQCN, LocationAwareLogger.INFO_INT, msg, ft.getArgArray(), ft.getThrowable());
|
||||
return;
|
||||
}
|
||||
logger.info(msg, arguments);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void info(Throwable e) {
|
||||
if (locationAwareLogger != null) {
|
||||
|
|
@ -129,6 +161,16 @@ public class Slf4jLogger implements Logger {
|
|||
logger.warn(msg);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void warn(String msg, Object... arguments) {
|
||||
if (locationAwareLogger != null) {
|
||||
FormattingTuple ft = MessageFormatter.arrayFormat(msg, arguments);
|
||||
locationAwareLogger.log(null, FQCN, LocationAwareLogger.WARN_INT, msg, ft.getArgArray(), ft.getThrowable());
|
||||
return;
|
||||
}
|
||||
logger.warn(msg, arguments);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void warn(Throwable e) {
|
||||
if (locationAwareLogger != null) {
|
||||
|
|
@ -156,6 +198,16 @@ public class Slf4jLogger implements Logger {
|
|||
logger.error(msg);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void error(String msg, Object... arguments) {
|
||||
if (locationAwareLogger != null) {
|
||||
FormattingTuple ft = MessageFormatter.arrayFormat(msg, arguments);
|
||||
locationAwareLogger.log(null, FQCN, LocationAwareLogger.ERROR_INT, msg, ft.getArgArray(), ft.getThrowable());
|
||||
return;
|
||||
}
|
||||
logger.error(msg, arguments);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void error(Throwable e) {
|
||||
if (locationAwareLogger != null) {
|
||||
|
|
|
|||
|
|
@ -18,16 +18,22 @@
|
|||
package org.apache.dubbo.common.logger.support;
|
||||
|
||||
import org.apache.dubbo.common.Version;
|
||||
import org.apache.dubbo.common.logger.ErrorTypeAwareLogger;
|
||||
import org.apache.dubbo.common.logger.ListenableLogger;
|
||||
import org.apache.dubbo.common.logger.LogListener;
|
||||
import org.apache.dubbo.common.logger.Logger;
|
||||
import org.apache.dubbo.common.utils.NetUtils;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.Optional;
|
||||
import java.util.concurrent.atomic.AtomicReference;
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
/**
|
||||
* A fail-safe (ignoring exception thrown by logger) wrapper of error type aware logger.
|
||||
*/
|
||||
public class FailsafeErrorTypeAwareLogger extends FailsafeLogger implements ErrorTypeAwareLogger {
|
||||
public class FailsafeErrorTypeAwareLogger extends FailsafeLogger implements ListenableLogger {
|
||||
|
||||
/**
|
||||
* Template address for formatting.
|
||||
|
|
@ -36,6 +42,16 @@ public class FailsafeErrorTypeAwareLogger extends FailsafeLogger implements Erro
|
|||
|
||||
private static final Pattern ERROR_CODE_PATTERN = Pattern.compile("\\d+-\\d+");
|
||||
|
||||
/**
|
||||
* Listeners that listened to all Loggers.
|
||||
*/
|
||||
private static final List<LogListener> GLOBAL_LISTENERS = Collections.synchronizedList(new ArrayList<>());
|
||||
|
||||
/**
|
||||
* Listeners that listened to this listener.
|
||||
*/
|
||||
private final AtomicReference<List<LogListener>> listeners = new AtomicReference<>();
|
||||
|
||||
public FailsafeErrorTypeAwareLogger(Logger logger) {
|
||||
super(logger);
|
||||
}
|
||||
|
|
@ -80,6 +96,7 @@ public class FailsafeErrorTypeAwareLogger extends FailsafeLogger implements Erro
|
|||
}
|
||||
|
||||
try {
|
||||
onEvent(code, msg);
|
||||
getLogger().warn(appendContextMessageWithInstructions(code, cause, extendedInformation, msg));
|
||||
} catch (Throwable t) {
|
||||
// ignored.
|
||||
|
|
@ -93,6 +110,7 @@ public class FailsafeErrorTypeAwareLogger extends FailsafeLogger implements Erro
|
|||
}
|
||||
|
||||
try {
|
||||
onEvent(code, msg);
|
||||
getLogger().warn(appendContextMessageWithInstructions(code, cause, extendedInformation, msg), e);
|
||||
} catch (Throwable t) {
|
||||
// ignored.
|
||||
|
|
@ -106,6 +124,7 @@ public class FailsafeErrorTypeAwareLogger extends FailsafeLogger implements Erro
|
|||
}
|
||||
|
||||
try {
|
||||
onEvent(code, msg);
|
||||
getLogger().error(appendContextMessageWithInstructions(code, cause, extendedInformation, msg));
|
||||
} catch (Throwable t) {
|
||||
// ignored.
|
||||
|
|
@ -119,9 +138,45 @@ public class FailsafeErrorTypeAwareLogger extends FailsafeLogger implements Erro
|
|||
}
|
||||
|
||||
try {
|
||||
onEvent(code, msg);
|
||||
getLogger().error(appendContextMessageWithInstructions(code, cause, extendedInformation, msg), e);
|
||||
} catch (Throwable t) {
|
||||
// ignored.
|
||||
}
|
||||
}
|
||||
|
||||
public static void registerGlobalListen(LogListener listener) {
|
||||
GLOBAL_LISTENERS.add(listener);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void registerListen(LogListener listener) {
|
||||
listeners.getAndUpdate(logListeners -> {
|
||||
if (logListeners == null) {
|
||||
logListeners = Collections.synchronizedList(new ArrayList<>());
|
||||
}
|
||||
logListeners.add(listener);
|
||||
return logListeners;
|
||||
});
|
||||
}
|
||||
|
||||
private void onEvent(String code, String msg) {
|
||||
Optional.ofNullable(listeners.get()).ifPresent(
|
||||
logListeners -> logListeners.forEach(logListener -> {
|
||||
try {
|
||||
logListener.onMessage(code, msg);
|
||||
} catch (Exception e) {
|
||||
// ignored.
|
||||
}
|
||||
}));
|
||||
|
||||
GLOBAL_LISTENERS.forEach(logListener -> {
|
||||
try {
|
||||
logListener.onMessage(code, msg);
|
||||
} catch (Exception e) {
|
||||
// ignored.
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -83,6 +83,17 @@ public class FailsafeLogger implements Logger {
|
|||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void trace(String msg, Object... arguments) {
|
||||
if (disabled) {
|
||||
return;
|
||||
}
|
||||
try {
|
||||
logger.trace(appendContextMessage(msg), arguments);
|
||||
} catch (Throwable t) {
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void debug(String msg, Throwable e) {
|
||||
if (disabled) {
|
||||
|
|
@ -116,6 +127,17 @@ public class FailsafeLogger implements Logger {
|
|||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void debug(String msg, Object... arguments) {
|
||||
if (disabled) {
|
||||
return;
|
||||
}
|
||||
try {
|
||||
logger.debug(appendContextMessage(msg), arguments);
|
||||
} catch (Throwable t) {
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void info(String msg, Throwable e) {
|
||||
if (disabled) {
|
||||
|
|
@ -138,6 +160,17 @@ public class FailsafeLogger implements Logger {
|
|||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void info(String msg, Object... arguments) {
|
||||
if (disabled) {
|
||||
return;
|
||||
}
|
||||
try {
|
||||
logger.info(appendContextMessage(msg), arguments);
|
||||
} catch (Throwable t) {
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void warn(String msg, Throwable e) {
|
||||
if (disabled) {
|
||||
|
|
@ -160,6 +193,17 @@ public class FailsafeLogger implements Logger {
|
|||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void warn(String msg, Object... arguments) {
|
||||
if (disabled) {
|
||||
return;
|
||||
}
|
||||
try {
|
||||
logger.warn(appendContextMessage(msg), arguments);
|
||||
} catch (Throwable t) {
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void error(String msg, Throwable e) {
|
||||
if (disabled) {
|
||||
|
|
@ -182,6 +226,17 @@ public class FailsafeLogger implements Logger {
|
|||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void error(String msg, Object... arguments) {
|
||||
if (disabled) {
|
||||
return;
|
||||
}
|
||||
try {
|
||||
logger.error(appendContextMessage(msg), arguments);
|
||||
} catch (Throwable t) {
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void error(Throwable e) {
|
||||
if (disabled) {
|
||||
|
|
|
|||
|
|
@ -132,6 +132,39 @@ public interface AnnotationUtils {
|
|||
return getAttribute(annotation, "value");
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the attribute from the specified {@link Annotation annotation}
|
||||
*
|
||||
* @param annotation the specified {@link Annotation annotation}
|
||||
* @param attributeNames the multiply attribute name arrays
|
||||
* @param <T> the type of attribute
|
||||
* @return the attribute value
|
||||
* @throws IllegalArgumentException If the attribute name can't be found
|
||||
*/
|
||||
static <T> T getAttribute(Annotation annotation, String... attributeNames) throws IllegalArgumentException {
|
||||
if (attributeNames == null || attributeNames.length == 0) {
|
||||
return null;
|
||||
}
|
||||
|
||||
for (String attributeName : attributeNames) {
|
||||
T attribute = getAttribute(annotation, attributeName);
|
||||
|
||||
if (attribute == null) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// exclude string attribute default is empty
|
||||
if ((attribute instanceof String) && ((String) attribute).length() == 0) {
|
||||
continue;
|
||||
}
|
||||
|
||||
return attribute;
|
||||
}
|
||||
|
||||
return null;
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the {@link Annotation} from the specified {@link AnnotatedElement the annotated element} and
|
||||
* {@link Annotation annotation} class name
|
||||
|
|
|
|||
|
|
@ -16,6 +16,7 @@
|
|||
*/
|
||||
package org.apache.dubbo.common.utils;
|
||||
|
||||
import org.apache.dubbo.common.aot.NativeDetector;
|
||||
import org.apache.dubbo.common.logger.ErrorTypeAwareLogger;
|
||||
import org.apache.dubbo.common.logger.LoggerFactory;
|
||||
import org.apache.dubbo.common.resource.GlobalResourcesRepository;
|
||||
|
|
@ -78,7 +79,7 @@ public class ClassLoaderResourceLoader {
|
|||
Enumeration<URL> urls;
|
||||
try {
|
||||
urls = currentClassLoader.getResources(fileName);
|
||||
boolean isNative = NativeUtils.isNative();
|
||||
boolean isNative = NativeDetector.inNativeImage();
|
||||
if (urls != null) {
|
||||
while (urls.hasMoreElements()) {
|
||||
URL url = urls.nextElement();
|
||||
|
|
|
|||
|
|
@ -212,6 +212,20 @@ public class ClassUtils {
|
|||
return forName(name, getClassLoader());
|
||||
}
|
||||
|
||||
/**
|
||||
* find class and don`t expect to throw exception
|
||||
* @param name
|
||||
* @return
|
||||
*/
|
||||
public static Class<?> forNameAndTryCatch(String name) {
|
||||
try {
|
||||
return forName(name, getClassLoader());
|
||||
} catch (Throwable e) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Replacement for <code>Class.forName()</code> that also returns Class
|
||||
* instances for primitives (like "int") and array class names (like
|
||||
|
|
|
|||
|
|
@ -0,0 +1,185 @@
|
|||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
* contributor license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright ownership.
|
||||
* The ASF licenses this file to You under the Apache License, Version 2.0
|
||||
* (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.apache.dubbo.common.utils;
|
||||
|
||||
import org.apache.dubbo.common.logger.Logger;
|
||||
import org.apache.dubbo.common.logger.LoggerFactory;
|
||||
|
||||
import java.lang.reflect.Field;
|
||||
import java.lang.reflect.GenericArrayType;
|
||||
import java.lang.reflect.Method;
|
||||
import java.lang.reflect.Modifier;
|
||||
import java.lang.reflect.ParameterizedType;
|
||||
import java.lang.reflect.Type;
|
||||
import java.lang.reflect.TypeVariable;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
|
||||
|
||||
public class JsonCompatibilityUtil {
|
||||
|
||||
private static final Logger logger = LoggerFactory.getLogger(JsonCompatibilityUtil.class);
|
||||
|
||||
private static final Set<String> unsupportedClasses = new HashSet<>(Arrays.asList("java.util.Optional", "java.util.Calendar", "java.util.Iterator", "java.io.InputStream", "java.io.OutputStream"));
|
||||
|
||||
|
||||
/**
|
||||
* Determine whether a Class can be serialized by JSON.
|
||||
* @param clazz Incoming Class.
|
||||
* @return If a Class can be serialized by JSON, return true;
|
||||
* else return false.
|
||||
*/
|
||||
public static boolean checkClassCompatibility(Class<?> clazz) {
|
||||
Method[] methods = clazz.getDeclaredMethods();
|
||||
|
||||
boolean result;
|
||||
|
||||
for (Method method : methods) {
|
||||
result = checkMethodCompatibility(method);
|
||||
if (!result) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Determine whether a Method can be serialized by JSON.
|
||||
* @param method Incoming Method.
|
||||
* @return If a Method can be serialized by JSON, return true;
|
||||
* else return false.
|
||||
*/
|
||||
public static boolean checkMethodCompatibility(Method method) {
|
||||
|
||||
boolean result;
|
||||
|
||||
Type[] types = method.getGenericParameterTypes();
|
||||
List<Type> typeList = new ArrayList<>(Arrays.asList(types));
|
||||
Type returnType = method.getGenericReturnType();
|
||||
typeList.add(returnType);
|
||||
for (Type type : typeList) {
|
||||
result = checkType(type);
|
||||
if (!result) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Get unsupported methods.
|
||||
* @param clazz
|
||||
* @return If there are unsupported methods, return them by List;
|
||||
* else return null.
|
||||
*/
|
||||
public static List<String> getUnsupportedMethods(Class<?> clazz) {
|
||||
ArrayList<String> unsupportedMethods = new ArrayList<>();
|
||||
|
||||
Method[] methods = clazz.getDeclaredMethods();
|
||||
|
||||
for (Method method : methods) {
|
||||
if (!checkMethodCompatibility(method)) {
|
||||
unsupportedMethods.add(method.getName());
|
||||
}
|
||||
}
|
||||
|
||||
return unsupportedMethods.size() > 0 ? unsupportedMethods : null;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Determine whether a Type can be serialized by JSON.
|
||||
* @param classType Incoming Type.
|
||||
* @return If a Type can be serialized by JSON, return true;
|
||||
* else return false.
|
||||
*/
|
||||
private static boolean checkType(Type classType) {
|
||||
|
||||
boolean result;
|
||||
|
||||
if (classType instanceof TypeVariable) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if (classType instanceof ParameterizedType) {
|
||||
|
||||
Type[] types = ((ParameterizedType) classType).getActualTypeArguments();
|
||||
List<Type> typeList = new ArrayList<>(Arrays.asList(types));
|
||||
classType = ((ParameterizedType) classType).getRawType();
|
||||
typeList.add(classType);
|
||||
for (Type type : typeList) {
|
||||
result = checkType(type);
|
||||
if (!result) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
} else if (classType instanceof GenericArrayType) {
|
||||
Type componentType = ((GenericArrayType) classType).getGenericComponentType();
|
||||
result = checkType(componentType);
|
||||
return result;
|
||||
} else if (classType instanceof Class<?> ) {
|
||||
Class<?> clazz = (Class<?>) classType;
|
||||
|
||||
String className = clazz.getName();
|
||||
|
||||
if (clazz.isArray()) {
|
||||
Type componentType = clazz.getComponentType();
|
||||
result = checkType(componentType);
|
||||
return result;
|
||||
} else if (clazz.isPrimitive()) {
|
||||
// deal with case of basic byte
|
||||
return !unsupportedClasses.contains(className);
|
||||
} else if (className.startsWith("java") || className.startsWith("javax")) {
|
||||
return !unsupportedClasses.contains(className);
|
||||
} else {
|
||||
// deal with case of interface
|
||||
if (clazz.isInterface()) {
|
||||
return false;
|
||||
}
|
||||
// deal with case of abstract
|
||||
if (Modifier.isAbstract(clazz.getModifiers())) {
|
||||
return false;
|
||||
}
|
||||
if (clazz.isEnum()) {
|
||||
return true;
|
||||
}
|
||||
// deal with case of record
|
||||
// if (clazz.isRecord()) {
|
||||
// return false;
|
||||
// }
|
||||
// deal with field one by one
|
||||
for (Field field : clazz.getDeclaredFields()) {
|
||||
Type type = field.getGenericType();
|
||||
Class<?> fieldClass = field.getType();
|
||||
result = checkType(type);
|
||||
if (!result) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -17,7 +17,7 @@
|
|||
package org.apache.dubbo.common.utils;
|
||||
|
||||
import org.apache.dubbo.common.constants.CommonConstants;
|
||||
import org.apache.dubbo.common.json.JSON;
|
||||
import org.apache.dubbo.common.json.JsonUtil;
|
||||
import org.apache.dubbo.common.json.impl.FastJson2Impl;
|
||||
import org.apache.dubbo.common.json.impl.FastJsonImpl;
|
||||
import org.apache.dubbo.common.json.impl.GsonImpl;
|
||||
|
|
@ -29,17 +29,16 @@ import java.util.List;
|
|||
import java.util.Map;
|
||||
|
||||
public class JsonUtils {
|
||||
private static volatile JsonUtil jsonUtil;
|
||||
|
||||
private static volatile JSON json;
|
||||
|
||||
protected static JSON getJson() {
|
||||
if (json == null) {
|
||||
protected static JsonUtil getJson() {
|
||||
if (jsonUtil == null) {
|
||||
synchronized (JsonUtils.class) {
|
||||
if (json == null) {
|
||||
if (jsonUtil == null) {
|
||||
String preferJsonFrameworkName = System.getProperty(CommonConstants.PREFER_JSON_FRAMEWORK_NAME);
|
||||
if (StringUtils.isNotEmpty(preferJsonFrameworkName)) {
|
||||
try {
|
||||
JSON instance = null;
|
||||
JsonUtil instance = null;
|
||||
switch (preferJsonFrameworkName) {
|
||||
case "fastjson2":
|
||||
instance = new FastJson2Impl();
|
||||
|
|
@ -55,23 +54,23 @@ public class JsonUtils {
|
|||
break;
|
||||
}
|
||||
if (instance != null && instance.isSupport()) {
|
||||
json = instance;
|
||||
jsonUtil = instance;
|
||||
}
|
||||
} catch (Throwable ignore) {
|
||||
|
||||
}
|
||||
}
|
||||
if (json == null) {
|
||||
List<Class<? extends JSON>> jsonClasses = Arrays.asList(
|
||||
if (jsonUtil == null) {
|
||||
List<Class<? extends JsonUtil>> jsonClasses = Arrays.asList(
|
||||
FastJson2Impl.class,
|
||||
FastJsonImpl.class,
|
||||
GsonImpl.class,
|
||||
JacksonImpl.class);
|
||||
for (Class<? extends JSON> jsonClass : jsonClasses) {
|
||||
for (Class<? extends JsonUtil> jsonClass : jsonClasses) {
|
||||
try {
|
||||
JSON instance = jsonClass.getConstructor().newInstance();
|
||||
JsonUtil instance = jsonClass.getConstructor().newInstance();
|
||||
if (instance.isSupport()) {
|
||||
json = instance;
|
||||
jsonUtil = instance;
|
||||
break;
|
||||
}
|
||||
} catch (Throwable ignore) {
|
||||
|
|
@ -79,22 +78,22 @@ public class JsonUtils {
|
|||
}
|
||||
}
|
||||
}
|
||||
if (json == null) {
|
||||
if (jsonUtil == null) {
|
||||
throw new IllegalStateException("Dubbo unable to find out any json framework (e.g. fastjson2, fastjson, gson, jackson) from jvm env. " +
|
||||
"Please import at least one json framework.");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return json;
|
||||
return jsonUtil;
|
||||
}
|
||||
|
||||
/**
|
||||
* @deprecated for uts only
|
||||
*/
|
||||
@Deprecated
|
||||
protected static void setJson(JSON json) {
|
||||
JsonUtils.json = json;
|
||||
protected static void setJson(JsonUtil json) {
|
||||
JsonUtils.jsonUtil = json;
|
||||
}
|
||||
|
||||
public static <T> T toJavaObject(String json, Type type) {
|
||||
|
|
|
|||
|
|
@ -856,6 +856,23 @@ public final class StringUtils {
|
|||
return sb.toString();
|
||||
}
|
||||
|
||||
public static String join(final Object[] array, final char delimiter, final int startIndex, final int endIndex) {
|
||||
if (ArrayUtils.isEmpty(array)) {
|
||||
return EMPTY_STRING;
|
||||
}
|
||||
if (endIndex - startIndex <= 0) {
|
||||
return EMPTY_STRING;
|
||||
}
|
||||
StringBuilder sb = new StringBuilder();
|
||||
for (int i = startIndex; i < endIndex; i++) {
|
||||
if (i > 0) {
|
||||
sb.append(delimiter);
|
||||
}
|
||||
sb.append(array[i]);
|
||||
}
|
||||
return sb.toString();
|
||||
}
|
||||
|
||||
/**
|
||||
* parse key-value pair.
|
||||
*
|
||||
|
|
|
|||
|
|
@ -172,6 +172,13 @@ public abstract class AbstractConfig implements Serializable {
|
|||
appendParameters0(parameters, config, prefix, false);
|
||||
}
|
||||
|
||||
public boolean validate() {
|
||||
if(scopeModel == null || scopeModel.getBeanFactory() == null || scopeModel.getBeanFactory().isDestroyed()){
|
||||
return ConfigValidateFacade.getDefaultInstance().validate(this);
|
||||
}
|
||||
return scopeModel.getBeanFactory().getOrRegisterBean(ConfigValidateFacade.class,clz -> new ConfigValidateFacade(scopeModel)).validate(this);
|
||||
}
|
||||
|
||||
private static void appendParameters0(Map<String, String> parameters, Object config, String prefix, boolean asParameters) {
|
||||
if (config == null) {
|
||||
return;
|
||||
|
|
|
|||
|
|
@ -18,6 +18,8 @@ package org.apache.dubbo.config;
|
|||
|
||||
import org.apache.dubbo.common.URL;
|
||||
import org.apache.dubbo.common.Version;
|
||||
import org.apache.dubbo.common.aot.NativeDetector;
|
||||
import org.apache.dubbo.common.compiler.support.AdaptiveCompiler;
|
||||
import org.apache.dubbo.common.config.ConfigurationUtils;
|
||||
import org.apache.dubbo.common.config.Environment;
|
||||
import org.apache.dubbo.common.config.InmemoryConfiguration;
|
||||
|
|
@ -47,7 +49,6 @@ import java.util.stream.Collectors;
|
|||
import static org.apache.dubbo.common.constants.CommonConstants.COMMA_SPLIT_PATTERN;
|
||||
import static org.apache.dubbo.common.constants.CommonConstants.DUBBO_VERSION_KEY;
|
||||
import static org.apache.dubbo.common.constants.CommonConstants.INVOKER_LISTENER_KEY;
|
||||
import static org.apache.dubbo.common.constants.CommonConstants.NATIVE;
|
||||
import static org.apache.dubbo.common.constants.CommonConstants.PID_KEY;
|
||||
import static org.apache.dubbo.common.constants.CommonConstants.REFERENCE_FILTER_KEY;
|
||||
import static org.apache.dubbo.common.constants.CommonConstants.RELEASE_KEY;
|
||||
|
|
@ -55,6 +56,7 @@ import static org.apache.dubbo.common.constants.CommonConstants.TAG_KEY;
|
|||
import static org.apache.dubbo.common.constants.CommonConstants.TIMESTAMP_KEY;
|
||||
import static org.apache.dubbo.common.constants.LoggerCodeConstants.CONFIG_NO_METHOD_FOUND;
|
||||
import static org.apache.dubbo.common.constants.MetricsConstants.PROTOCOL_PROMETHEUS;
|
||||
import static org.apache.dubbo.config.Constants.DEFAULT_NATIVE_PROXY;
|
||||
|
||||
|
||||
/**
|
||||
|
|
@ -293,8 +295,7 @@ public abstract class AbstractInterfaceConfig extends AbstractMethodConfig {
|
|||
* @return
|
||||
*/
|
||||
protected String[] methods(Class<?> interfaceClass) {
|
||||
boolean isNative = getEnvironment().getConfiguration().getBoolean(NATIVE, false);
|
||||
if (isNative) {
|
||||
if (NativeDetector.inNativeImage()) {
|
||||
return Arrays.stream(interfaceClass.getMethods()).map(Method::getName).toArray(String[]::new);
|
||||
} else {
|
||||
return ClassUtils.getMethodNames(interfaceClass);
|
||||
|
|
@ -613,12 +614,21 @@ public abstract class AbstractInterfaceConfig extends AbstractMethodConfig {
|
|||
}
|
||||
|
||||
public String getProxy() {
|
||||
return proxy;
|
||||
if (NativeDetector.inNativeImage()) {
|
||||
return DEFAULT_NATIVE_PROXY;
|
||||
} else {
|
||||
return this.proxy;
|
||||
}
|
||||
}
|
||||
|
||||
public void setProxy(String proxy) {
|
||||
if (NativeDetector.inNativeImage()) {
|
||||
this.proxy = DEFAULT_NATIVE_PROXY;
|
||||
AdaptiveCompiler.setDefaultCompiler(DEFAULT_NATIVE_PROXY);
|
||||
} else {
|
||||
this.proxy = proxy;
|
||||
}
|
||||
}
|
||||
|
||||
public Integer getConnections() {
|
||||
return connections;
|
||||
|
|
|
|||
|
|
@ -16,6 +16,7 @@
|
|||
*/
|
||||
package org.apache.dubbo.config;
|
||||
|
||||
import org.apache.dubbo.common.aot.NativeDetector;
|
||||
import org.apache.dubbo.common.compiler.support.AdaptiveCompiler;
|
||||
import org.apache.dubbo.common.infra.InfraAdapter;
|
||||
import org.apache.dubbo.common.logger.ErrorTypeAwareLogger;
|
||||
|
|
@ -67,6 +68,7 @@ import static org.apache.dubbo.common.constants.QosConstants.QOS_PORT;
|
|||
import static org.apache.dubbo.common.constants.QosConstants.QOS_PORT_COMPATIBLE;
|
||||
import static org.apache.dubbo.common.constants.RegistryConstants.ENABLE_EMPTY_PROTECTION_KEY;
|
||||
import static org.apache.dubbo.common.constants.RegistryConstants.REGISTER_MODE_KEY;
|
||||
import static org.apache.dubbo.config.Constants.DEFAULT_NATIVE_COMPILER;
|
||||
import static org.apache.dubbo.config.Constants.DEVELOPMENT_ENVIRONMENT;
|
||||
import static org.apache.dubbo.config.Constants.PRODUCTION_ENVIRONMENT;
|
||||
import static org.apache.dubbo.config.Constants.TEST_ENVIRONMENT;
|
||||
|
|
@ -395,13 +397,23 @@ public class ApplicationConfig extends AbstractConfig {
|
|||
}
|
||||
|
||||
public String getCompiler() {
|
||||
if (NativeDetector.inNativeImage()) {
|
||||
return DEFAULT_NATIVE_COMPILER;
|
||||
} else {
|
||||
return compiler;
|
||||
}
|
||||
}
|
||||
|
||||
public void setCompiler(String compiler) {
|
||||
|
||||
if (NativeDetector.inNativeImage()) {
|
||||
this.compiler = DEFAULT_NATIVE_COMPILER;
|
||||
AdaptiveCompiler.setDefaultCompiler(DEFAULT_NATIVE_COMPILER);
|
||||
} else {
|
||||
this.compiler = compiler;
|
||||
AdaptiveCompiler.setDefaultCompiler(compiler);
|
||||
}
|
||||
}
|
||||
|
||||
public String getLogger() {
|
||||
return logger;
|
||||
|
|
|
|||
|
|
@ -0,0 +1,36 @@
|
|||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
* contributor license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright ownership.
|
||||
* The ASF licenses this file to You under the Apache License, Version 2.0
|
||||
* (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.apache.dubbo.config;
|
||||
|
||||
import org.apache.dubbo.common.extension.ExtensionScope;
|
||||
import org.apache.dubbo.common.extension.SPI;
|
||||
|
||||
/**
|
||||
* it will be call when reference or service config refresh
|
||||
*/
|
||||
|
||||
@SPI(scope = ExtensionScope.MODULE)
|
||||
public interface CommonConfigPostProcessor {
|
||||
|
||||
default void postProcessReferConfig(ReferenceConfigBase referenceConfig) {
|
||||
|
||||
}
|
||||
|
||||
default void postProcessServiceConfig(ServiceConfigBase serviceConfig) {
|
||||
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,115 @@
|
|||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
* contributor license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright ownership.
|
||||
* The ASF licenses this file to You under the Apache License, Version 2.0
|
||||
* (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.apache.dubbo.config;
|
||||
|
||||
import org.apache.dubbo.common.extension.ExtensionLoader;
|
||||
import org.apache.dubbo.common.logger.Logger;
|
||||
import org.apache.dubbo.common.logger.LoggerFactory;
|
||||
import org.apache.dubbo.config.context.ConfigValidator;
|
||||
import org.apache.dubbo.config.exception.ConfigValidationException;
|
||||
import org.apache.dubbo.rpc.model.ApplicationModel;
|
||||
import org.apache.dubbo.rpc.model.ScopeModel;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
|
||||
@SuppressWarnings({"rawtypes", "unchecked"})
|
||||
public class ConfigValidateFacade implements ConfigValidator{
|
||||
|
||||
private static final Logger LOGGER = LoggerFactory.getErrorTypeAwareLogger(ConfigValidateFacade.class);
|
||||
|
||||
private final List<ConfigValidator> validators;
|
||||
|
||||
/**
|
||||
* For test
|
||||
*/
|
||||
private static boolean enableValidate = true;
|
||||
|
||||
public ConfigValidateFacade(ScopeModel scopeModel) {
|
||||
if(scopeModel != null) {
|
||||
ExtensionLoader<ConfigValidator> extensionLoader = scopeModel.getExtensionLoader(ConfigValidator.class);
|
||||
if (extensionLoader != null) {
|
||||
this.validators = extensionLoader.getActivateExtensions();
|
||||
this.validators.forEach(scopeModel.getBeanFactory()::registerBean);
|
||||
} else {
|
||||
this.validators = Collections.emptyList();
|
||||
}
|
||||
}else {
|
||||
this.validators = Collections.emptyList();
|
||||
}
|
||||
}
|
||||
|
||||
public List<ConfigValidator> getValidators() {
|
||||
return validators;
|
||||
}
|
||||
|
||||
/**
|
||||
* Auto choose a appropriate validator to validate config.
|
||||
*
|
||||
* @param config the config to validate
|
||||
* @return TRUE if pass the validation.
|
||||
* FALSE if no ConfigValidator found for this config,
|
||||
* or one of the supported {@link ConfigValidator#validate(AbstractConfig)} returns FALSE.
|
||||
*/
|
||||
@Override
|
||||
public boolean validate(AbstractConfig config) throws ConfigValidationException{
|
||||
if(!enableValidate){
|
||||
return true;
|
||||
}
|
||||
if (config == null) {
|
||||
return false;
|
||||
}
|
||||
boolean validated = false;
|
||||
try {
|
||||
for (ConfigValidator validator : validators) {
|
||||
if (validator.isSupport(config.getClass())) {
|
||||
validated = true;
|
||||
if(!validator.validate(config)){
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
}catch (Throwable t){
|
||||
throw new ConfigValidationException(config.getClass().getSimpleName()+" validation failed: "+t.getMessage(),t);
|
||||
}
|
||||
if (!validated) {
|
||||
LOGGER.info(config.getClass().getSimpleName()+" is not validated. This may caused by you did not imported the relevant module.");
|
||||
}
|
||||
return validated;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isSupport(Class configClass) {
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* For test
|
||||
*/
|
||||
@Deprecated
|
||||
public static ConfigValidateFacade getDefaultInstance() {
|
||||
return ApplicationModel.defaultModel().getBeanFactory().getOrRegisterBean(ConfigValidateFacade.class);
|
||||
}
|
||||
|
||||
/**
|
||||
* For test
|
||||
*/
|
||||
@Deprecated
|
||||
public static void setEnableValidate(boolean enable){
|
||||
enableValidate = enable;
|
||||
}
|
||||
}
|
||||
|
|
@ -152,4 +152,8 @@ public interface Constants {
|
|||
String CLIENT_THREAD_POOL_NAME = "DubboClientHandler";
|
||||
|
||||
String REST_PROTOCOL="rest";
|
||||
|
||||
String DEFAULT_NATIVE_COMPILER="jdk";
|
||||
|
||||
String DEFAULT_NATIVE_PROXY="jdk";
|
||||
}
|
||||
|
|
|
|||
|
|
@ -61,6 +61,11 @@ public class MetricsConfig extends AbstractConfig {
|
|||
*/
|
||||
private Boolean exportMetricsService;
|
||||
|
||||
/**
|
||||
* Enable netty metrics.
|
||||
*/
|
||||
private Boolean enableNetty;
|
||||
|
||||
/**
|
||||
* @deprecated After metrics config is refactored.
|
||||
* This parameter should no longer use and will be deleted in the future.
|
||||
|
|
@ -223,4 +228,12 @@ public class MetricsConfig extends AbstractConfig {
|
|||
public void setEnableRpc(Boolean enableRpc) {
|
||||
this.enableRpc = enableRpc;
|
||||
}
|
||||
|
||||
public Boolean getEnableNetty() {
|
||||
return enableNetty;
|
||||
}
|
||||
|
||||
public void setEnableNetty(Boolean enableNetty) {
|
||||
this.enableNetty = enableNetty;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -26,6 +26,7 @@ import java.util.Map;
|
|||
import java.util.Optional;
|
||||
|
||||
import static org.apache.dubbo.common.constants.CommonConstants.DUBBO_PROTOCOL;
|
||||
import static org.apache.dubbo.common.constants.CommonConstants.JSON_CHECK_LEVEL_KEY;
|
||||
import static org.apache.dubbo.common.constants.CommonConstants.SSL_ENABLED_KEY;
|
||||
import static org.apache.dubbo.common.constants.CommonConstants.THREAD_POOL_EXHAUSTED_LISTENERS_KEY;
|
||||
import static org.apache.dubbo.common.constants.LoggerCodeConstants.COMMON_UNEXPECTED_EXCEPTION;
|
||||
|
|
@ -229,6 +230,8 @@ public class ProtocolConfig extends AbstractConfig {
|
|||
*/
|
||||
private String extProtocol;
|
||||
|
||||
private String jsonCheckLevel;
|
||||
|
||||
public ProtocolConfig() {
|
||||
}
|
||||
|
||||
|
|
@ -331,6 +334,15 @@ public class ProtocolConfig extends AbstractConfig {
|
|||
this.threadname = threadname;
|
||||
}
|
||||
|
||||
@Parameter(key = JSON_CHECK_LEVEL_KEY)
|
||||
public String getJsonCheckLevel() {
|
||||
return jsonCheckLevel;
|
||||
}
|
||||
|
||||
public void setJsonCheckLevel(String jsonCheckLevel) {
|
||||
this.jsonCheckLevel = jsonCheckLevel;
|
||||
}
|
||||
|
||||
@Parameter(key = THREAD_POOL_EXHAUSTED_LISTENERS_KEY)
|
||||
public String getThreadPoolExhaustedListeners() {
|
||||
return threadPoolExhaustedListeners;
|
||||
|
|
|
|||
|
|
@ -31,6 +31,7 @@ import org.apache.dubbo.common.utils.StringUtils;
|
|||
import org.apache.dubbo.config.AbstractConfig;
|
||||
import org.apache.dubbo.config.ApplicationConfig;
|
||||
import org.apache.dubbo.config.ConfigKeys;
|
||||
import org.apache.dubbo.config.ConfigValidateFacade;
|
||||
import org.apache.dubbo.config.MetadataReportConfig;
|
||||
import org.apache.dubbo.config.MetricsConfig;
|
||||
import org.apache.dubbo.config.ModuleConfig;
|
||||
|
|
@ -585,11 +586,9 @@ public abstract class AbstractConfigManager extends LifecycleAdapter {
|
|||
|
||||
// validate configs
|
||||
Collection<T> configs = this.getConfigs(configType);
|
||||
if (getConfigValidator() != null) {
|
||||
for (T config : configs) {
|
||||
getConfigValidator().validate(config);
|
||||
}
|
||||
}
|
||||
|
||||
// check required default
|
||||
if (isRequired(configType) && configs.isEmpty()) {
|
||||
|
|
@ -611,11 +610,11 @@ public abstract class AbstractConfigManager extends LifecycleAdapter {
|
|||
return true;
|
||||
}
|
||||
|
||||
private ConfigValidator getConfigValidator() {
|
||||
private ConfigValidateFacade getConfigValidator() {
|
||||
if (configValidator == null) {
|
||||
configValidator = applicationModel.getBeanFactory().getBean(ConfigValidator.class);
|
||||
configValidator = applicationModel.getBeanFactory().getOrRegisterBean(ConfigValidateFacade.class, clz -> new ConfigValidateFacade(scopeModel));
|
||||
}
|
||||
return configValidator;
|
||||
return (ConfigValidateFacade) configValidator;
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
|||
|
|
@ -16,10 +16,26 @@
|
|||
*/
|
||||
package org.apache.dubbo.config.context;
|
||||
|
||||
import org.apache.dubbo.common.extension.SPI;
|
||||
import org.apache.dubbo.config.AbstractConfig;
|
||||
import org.apache.dubbo.config.exception.ConfigValidationException;
|
||||
|
||||
public interface ConfigValidator {
|
||||
/**
|
||||
* ConfigValidator. Allow provides an optional validation logic for a {@link AbstractConfig} impl.
|
||||
* @param <T> type of {@link AbstractConfig} implement
|
||||
*/
|
||||
@SPI
|
||||
public interface ConfigValidator<T extends AbstractConfig> {
|
||||
|
||||
void validate(AbstractConfig config);
|
||||
/**
|
||||
* Validate a config.
|
||||
* If the config does not pass validation, returns false or throws exception, depends on implementation.
|
||||
*
|
||||
* @param config the config to validate
|
||||
* @return TRUE if pass validation
|
||||
*/
|
||||
boolean validate(T config) throws ConfigValidationException;
|
||||
|
||||
boolean isSupport(Class<?> configClass);
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -0,0 +1,166 @@
|
|||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
* contributor license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright ownership.
|
||||
* The ASF licenses this file to You under the Apache License, Version 2.0
|
||||
* (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.apache.dubbo.config.deploy.context;
|
||||
|
||||
import org.apache.dubbo.common.config.Environment;
|
||||
import org.apache.dubbo.common.config.ReferenceCache;
|
||||
import org.apache.dubbo.common.deploy.DeployListener;
|
||||
import org.apache.dubbo.common.deploy.DeployState;
|
||||
import org.apache.dubbo.common.threadpool.manager.ExecutorRepository;
|
||||
import org.apache.dubbo.common.threadpool.manager.FrameworkExecutorRepository;
|
||||
import org.apache.dubbo.config.deploy.lifecycle.manager.ApplicationLifecycleManager;
|
||||
|
||||
import org.apache.dubbo.rpc.model.ApplicationModel;
|
||||
|
||||
|
||||
import java.util.List;
|
||||
import java.util.concurrent.atomic.AtomicBoolean;
|
||||
import java.util.concurrent.atomic.AtomicInteger;
|
||||
import java.util.concurrent.atomic.AtomicReference;
|
||||
|
||||
/**
|
||||
* The lifecycle attribute aggregate of application.
|
||||
*/
|
||||
public class ApplicationContext {
|
||||
|
||||
private final ApplicationModel applicationModel;
|
||||
|
||||
private final AtomicBoolean hasPreparedApplicationInstance;
|
||||
|
||||
private final AtomicBoolean registered ;
|
||||
|
||||
private final AtomicBoolean hasPreparedInternalModule;
|
||||
|
||||
private final ReferenceCache referenceCache;
|
||||
|
||||
/**
|
||||
* Indicate that how many threads are updating service
|
||||
*/
|
||||
private final AtomicInteger serviceRefreshState;
|
||||
|
||||
private final ApplicationLifecycleManager lifecycleManager;
|
||||
|
||||
private final ExecutorRepository executorRepository;
|
||||
|
||||
private final FrameworkExecutorRepository frameworkExecutorRepository;
|
||||
|
||||
private final Environment environment;
|
||||
|
||||
private final ApplicationModel scopeModel;
|
||||
|
||||
private final AtomicReference<DeployState> modelState;
|
||||
|
||||
private final AtomicBoolean initialized;
|
||||
|
||||
private final AtomicReference<Throwable> lastError;
|
||||
|
||||
private final List<DeployListener<ApplicationModel>> deployListeners;
|
||||
|
||||
public ApplicationContext(ApplicationModel applicationModel, AtomicBoolean hasPreparedApplicationInstance, AtomicBoolean registered, AtomicBoolean hasPreparedInternalModule, ReferenceCache referenceCache, AtomicInteger serviceRefreshState, ApplicationLifecycleManager lifecycleManager, ExecutorRepository executorRepository, FrameworkExecutorRepository frameworkExecutorRepository, Environment environment, ApplicationModel scopeModel, AtomicReference<DeployState> modelState, AtomicBoolean initialized, AtomicReference<Throwable> lastError,List<DeployListener<ApplicationModel>> deployListeners) {
|
||||
this.applicationModel = applicationModel;
|
||||
this.hasPreparedApplicationInstance = hasPreparedApplicationInstance;
|
||||
this.registered = registered;
|
||||
this.hasPreparedInternalModule = hasPreparedInternalModule;
|
||||
this.referenceCache = referenceCache;
|
||||
this.serviceRefreshState = serviceRefreshState;
|
||||
this.lifecycleManager = lifecycleManager;
|
||||
this.executorRepository = executorRepository;
|
||||
this.frameworkExecutorRepository = frameworkExecutorRepository;
|
||||
this.environment = environment;
|
||||
this.scopeModel = scopeModel;
|
||||
this.modelState = modelState;
|
||||
this.initialized = initialized;
|
||||
this.lastError = lastError;
|
||||
this.deployListeners = deployListeners;
|
||||
}
|
||||
|
||||
public ApplicationModel getModel() {
|
||||
return applicationModel;
|
||||
}
|
||||
|
||||
public void setModelState(DeployState newState) {
|
||||
this.modelState.set(newState);
|
||||
}
|
||||
|
||||
public DeployState getCurrentState() {
|
||||
return this.modelState.get();
|
||||
}
|
||||
|
||||
public Throwable getLastError() {
|
||||
return lastError.get();
|
||||
}
|
||||
|
||||
public void setLastError(Throwable lastError) {
|
||||
this.lastError.set(lastError);
|
||||
}
|
||||
|
||||
public boolean initialized() {
|
||||
return initialized.get();
|
||||
}
|
||||
|
||||
public void setInitialized(boolean initialized) {
|
||||
this.initialized.set(initialized);
|
||||
}
|
||||
|
||||
public boolean hasPreparedInternalModule() {
|
||||
return hasPreparedInternalModule.get();
|
||||
}
|
||||
|
||||
public void setHasPreparedInternalModule(boolean hasPreparedInternalModule) {
|
||||
this.hasPreparedInternalModule.set(hasPreparedInternalModule);
|
||||
}
|
||||
|
||||
public boolean isHasPreparedApplicationInstance() {
|
||||
return hasPreparedApplicationInstance.get();
|
||||
}
|
||||
|
||||
public boolean isHasPreparedInternalModule() {
|
||||
return hasPreparedInternalModule.get();
|
||||
}
|
||||
|
||||
public AtomicBoolean getHasPreparedApplicationInstance() {
|
||||
return hasPreparedApplicationInstance;
|
||||
}
|
||||
|
||||
public void setRegistered(boolean registered){
|
||||
this.registered.set(registered);
|
||||
}
|
||||
|
||||
public boolean registered() {
|
||||
return registered.get();
|
||||
}
|
||||
|
||||
public AtomicBoolean getRegistered(){
|
||||
return registered;
|
||||
}
|
||||
|
||||
public ReferenceCache getReferenceCache() {
|
||||
return referenceCache;
|
||||
}
|
||||
|
||||
public AtomicInteger getServiceRefreshState() {
|
||||
return serviceRefreshState;
|
||||
}
|
||||
|
||||
public ExecutorRepository getExecutorRepository() {
|
||||
return executorRepository;
|
||||
}
|
||||
|
||||
public List<DeployListener<ApplicationModel>> getDeployListeners() {
|
||||
return deployListeners;
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,36 @@
|
|||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
* contributor license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright ownership.
|
||||
* The ASF licenses this file to You under the Apache License, Version 2.0
|
||||
* (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.apache.dubbo.config.deploy.lifecycle;
|
||||
|
||||
/**
|
||||
* Lifecycle. The abstraction of dubbo model lifecycle operations.
|
||||
*/
|
||||
public interface Lifecycle<T>{
|
||||
|
||||
/**
|
||||
* If this lifecycle need to initialize.
|
||||
*/
|
||||
boolean needInitialize();
|
||||
|
||||
default void start(T context){}
|
||||
|
||||
default void initialize(T context){}
|
||||
|
||||
default void preDestroy(T context) {}
|
||||
|
||||
default void postDestroy(T context) {}
|
||||
}
|
||||
|
|
@ -0,0 +1,53 @@
|
|||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
* contributor license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright ownership.
|
||||
* The ASF licenses this file to You under the Apache License, Version 2.0
|
||||
* (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.apache.dubbo.config.deploy.lifecycle.application;
|
||||
|
||||
import org.apache.dubbo.common.deploy.ApplicationDeployListener;
|
||||
import org.apache.dubbo.common.deploy.DeployState;
|
||||
import org.apache.dubbo.common.extension.ExtensionScope;
|
||||
import org.apache.dubbo.common.extension.SPI;
|
||||
import org.apache.dubbo.config.deploy.context.ApplicationContext;
|
||||
import org.apache.dubbo.config.deploy.lifecycle.Lifecycle;
|
||||
import org.apache.dubbo.rpc.model.ModuleModel;
|
||||
|
||||
/**
|
||||
* ApplicationLifecycle.
|
||||
* <br>
|
||||
* Used in an application Lifecycle managing procedure, and dubbo packages
|
||||
* can implement this interface to define what to do when application status changes.
|
||||
* <p>
|
||||
* Note: If you want to auto registry some extensions to BeanFactory that shared in an application, consider use {@link ApplicationDeployListener}.
|
||||
* <br>
|
||||
*/
|
||||
@SPI(scope = ExtensionScope.APPLICATION)
|
||||
public interface ApplicationLifecycle extends Lifecycle<ApplicationContext> {
|
||||
|
||||
/**
|
||||
* @see org.apache.dubbo.config.deploy.lifecycle.manager.ApplicationLifecycleManager#preModuleChanged(ApplicationContext, ModuleModel, DeployState)
|
||||
*/
|
||||
default void preModuleChanged(ApplicationContext applicationContext,ModuleModel changedModule,DeployState moduleState){}
|
||||
|
||||
/**
|
||||
* @see org.apache.dubbo.config.deploy.lifecycle.manager.ApplicationLifecycleManager#postModuleChanged(ApplicationContext, ModuleModel, DeployState, DeployState, DeployState)
|
||||
*/
|
||||
default void postModuleChanged(ApplicationContext applicationContext,ModuleModel changedModule,DeployState moduleNewState,DeployState applicationOldState,DeployState applicationNewState){}
|
||||
|
||||
/**
|
||||
* @see org.apache.dubbo.config.deploy.lifecycle.manager.ApplicationLifecycleManager#runRefreshServiceInstance(ApplicationContext)
|
||||
*/
|
||||
default void refreshServiceInstance(ApplicationContext applicationContext){}
|
||||
}
|
||||
|
|
@ -0,0 +1,98 @@
|
|||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
* contributor license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright ownership.
|
||||
* The ASF licenses this file to You under the Apache License, Version 2.0
|
||||
* (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.apache.dubbo.config.deploy.lifecycle.manager;
|
||||
|
||||
import org.apache.dubbo.common.beans.factory.ScopeBeanFactory;
|
||||
import org.apache.dubbo.common.deploy.DeployState;
|
||||
import org.apache.dubbo.common.extension.ExtensionLoader;
|
||||
import org.apache.dubbo.common.logger.ErrorTypeAwareLogger;
|
||||
import org.apache.dubbo.common.logger.LoggerFactory;
|
||||
import org.apache.dubbo.config.deploy.context.ApplicationContext;
|
||||
import org.apache.dubbo.config.deploy.lifecycle.application.ApplicationLifecycle;
|
||||
import org.apache.dubbo.rpc.model.ApplicationModel;
|
||||
import org.apache.dubbo.rpc.model.ModuleModel;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
|
||||
/**
|
||||
* Application lifecycle manager
|
||||
*/
|
||||
public class ApplicationLifecycleManager{
|
||||
|
||||
private static final ErrorTypeAwareLogger logger = LoggerFactory.getErrorTypeAwareLogger(ApplicationLifecycleManager.class);
|
||||
|
||||
private final List<ApplicationLifecycle> sequences;
|
||||
|
||||
private final ApplicationModel applicationModel;
|
||||
|
||||
public ApplicationLifecycleManager(ApplicationModel applicationModel) {
|
||||
this.applicationModel = applicationModel;
|
||||
sequences = loadAll();
|
||||
}
|
||||
|
||||
public void start(ApplicationContext applicationContext){
|
||||
getAll().forEach(applicationLifecycle -> applicationLifecycle.start(applicationContext));
|
||||
}
|
||||
|
||||
public void initialize(ApplicationContext applicationContext) {
|
||||
getAll().forEach(applicationLifecycle-> applicationLifecycle.initialize(applicationContext));
|
||||
}
|
||||
|
||||
public void preDestroy(ApplicationContext applicationContext) {
|
||||
getAll().forEach(applicationLifecycle-> applicationLifecycle.preDestroy(applicationContext));
|
||||
}
|
||||
|
||||
public void postDestroy(ApplicationContext applicationContext) {
|
||||
getAll().forEach(applicationLifecycle-> applicationLifecycle.postDestroy(applicationContext));
|
||||
}
|
||||
|
||||
public void preModuleChanged(ApplicationContext applicationContext,ModuleModel changedModule, DeployState moduleNewState) {
|
||||
getAll().forEach(applicationLifecycle -> applicationLifecycle.preModuleChanged(applicationContext,changedModule,moduleNewState));
|
||||
}
|
||||
|
||||
public void postModuleChanged(ApplicationContext applicationContext,ModuleModel changedModule, DeployState moduleNewState,DeployState applicationOldState,DeployState applicationNewState) {
|
||||
getAll().forEach(applicationLifecycle -> applicationLifecycle.postModuleChanged(applicationContext,changedModule,moduleNewState,applicationOldState,applicationNewState));
|
||||
}
|
||||
|
||||
public void runRefreshServiceInstance(ApplicationContext applicationContext){
|
||||
getAll().forEach(applicationLifecycle -> applicationLifecycle.refreshServiceInstance(applicationContext));
|
||||
}
|
||||
|
||||
public List<ApplicationLifecycle> getAll(){
|
||||
return this.sequences;
|
||||
}
|
||||
|
||||
protected List<ApplicationLifecycle> loadAll() {
|
||||
ExtensionLoader<ApplicationLifecycle> loader = applicationModel.getExtensionLoader(ApplicationLifecycle.class);
|
||||
List<ApplicationLifecycle> lifecycles = loader.getActivateExtensions();
|
||||
|
||||
ScopeBeanFactory beanFactory = applicationModel.getBeanFactory();
|
||||
StringBuilder sequence = new StringBuilder("Loaded lifecycle sequences: [START]-> ");
|
||||
|
||||
lifecycles.forEach(applicationLifecycle -> {
|
||||
if(applicationLifecycle.needInitialize()) {
|
||||
beanFactory.registerBean(applicationLifecycle);
|
||||
sequence.append(applicationLifecycle.getClass().getSimpleName()).append("-> ");
|
||||
}
|
||||
});
|
||||
sequence.append(" [END]");
|
||||
logger.info(sequence.toString());
|
||||
|
||||
return lifecycles;
|
||||
}
|
||||
}
|
||||
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue