diff --git a/.travis.yml b/.travis.yml index 32306778b30..e3f3350628c 100644 --- a/.travis.yml +++ b/.travis.yml @@ -16,3 +16,6 @@ script: after_success: - bash <(curl -s https://codecov.io/bash) + +after_failure: + - if [ -f dubbo.log ]; then echo "------TAIL of dubbo.log------"; tail -n 1000 dubbo.log; echo "------END of dubbo.log------"; fi diff --git a/CHANGES.md b/CHANGES.md index 0efe5519f8c..1fde3bd1206 100644 --- a/CHANGES.md +++ b/CHANGES.md @@ -1,15 +1,158 @@ # Release Notes -## 2.6.2 - -1. Hessian-lite serialization: revert locale serialization for compatibility, #1413 -2. Asset transfer to ASF, includeing pom, license, DISCLAIMER and so on, #1491 -3. Introduce of new dispatcher policy: EagerThreadpool, #1568 -4. Separate monitor data with group and version, #1407 -5. Spring Boot Enhancement, #1611 -6. Graceful shutdown enhancement - - Remove exporter destroy logic in AnnotationBean. - - Waiting for registry notification on consumer side by checking channel state. -7. Simplify consumer/provider side check in RpcContext, #1444. - -Issues and Pull Requests, check [milestone-2.6.2](https://github.com/apache/incubator-dubbo/milestone/15). +## 2.7.0 + +Requirements: **Java 8+** required + +Please check [here](https://github.com/apache/incubator-dubbo/blob/2.7.0-release/CHANGES.md#upgrading-and-compatibility-notifications) for notes and possible compatibility issues for upgrading from 2.6.x or lower to 2.7.0. + +### New Features + +- Enhancement of service governance rules. + - Enriched Routing Rules. + 1. Conditional Routing. Supports both application-level and service-level conditions. + 2. Tag Routing. Newly introduced to better support traffic isolation, such as grey deployment. + - Decoupling governance rules with the registry, making it easier to extend. Apollo and Zookeeper are available in this version. Nacos support is on the way... + - Application-level Dynamic Configuration support. + - Use YAML as the configuration language, which is more friendly to read and use. + +- Externalized Configuration. Supports reading `dubbo.properties` hosted in remote centralized configuration center - centralized configuration. + +- Simplified registry URL. With lower Registry memory use and less notification pressure from Service Directory, separates Configuration notification from Service Discovery. + +- Metadata Center. A totally new concept since 2.7.0, used to store service metadata including static configuration, service definition, method signature, etc.. By default, Zookeeper and Redis are supported as the backend storage. Will work as the basis of service testing, mock and other service governance features going to be supported in OPS. + +- Asynchronous Programming Model (only works for Dubbo protocol now) + - Built-in support for the method with CompletableFuture signature. + - Server-side asynchronous support, with an AsyncContext API works like Servlet 3.0. + - Asynchronous filter chain callback. + +- Serialization Extension: Protobuf. + +- Caching Policy Extension: Expiring Cache. + +### Enhancements / Bugfixes + +- Load Balancing strategy enhancement: ConsitentHash #2190, LeastActive #2171, Random #2597, RoundRobin #2650. + +- Third-party dependency upgrading. + - Switch default remoting to Netty 4. + - Switch default Zookeeper client to Curator. + - Upgrade Jetty to 9.x. + +- IPV6 support #2079. + +- Performance tuning, check hanging requests on a closed channel, make them return directly #2185. + +- Fixed the serialization problem of JDK primitive types in Kryo #2178. + +- Fixed the problem of failing to notify Consumer as early as possible after the Provider side deserialization failed #1903. + +### Upgrading and Compatibility Notifications + +We have always keep compatibility in mind during the whole process of 2.7.0. We even want old users to upgrade with only on pom version upgrade, but it's hard to achieve that, especially when considering that we have the package renamed in this version, so we had some tradeoffs. If you only used the Dubbo's most basic features, you may have little problems of upgrading, but if you have used some advanced features or have some SPI extensions inside, you'd better read the upgrade notifications carefully. The compatibility issues can be classified into the following 5 categories, for each part, there will have detailed dos and don'ts published later in the official website. + +1. Interoperability between 2.7.0 and lower versions + +2. Package renaming + + com.alibaba.dubbo -> org.apache.dubbo + +3. Simplification of registered URLs + +4. Service Governance Rules + +5. Configuration + + +## 2.6.5 + +Enhancements / Features: + +- Reactor the generation rule for @Service Bean name [#2235](https://github.com/apache/incubator-dubbo/issues/2235) +- Introduce a new Spring ApplicationEvent for ServiceBean exporting [#2251](https://github.com/apache/incubator-dubbo/issues/2251) +- [Enhancement] the algorithm of load issue on Windows. [#1641](https://github.com/apache/incubator-dubbo/issues/1641) +- add javadoc to dubbo-all module good first issue. [#2600](https://github.com/apache/incubator-dubbo/issues/2600) +- [Enhancement] Reactor the generation rule for @Service Bean name type/enhancement [#2235](https://github.com/apache/incubator-dubbo/issues/2235) +- Optimize LeastActiveLoadBalance and add weight test case. [#2540](https://github.com/apache/incubator-dubbo/issues/2540) +- Smooth Round Robin selection. [#2578](https://github.com/apache/incubator-dubbo/issues/2578) [#2647](https://github.com/apache/incubator-dubbo/pull/2647) +- [Enhancement] Resolve the placeholders for sub-properties. [#2297](https://github.com/apache/incubator-dubbo/issues/2297) +- Add ability to turn off SPI auto injection, special support for generic Object type injection. [#2681](https://github.com/apache/incubator-dubbo/pull/2681) + + +Bugfixes: + +- @Service(register=false) is not work. [#2063](https://github.com/apache/incubator-dubbo/issues/2063) +- Our customized serialization id exceeds the maximum limit, now it cannot work on 2.6.2 anymore. [#1903](https://github.com/apache/incubator-dubbo/issues/1903) +- Consumer throws RpcException after RegistryDirectory notify in high QPS. [#2016](https://github.com/apache/incubator-dubbo/issues/2016) +- Annotation @Reference can't support to export a service with a sync one and an async one . [#2194](https://github.com/apache/incubator-dubbo/issues/2194) +- `org.apache.dubbo.config.spring.beans.factory.annotation.ReferenceAnnotationBeanPostProcessor#generateReferenceBeanCacheKey` has a bug. [#2522](https://github.com/apache/incubator-dubbo/issues/2522) +- 2.6.x Spring Event & Bugfix. [#2256](https://github.com/apache/incubator-dubbo/issues/2256) +- Fix incorrect descriptions for dubbo-serialization module. [#2665](https://github.com/apache/incubator-dubbo/issues/2665) +- A empty directory dubbo-config/dubbo-config-spring/src/test/resources/work after package source tgz. [#2560](https://github.com/apache/incubator-dubbo/issues/2560) +- Fixed 2.6.x branch a minor issue with doConnect not using getConnectTimeout() in NettyClient. (*No issue*). [#2622](https://github.com/apache/incubator-dubbo/pull/2622) +- Bean name of @service annotated class does not resolve placeholder. [#1755](https://github.com/apache/incubator-dubbo/issues/1755) + + + +Issues and Pull Requests, check [milestone-2.6.5](https://github.com/apache/incubator-dubbo/milestone/21). + +## 2.6.4 + +Enhancements / Features + +- Support access Redis with password, [#2146](https://github.com/apache/incubator-dubbo/pull/2146) +- Support char array for GenericService, [#2137](https://github.com/apache/incubator-dubbo/pull/2137) +- Direct return when the server goes down abnormally, [#2451](https://github.com/apache/incubator-dubbo/pull/2451) +- Add log for trouble-shooting when qos start failed, [#2455](https://github.com/apache/incubator-dubbo/pull/2455) +- PojoUtil support subclasses of java.util.Date, [#2502](https://github.com/apache/incubator-dubbo/pull/2502) +- Add ip and application name for MonitorService, [#2166](https://github.com/apache/incubator-dubbo/pull/2166) +- New ASCII logo, [#2402](https://github.com/apache/incubator-dubbo/pull/2402) + +Bugfixes + +- Change consumer retries default value from 0 to 2, [#2303](https://github.com/apache/incubator-dubbo/pull/2303) +- Fix the problem that attachment is lost when retry, [#2024](https://github.com/apache/incubator-dubbo/pull/2024) +- Fix NPE when telnet get a null parameter, [#2453](https://github.com/apache/incubator-dubbo/pull/2453) + +UT stability + +- Improve the stability by changing different port, setting timeout to 3000ms, [#2501](https://github.com/apache/incubator-dubbo/pull/2501) + +Issues and Pull Requests, check [milestone-2.6.4](https://github.com/apache/incubator-dubbo/milestone/19). + +## 2.6.3 + +Enhancements / Features + +- Support implicit delivery of attachments from provider to consumer, #889 +- Support inject Spring bean to SPI by bean type, #1837 +- Add generic invoke and attachments support for http&hessian protocol, #1827 +- Get the real methodname to support consistenthash for generic invoke, #1872 +- Remove validation key from provider url on Consumer side, config depedently, #1386 +- Introducing the Bootstrap module as a unified entry for Dubbo startup and resource destruction, #1820 +- Open TCP_NODELAY on Netty 3, #1746 +- Support specify proxy type on provider side, #1873 +- Support dbindex in redis, #1831 +- Upgrade tomcat to 8.5.31, #1781 + +Bugfixes + +- ExecutionDispatcher meet with user docs, #1089 +- Remove side effects of Dubbo custom loggers on Netty logger, #1717 +- Fix isShutdown() judge of Dubbo biz threadpool always return true, #1426 +- Selection of invoker node under the critical condition of only two nodes, #1759 +- Listener cann't be removed during unsubscribe when use ZK as registry, #1792 +- URL parsing problem when user filed contains '@', #1808 +- Check null in CacheFilter to avoid NPE, #1828 +- Fix potential deadlock in DubboProtocol, #1836 +- Restore the bug that attachment has not been updated in the RpcContext when the Dubbo built-in retry mechanism is triggered, #1453 +- Some other small bugfixes + +Performance Tuning + +- ChannelState branch prediction optimization. #1643 +- Optimize AtomicPositiveInteger, less memory and compute cost, #348 +- Introduce embedded Threadlocal to replace the JDK implementation, #1745 + +Hessian-lite diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index b987b16e658..e5ed3a9ee9b 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -13,7 +13,7 @@ The mailing list is the recommended way for discussing almost anything that rela - [dev@dubbo.incubator.apache.org](mailto:dev-subscribe@dubbo.incubator.apache.org): the develop mailing list, you can ask question here if you have encountered any problem when using or developing Dubbo. - [commits@dubbo.incubator.apache.org](mailto:commits-subscribe@dubbo.incubator.apache.org): all the commits will be sent to this mailing list. You can subscribe to it if you are interested in Dubbo's development. -- [notification@dubbo.incubator.apache.org](mailto:notification-subscribe@dubbo.incubator.apache.org): all the Github [issue](https://github.com/apache/incubator-dubbo/issues) updates and [pull request](https://github.com/apache/incubator-dubbo/pulls) updates will be sent to this mailing list. +- [notifications@dubbo.incubator.apache.org](mailto:notifications-subscribe@dubbo.incubator.apache.org): all the Github [issue](https://github.com/apache/incubator-dubbo/issues) updates and [pull request](https://github.com/apache/incubator-dubbo/pulls) updates will be sent to this mailing list. ### Reporting issue diff --git a/LICENSE b/LICENSE index 9c706ace39a..a35e3b94fe0 100644 --- a/LICENSE +++ b/LICENSE @@ -208,15 +208,6 @@ Apache Dubbo includes a number of submodules with separate copyright notices and license terms. Your use of these submodules is subject to the terms and conditions of the following licenses. -For the org.apache.dubbo.common.concurrent package: - -This product bundles and repackages the following code in Google Guava 16.0.1, which is available under a -"Apache License 2.0" license. For details, see https://github.com/google/guava/blob/v16.0.1/COPYING. - - * com.google.common.util.concurrent.ExecutionList - * com.google.common.util.concurrent.ListenableFuture - * com.google.common.util.concurrent.ListenableFutureTask - For the package org.apache.dubbo.common.threadlocal and org.apache.dubbo.common.timer: This product contains a modified portion of 'Netty', an event-driven asynchronous network application framework also @@ -229,15 +220,3 @@ This product contains a modified portion of 'Netty', an event-driven asynchronou * io.netty.util.Timeout * io.netty.util.HashedWheelTimer - This product contains modified portion of common-lang3 org.apache.commons.lang3.time package java file, an thread safe date format utility, which - is under a "Apache License 2.0" license, see https://github.com/apache/commons-lang/blob/master/LICENSE.txt - - * org.apache.commons.lang3.time.DateParser - * org.apache.commons.lang3.time.DatePrinter - * org.apache.commons.lang3.time.FastDateFormat - * org.apache.commons.lang3.FastDateParser - * org.apache.commons.lang3.FastDatePrinter - * org.apache.commons.lang3.FastTimeZone - * org.apache.commons.lang3.FormatCache - * org.apache.commons.lang3.GmtTimeZone - diff --git a/README.md b/README.md index 5b00da21169..efbe080bd41 100644 --- a/README.md +++ b/README.md @@ -42,13 +42,13 @@ There's a [README](https://github.com/dubbo/dubbo-samples/blob/master/dubbo-samp ```xml - 2.6.5 + 2.7.0 - com.alibaba + org.apache.dubbo dubbo-dependencies-bom ${dubbo.version} pom @@ -59,8 +59,8 @@ There's a [README](https://github.com/dubbo/dubbo-samples/blob/master/dubbo-samp - com.alibaba - dubbo + org.apache.dubbo + dubbo-parent ${dubbo.version} @@ -73,7 +73,7 @@ There's a [README](https://github.com/dubbo/dubbo-samples/blob/master/dubbo-samp ### Define service interfaces ```java -package org.apache.dubbo.demo.api; +package org.apache.dubbo.samples.api; public interface GreetingService { String sayHello(String name); @@ -85,9 +85,9 @@ public interface GreetingService { ### Implement service interface for the provider ```java -package org.apache.dubbo.demo.provider; +package org.apache.dubbo.samples.provider; -import org.apache.dubbo.demo.GreetingService; +import org.apache.dubbo.samples.api.GreetingService; public class GreetingServiceImpl implements GreetingService { public String sayHello(String name) { @@ -103,10 +103,10 @@ public class GreetingServiceImpl implements GreetingService { ```java package org.apache.dubbo.demo.provider; -import com.alibaba.dubbo.config.ApplicationConfig; -import com.alibaba.dubbo.config.RegistryConfig; -import com.alibaba.dubbo.config.ServiceConfig; -import org.apache.dubbo.demo.GreetingService; +import org.apache.dubbo.config.ApplicationConfig; +import org.apache.dubbo.config.RegistryConfig; +import org.apache.dubbo.config.ServiceConfig; +import org.apache.dubbo.samples.api.GreetingService; import java.io.IOException; @@ -138,10 +138,10 @@ public class Application { ```java package org.apache.dubbo.demo.consumer; -import com.alibaba.dubbo.config.ApplicationConfig; -import com.alibaba.dubbo.config.ReferenceConfig; -import com.alibaba.dubbo.config.RegistryConfig; -import org.apache.dubbo.demo.GreetingService; +import org.apache.dubbo.config.ApplicationConfig; +import org.apache.dubbo.config.ReferenceConfig; +import org.apache.dubbo.config.RegistryConfig; +import org.apache.dubbo.samples.api.GreetingService; public class Application { public static void main(String[] args) { diff --git a/dubbo-all/pom.xml b/dubbo-all/pom.xml index 6e507dd5e7c..15fd731d706 100644 --- a/dubbo-all/pom.xml +++ b/dubbo-all/pom.xml @@ -19,11 +19,11 @@ org.apache.dubbo dubbo-parent - 2.7.0-SNAPSHOT + 2.7.1-SNAPSHOT ../pom.xml dubbo - 2.7.0-SNAPSHOT + 2.7.1-SNAPSHOT jar dubbo-all The all in one project of dubbo @@ -395,6 +395,10 @@ io.netty netty-all + + com.google.code.gson + gson + @@ -488,7 +492,6 @@ org.apache.dubbo:dubbo-metadata-definition org.apache.dubbo:dubbo-metadata-report-redis org.apache.dubbo:dubbo-metadata-report-zookeeper - com.google.code.gson:gson @@ -606,12 +609,23 @@ META-INF/dubbo/internal/org.apache.dubbo.qos.command.BaseCommand - - META-INF/dubbo/internal/org.apache.dubbo.configcenter.DynamicConfiguration + + META-INF/dubbo/internal/org.apache.dubbo.configcenter.DynamicConfigurationFactory + + + org.apache.dubbo:dubbo + + + com/** + org/** + + META-INF/dubbo/** + + + diff --git a/dubbo-bom/pom.xml b/dubbo-bom/pom.xml index dd87f685970..c0997313247 100644 --- a/dubbo-bom/pom.xml +++ b/dubbo-bom/pom.xml @@ -6,12 +6,12 @@ org.apache.dubbo dubbo-parent - 2.7.0-SNAPSHOT + 2.7.1-SNAPSHOT org.apache.dubbo dubbo-bom - 2.7.0-SNAPSHOT + 2.7.1-SNAPSHOT pom dubbo-bom diff --git a/dubbo-cluster/pom.xml b/dubbo-cluster/pom.xml index 6688160109c..58d0367d873 100644 --- a/dubbo-cluster/pom.xml +++ b/dubbo-cluster/pom.xml @@ -19,7 +19,7 @@ org.apache.dubbo dubbo-parent - 2.7.0-SNAPSHOT + 2.7.1-SNAPSHOT dubbo-cluster jar diff --git a/dubbo-cluster/src/main/java/org/apache/dubbo/rpc/cluster/Configurator.java b/dubbo-cluster/src/main/java/org/apache/dubbo/rpc/cluster/Configurator.java index 8d5f02c2861..b85a0461312 100644 --- a/dubbo-cluster/src/main/java/org/apache/dubbo/rpc/cluster/Configurator.java +++ b/dubbo-cluster/src/main/java/org/apache/dubbo/rpc/cluster/Configurator.java @@ -98,6 +98,7 @@ static Optional> toConfigurators(List urls) { * 1. the url with a specific host ip should have higher priority than 0.0.0.0 * 2. if two url has the same host, compare by priority value; */ + @Override default int compareTo(Configurator o) { if (o == null) { return -1; diff --git a/dubbo-cluster/src/main/java/org/apache/dubbo/rpc/cluster/Router.java b/dubbo-cluster/src/main/java/org/apache/dubbo/rpc/cluster/Router.java index 5addb8e4911..70fd8faa3a6 100644 --- a/dubbo-cluster/src/main/java/org/apache/dubbo/rpc/cluster/Router.java +++ b/dubbo-cluster/src/main/java/org/apache/dubbo/rpc/cluster/Router.java @@ -85,4 +85,22 @@ default void notify(List> invokers) { * @return router's priority */ int getPriority(); + + @Override + default int compareTo(Router o) { + if (o == null) { + throw new IllegalArgumentException(); + } + if (this.getPriority() == o.getPriority()) { + if (o.getUrl() == null) { + return 1; + } + if (getUrl() == null) { + return -1; + } + return getUrl().toFullString().compareTo(o.getUrl().toFullString()); + } else { + return getPriority() > o.getPriority() ? 1 : -1; + } + } } diff --git a/dubbo-cluster/src/main/java/org/apache/dubbo/rpc/cluster/configurator/override/OverrideConfigurator.java b/dubbo-cluster/src/main/java/org/apache/dubbo/rpc/cluster/configurator/override/OverrideConfigurator.java index 1d57773edbc..bc9beb4f8b4 100644 --- a/dubbo-cluster/src/main/java/org/apache/dubbo/rpc/cluster/configurator/override/OverrideConfigurator.java +++ b/dubbo-cluster/src/main/java/org/apache/dubbo/rpc/cluster/configurator/override/OverrideConfigurator.java @@ -20,7 +20,7 @@ import org.apache.dubbo.rpc.cluster.configurator.AbstractConfigurator; /** - * AbsentConfigurator + * OverrideConfigurator * */ public class OverrideConfigurator extends AbstractConfigurator { diff --git a/dubbo-cluster/src/main/java/org/apache/dubbo/rpc/cluster/configurator/override/OverrideConfiguratorFactory.java b/dubbo-cluster/src/main/java/org/apache/dubbo/rpc/cluster/configurator/override/OverrideConfiguratorFactory.java index 051b4bd82fd..a63aa55004e 100644 --- a/dubbo-cluster/src/main/java/org/apache/dubbo/rpc/cluster/configurator/override/OverrideConfiguratorFactory.java +++ b/dubbo-cluster/src/main/java/org/apache/dubbo/rpc/cluster/configurator/override/OverrideConfiguratorFactory.java @@ -21,7 +21,7 @@ import org.apache.dubbo.rpc.cluster.ConfiguratorFactory; /** - * AbsentConfiguratorFactory + * OverrideConfiguratorFactory * */ public class OverrideConfiguratorFactory implements ConfiguratorFactory { diff --git a/dubbo-cluster/src/main/java/org/apache/dubbo/rpc/cluster/directory/AbstractDirectory.java b/dubbo-cluster/src/main/java/org/apache/dubbo/rpc/cluster/directory/AbstractDirectory.java index 54ce8269afd..c6a01e8ec43 100644 --- a/dubbo-cluster/src/main/java/org/apache/dubbo/rpc/cluster/directory/AbstractDirectory.java +++ b/dubbo-cluster/src/main/java/org/apache/dubbo/rpc/cluster/directory/AbstractDirectory.java @@ -64,7 +64,7 @@ public AbstractDirectory(URL url, URL consumerUrl, RouterChain routerChain) { if (url.getProtocol().equals(Constants.REGISTRY_PROTOCOL)) { Map queryMap = StringUtils.parseQueryString(url.getParameterAndDecoded(Constants.REFER_KEY)); - this.url = url.clearParameters().addParameters(queryMap).removeParameter(Constants.MONITOR_KEY); + this.url = url.addParameters(queryMap).removeParameter(Constants.MONITOR_KEY); } else { this.url = url; } diff --git a/dubbo-cluster/src/main/java/org/apache/dubbo/rpc/cluster/directory/StaticDirectory.java b/dubbo-cluster/src/main/java/org/apache/dubbo/rpc/cluster/directory/StaticDirectory.java index cccbd12e3fd..c5a26a3f7d3 100644 --- a/dubbo-cluster/src/main/java/org/apache/dubbo/rpc/cluster/directory/StaticDirectory.java +++ b/dubbo-cluster/src/main/java/org/apache/dubbo/rpc/cluster/directory/StaticDirectory.java @@ -97,7 +97,6 @@ protected List> doList(Invocation invocation) throws RpcException { List> finalInvokers = invokers; if (routerChain != null) { try { - // Get invokers from cache, only runtime routers will be executed. finalInvokers = routerChain.route(getConsumerUrl(), invocation); } catch (Throwable t) { logger.error("Failed to execute router: " + getUrl() + ", cause: " + t.getMessage(), t); diff --git a/dubbo-cluster/src/main/java/org/apache/dubbo/rpc/cluster/loadbalance/ConsistentHashLoadBalance.java b/dubbo-cluster/src/main/java/org/apache/dubbo/rpc/cluster/loadbalance/ConsistentHashLoadBalance.java index 8671cdeca82..83d6f8c9112 100644 --- a/dubbo-cluster/src/main/java/org/apache/dubbo/rpc/cluster/loadbalance/ConsistentHashLoadBalance.java +++ b/dubbo-cluster/src/main/java/org/apache/dubbo/rpc/cluster/loadbalance/ConsistentHashLoadBalance.java @@ -22,7 +22,7 @@ import org.apache.dubbo.rpc.Invoker; import org.apache.dubbo.rpc.support.RpcUtils; -import java.io.UnsupportedEncodingException; +import java.nio.charset.StandardCharsets; import java.security.MessageDigest; import java.security.NoSuchAlgorithmException; import java.util.List; @@ -33,7 +33,6 @@ /** * ConsistentHashLoadBalance - * */ public class ConsistentHashLoadBalance extends AbstractLoadBalance { public static final String NAME = "consistenthash"; @@ -126,12 +125,7 @@ private byte[] md5(String value) { throw new IllegalStateException(e.getMessage(), e); } md5.reset(); - byte[] bytes; - try { - bytes = value.getBytes("UTF-8"); - } catch (UnsupportedEncodingException e) { - throw new IllegalStateException(e.getMessage(), e); - } + byte[] bytes = value.getBytes(StandardCharsets.UTF_8); md5.update(bytes); return md5.digest(); } diff --git a/dubbo-cluster/src/main/java/org/apache/dubbo/rpc/cluster/router/AbstractRouter.java b/dubbo-cluster/src/main/java/org/apache/dubbo/rpc/cluster/router/AbstractRouter.java index 411c213eb29..f826dae570a 100644 --- a/dubbo-cluster/src/main/java/org/apache/dubbo/rpc/cluster/router/AbstractRouter.java +++ b/dubbo-cluster/src/main/java/org/apache/dubbo/rpc/cluster/router/AbstractRouter.java @@ -20,9 +20,6 @@ import org.apache.dubbo.configcenter.DynamicConfiguration; import org.apache.dubbo.rpc.cluster.Router; -/** - * TODO Extract more code to here if necessary - */ public abstract class AbstractRouter implements Router { protected int priority; protected boolean force = false; @@ -65,11 +62,6 @@ public void setForce(boolean force) { this.force = force; } - @Override - public int compareTo(Router o) { - return (this.getPriority() >= o.getPriority()) ? 1 : -1; - } - @Override public int getPriority() { return priority; diff --git a/dubbo-cluster/src/main/java/org/apache/dubbo/rpc/cluster/router/condition/config/AppRouter.java b/dubbo-cluster/src/main/java/org/apache/dubbo/rpc/cluster/router/condition/config/AppRouter.java index e9276b6a526..9c723df54f3 100644 --- a/dubbo-cluster/src/main/java/org/apache/dubbo/rpc/cluster/router/condition/config/AppRouter.java +++ b/dubbo-cluster/src/main/java/org/apache/dubbo/rpc/cluster/router/condition/config/AppRouter.java @@ -21,7 +21,7 @@ import org.apache.dubbo.configcenter.DynamicConfiguration; /** - * Application level router, "application.routers" + * Application level router, "application.condition-router" */ public class AppRouter extends ListenableRouter { public static final String NAME = "APP_ROUTER"; diff --git a/dubbo-cluster/src/main/java/org/apache/dubbo/rpc/cluster/router/condition/config/ListenableRouter.java b/dubbo-cluster/src/main/java/org/apache/dubbo/rpc/cluster/router/condition/config/ListenableRouter.java index 84419a7ea30..65a4eec7d52 100644 --- a/dubbo-cluster/src/main/java/org/apache/dubbo/rpc/cluster/router/condition/config/ListenableRouter.java +++ b/dubbo-cluster/src/main/java/org/apache/dubbo/rpc/cluster/router/condition/config/ListenableRouter.java @@ -16,7 +16,6 @@ */ package org.apache.dubbo.rpc.cluster.router.condition.config; -import org.apache.dubbo.common.Constants; import org.apache.dubbo.common.URL; import org.apache.dubbo.common.logger.Logger; import org.apache.dubbo.common.logger.LoggerFactory; @@ -32,22 +31,23 @@ import org.apache.dubbo.rpc.cluster.Router; import org.apache.dubbo.rpc.cluster.router.AbstractRouter; import org.apache.dubbo.rpc.cluster.router.condition.ConditionRouter; -import org.apache.dubbo.rpc.cluster.router.condition.config.model.BlackWhiteListRule; import org.apache.dubbo.rpc.cluster.router.condition.config.model.ConditionRouterRule; import org.apache.dubbo.rpc.cluster.router.condition.config.model.ConditionRuleParser; -import java.util.ArrayList; +import java.util.Collections; import java.util.List; +import java.util.stream.Collectors; /** * Abstract router which listens to dynamic configuration */ public abstract class ListenableRouter extends AbstractRouter implements ConfigurationListener { public static final String NAME = "LISTENABLE_ROUTER"; + private static final String RULE_SUFFIX = ".condition-router"; public static final int DEFAULT_PRIORITY = 200; private static final Logger logger = LoggerFactory.getLogger(ListenableRouter.class); private ConditionRouterRule routerRule; - private List conditionRouters = new ArrayList<>(); + private List conditionRouters = Collections.emptyList(); public ListenableRouter(DynamicConfiguration configuration, URL url, String ruleKey) { super(configuration, url); @@ -64,11 +64,11 @@ public synchronized void process(ConfigChangeEvent event) { if (event.getChangeType().equals(ConfigChangeType.DELETED)) { routerRule = null; - conditionRouters.clear(); + conditionRouters = Collections.emptyList(); } else { try { routerRule = ConditionRuleParser.parse(event.getValue()); - generateConditions(routerRule, conditionRouters); + generateConditions(routerRule); } catch (Exception e) { logger.error("Failed to parse the raw condition rule and it will not take effect, please check " + "if the condition rule matches with the template, the raw rule is:\n " + event.getValue(), e); @@ -104,23 +104,12 @@ private boolean isRuleRuntime() { return routerRule != null && routerRule.isValid() && routerRule.isRuntime(); } - private void generateConditions(ConditionRouterRule rule, List routers) { + private void generateConditions(ConditionRouterRule rule) { if (rule != null && rule.isValid()) { - routers.clear(); - rule.getConditions().forEach(condition -> { - // All sub rules have the same force, runtime value. - ConditionRouter subRouter = new ConditionRouter(condition, rule.isForce(), rule.isEnabled()); - routers.add(subRouter); - }); - - BlackWhiteListRule blackWhiteList = rule.getBlackWhiteList(); - if (blackWhiteList != null && blackWhiteList.isValid()) { - blackWhiteList.getConditions().forEach(condition -> { - // All sub rules have the same force, runtime value. - ConditionRouter subRouter = new ConditionRouter(condition, true, blackWhiteList.isEnabled()); - routers.add(subRouter); - }); - } + this.conditionRouters = rule.getConditions() + .stream() + .map(condition -> new ConditionRouter(condition, rule.isForce(), rule.isEnabled())) + .collect(Collectors.toList()); } } @@ -128,7 +117,7 @@ private synchronized void init(String ruleKey) { if (StringUtils.isEmpty(ruleKey)) { return; } - String routerKey = ruleKey + Constants.ROUTERS_SUFFIX; + String routerKey = ruleKey + RULE_SUFFIX; configuration.addListener(routerKey, this); String rule = configuration.getConfig(routerKey); if (rule != null) { diff --git a/dubbo-cluster/src/main/java/org/apache/dubbo/rpc/cluster/router/condition/config/ServiceRouter.java b/dubbo-cluster/src/main/java/org/apache/dubbo/rpc/cluster/router/condition/config/ServiceRouter.java index 13fd69bccb8..c76f2a7c054 100644 --- a/dubbo-cluster/src/main/java/org/apache/dubbo/rpc/cluster/router/condition/config/ServiceRouter.java +++ b/dubbo-cluster/src/main/java/org/apache/dubbo/rpc/cluster/router/condition/config/ServiceRouter.java @@ -20,7 +20,7 @@ import org.apache.dubbo.configcenter.DynamicConfiguration; /** - * Service level router, "server-uniq-name.routers" + * Service level router, "server-unique-name.condition-router" */ public class ServiceRouter extends ListenableRouter { public static final String NAME = "SERVICE_ROUTER"; diff --git a/dubbo-cluster/src/main/java/org/apache/dubbo/rpc/cluster/router/condition/config/model/ConditionRouterRule.java b/dubbo-cluster/src/main/java/org/apache/dubbo/rpc/cluster/router/condition/config/model/ConditionRouterRule.java index ede69133d2c..7455585fe59 100644 --- a/dubbo-cluster/src/main/java/org/apache/dubbo/rpc/cluster/router/condition/config/model/ConditionRouterRule.java +++ b/dubbo-cluster/src/main/java/org/apache/dubbo/rpc/cluster/router/condition/config/model/ConditionRouterRule.java @@ -27,7 +27,6 @@ public class ConditionRouterRule extends AbstractRouterRule { public ConditionRouterRule() { } - private BlackWhiteListRule blackWhiteList; private List conditions; public List getConditions() { @@ -37,12 +36,4 @@ public List getConditions() { public void setConditions(List conditions) { this.conditions = conditions; } - - public BlackWhiteListRule getBlackWhiteList() { - return blackWhiteList; - } - - public void setBlackWhiteList(BlackWhiteListRule blackWhiteList) { - this.blackWhiteList = blackWhiteList; - } } diff --git a/dubbo-cluster/src/main/java/org/apache/dubbo/rpc/cluster/router/condition/config/model/ConditionRuleParser.java b/dubbo-cluster/src/main/java/org/apache/dubbo/rpc/cluster/router/condition/config/model/ConditionRuleParser.java index 4c6a04bac04..07cc7ede2d8 100644 --- a/dubbo-cluster/src/main/java/org/apache/dubbo/rpc/cluster/router/condition/config/model/ConditionRuleParser.java +++ b/dubbo-cluster/src/main/java/org/apache/dubbo/rpc/cluster/router/condition/config/model/ConditionRuleParser.java @@ -47,10 +47,6 @@ public static ConditionRouterRule parse(String rawRule) { rule.setValid(false); } - BlackWhiteListRule blackWhiteList = rule.getBlackWhiteList(); - if (blackWhiteList != null && CollectionUtils.isEmpty(blackWhiteList.getConditions())) { - blackWhiteList.setValid(false); - } return rule; } diff --git a/dubbo-cluster/src/main/java/org/apache/dubbo/rpc/cluster/router/mock/MockInvokersSelector.java b/dubbo-cluster/src/main/java/org/apache/dubbo/rpc/cluster/router/mock/MockInvokersSelector.java index 896638a2c04..d6961d630bd 100644 --- a/dubbo-cluster/src/main/java/org/apache/dubbo/rpc/cluster/router/mock/MockInvokersSelector.java +++ b/dubbo-cluster/src/main/java/org/apache/dubbo/rpc/cluster/router/mock/MockInvokersSelector.java @@ -22,7 +22,6 @@ import org.apache.dubbo.rpc.Invocation; import org.apache.dubbo.rpc.Invoker; import org.apache.dubbo.rpc.RpcException; -import org.apache.dubbo.rpc.cluster.Router; import org.apache.dubbo.rpc.cluster.router.AbstractRouter; import java.util.ArrayList; @@ -95,15 +94,9 @@ private boolean hasMockProviders(final List> invokers) { return hasMockProvider; } - /** - * Always stay on the top of the list - * - * @param o - * @return - */ @Override - public int compareTo(Router o) { - return 1; + public int getPriority() { + return Integer.MAX_VALUE; } } diff --git a/dubbo-cluster/src/main/java/org/apache/dubbo/rpc/cluster/router/script/ScriptRouter.java b/dubbo-cluster/src/main/java/org/apache/dubbo/rpc/cluster/router/script/ScriptRouter.java index 3a04f88e601..74ef98bd38b 100644 --- a/dubbo-cluster/src/main/java/org/apache/dubbo/rpc/cluster/router/script/ScriptRouter.java +++ b/dubbo-cluster/src/main/java/org/apache/dubbo/rpc/cluster/router/script/ScriptRouter.java @@ -25,6 +25,7 @@ import org.apache.dubbo.rpc.Invoker; import org.apache.dubbo.rpc.RpcContext; import org.apache.dubbo.rpc.RpcException; +import org.apache.dubbo.rpc.cluster.Router; import org.apache.dubbo.rpc.cluster.router.AbstractRouter; import javax.script.Bindings; @@ -38,6 +39,7 @@ import java.util.List; import java.util.Map; import java.util.concurrent.ConcurrentHashMap; +import java.util.stream.Collectors; /** * ScriptRouter @@ -50,61 +52,49 @@ public class ScriptRouter extends AbstractRouter { private final ScriptEngine engine; - private final int priority; - private final String rule; public ScriptRouter(URL url) { this.url = url; - String type = url.getParameter(Constants.TYPE_KEY); this.priority = url.getParameter(Constants.PRIORITY_KEY, 0); - String rule = url.getParameterAndDecoded(Constants.RULE_KEY); - if (StringUtils.isEmpty(type)) { - type = Constants.DEFAULT_SCRIPT_TYPE_KEY; - } - if (StringUtils.isEmpty(rule)) { - throw new IllegalStateException("route rule can not be empty. rule:" + rule); - } - ScriptEngine engine = engines.get(type); - if (engine == null) { - engine = new ScriptEngineManager().getEngineByName(type); - if (engine == null) { - throw new IllegalStateException("unsupported route rule type: " + type + ", rule: " + rule); - } - engines.put(type, engine); - } - this.engine = engine; - this.rule = rule; + + engine = getEngine(url); + rule = getRule(url); } - @Override - public URL getUrl() { - return url; + /** + * get rule from url parameters. + */ + private String getRule(URL url) { + String vRule = url.getParameterAndDecoded(Constants.RULE_KEY); + if (StringUtils.isEmpty(vRule)) { + throw new IllegalStateException("route rule can not be empty."); + } + return vRule; + } + + /** + * create ScriptEngine instance by type from url parameters, then cache it + */ + private ScriptEngine getEngine(URL url) { + String type = url.getParameter(Constants.TYPE_KEY, Constants.DEFAULT_SCRIPT_TYPE_KEY); + + return engines.computeIfAbsent(type, t -> { + ScriptEngine scriptEngine = new ScriptEngineManager().getEngineByName(type); + if (scriptEngine == null) { + throw new IllegalStateException("unsupported route engine type: " + type); + } + return scriptEngine; + }); } @Override - @SuppressWarnings("unchecked") public List> route(List> invokers, URL url, Invocation invocation) throws RpcException { try { - List> invokersCopy = new ArrayList<>(invokers); + Bindings bindings = createBindings(invokers, invocation); Compilable compilable = (Compilable) engine; - Bindings bindings = engine.createBindings(); - bindings.put("invokers", invokersCopy); - bindings.put("invocation", invocation); - bindings.put("context", RpcContext.getContext()); CompiledScript function = compilable.compile(rule); - Object obj = function.eval(bindings); - if (obj instanceof Invoker[]) { - invokersCopy = Arrays.asList((Invoker[]) obj); - } else if (obj instanceof Object[]) { - invokersCopy = new ArrayList>(); - for (Object inv : (Object[]) obj) { - invokersCopy.add((Invoker) inv); - } - } else { - invokersCopy = (List>) obj; - } - return invokersCopy; + return getRoutedInvokers(function.eval(bindings)); } catch (ScriptException e) { logger.error("route error, rule has been ignored. rule: " + rule + ", method:" + invocation.getMethodName() + ", url: " + RpcContext.getContext().getUrl(), e); @@ -112,6 +102,32 @@ public List> route(List> invokers, URL url, Invocation } } + /** + * get routed invokers from result of script rule evaluation + */ + @SuppressWarnings("unchecked") + protected List> getRoutedInvokers(Object obj) { + if (obj instanceof Invoker[]) { + return Arrays.asList((Invoker[]) obj); + } else if (obj instanceof Object[]) { + return Arrays.stream((Object[]) obj).map(item -> (Invoker) item).collect(Collectors.toList()); + } else { + return (List>) obj; + } + } + + /** + * create bindings for script engine + */ + private Bindings createBindings(List> invokers, Invocation invocation) { + Bindings bindings = engine.createBindings(); + // create a new List of invokers + bindings.put("invokers", new ArrayList<>(invokers)); + bindings.put("invocation", invocation); + bindings.put("context", RpcContext.getContext()); + return bindings; + } + @Override public boolean isRuntime() { return this.url.getParameter(Constants.RUNTIME_KEY, false); @@ -121,4 +137,13 @@ public boolean isRuntime() { public boolean isForce() { return url.getParameter(Constants.FORCE_KEY, false); } + + @Override + public int compareTo(Router o) { + if (o == null || o.getClass() != ScriptRouter.class) { + return 1; + } + ScriptRouter c = (ScriptRouter) o; + return this.priority == c.priority ? rule.compareTo(c.rule) : (this.priority > c.priority ? 1 : -1); + } } diff --git a/dubbo-cluster/src/main/java/org/apache/dubbo/rpc/cluster/router/tag/TagRouter.java b/dubbo-cluster/src/main/java/org/apache/dubbo/rpc/cluster/router/tag/TagRouter.java index d65371e1ab2..c8e8750bff4 100644 --- a/dubbo-cluster/src/main/java/org/apache/dubbo/rpc/cluster/router/tag/TagRouter.java +++ b/dubbo-cluster/src/main/java/org/apache/dubbo/rpc/cluster/router/tag/TagRouter.java @@ -42,13 +42,13 @@ import static org.apache.dubbo.common.Constants.TAG_KEY; /** - * TagRouter + * TagRouter, "application.tag-router" */ public class TagRouter extends AbstractRouter implements Comparable, ConfigurationListener { public static final String NAME = "TAG_ROUTER"; private static final int DEFAULT_PRIORITY = 100; private static final Logger logger = LoggerFactory.getLogger(TagRouter.class); - private static final String RULE_PREFIX = ".tagrouters"; + private static final String RULE_SUFFIX = ".tag-router"; private TagRouterRule tagRouterRule; private String application; @@ -88,7 +88,7 @@ public List> route(List> invokers, URL url, Invocation } if (tagRouterRule == null || !tagRouterRule.isValid() || !tagRouterRule.isEnabled()) { - return invokers; + return filterUsingStaticTag(invokers, url, invocation); } List> result = invokers; @@ -112,7 +112,7 @@ public List> route(List> invokers, URL url, Invocation } // If there's no tagged providers that can match the current tagged request. force.tag is set by default // to false, which means it will invoke any providers without a tag unless it's explicitly disallowed. - if (CollectionUtils.isNotEmpty(result) || isForceUse(invocation)) { + if (CollectionUtils.isNotEmpty(result) || isForceUseTag(invocation)) { return result; } // FAILOVER: return all Providers without any tags. @@ -141,6 +141,37 @@ public List> route(List> invokers, URL url, Invocation } } + /** + * If there's no dynamic tag rule being set, use static tag in URL. + * + * A typical scenario is a Consumer using version 2.7.x calls Providers using version 2.6.x or lower, + * the Consumer should always respect the tag in provider URL regardless of whether a dynamic tag rule has been set to it or not. + * + * TODO, to guarantee consistent behavior of interoperability between 2.6- and 2.7+, this method should has the same logic with the TagRouter in 2.6.x. + * + * @param invokers + * @param url + * @param invocation + * @param + * @return + */ + private List> filterUsingStaticTag(List> invokers, URL url, Invocation invocation) { + List> result = invokers; + // Dynamic param + String tag = StringUtils.isEmpty(invocation.getAttachment(TAG_KEY)) ? url.getParameter(TAG_KEY) : + invocation.getAttachment(TAG_KEY); + // Tag request + if (!StringUtils.isEmpty(tag)) { + result = filterInvoker(invokers, invoker -> tag.equals(invoker.getUrl().getParameter(Constants.TAG_KEY))); + if (CollectionUtils.isEmpty(result) && !isForceUseTag(invocation)) { + result = filterInvoker(invokers, invoker -> StringUtils.isEmpty(invoker.getUrl().getParameter(Constants.TAG_KEY))); + } + } else { + result = filterInvoker(invokers, invoker -> StringUtils.isEmpty(invoker.getUrl().getParameter(Constants.TAG_KEY))); + } + return result; + } + @Override public int getPriority() { return DEFAULT_PRIORITY; @@ -157,7 +188,7 @@ public boolean isForce() { return tagRouterRule != null && tagRouterRule.isForce(); } - private boolean isForceUse(Invocation invocation) { + private boolean isForceUseTag(Invocation invocation) { return Boolean.valueOf(invocation.getAttachment(FORCE_USE_TAG, url.getParameter(FORCE_USE_TAG, "false"))); } @@ -198,9 +229,9 @@ public void notify(List> invokers) { synchronized (this) { if (!providerApplication.equals(application)) { if (!StringUtils.isEmpty(application)) { - configuration.removeListener(application + RULE_PREFIX, this); + configuration.removeListener(application + RULE_SUFFIX, this); } - String key = providerApplication + RULE_PREFIX; + String key = providerApplication + RULE_SUFFIX; configuration.addListener(key, this); application = providerApplication; String rawRule = configuration.getConfig(key); diff --git a/dubbo-cluster/src/main/java/org/apache/dubbo/rpc/cluster/support/AbstractClusterInvoker.java b/dubbo-cluster/src/main/java/org/apache/dubbo/rpc/cluster/support/AbstractClusterInvoker.java index 63486aa5c5c..abc9cf21afb 100644 --- a/dubbo-cluster/src/main/java/org/apache/dubbo/rpc/cluster/support/AbstractClusterInvoker.java +++ b/dubbo-cluster/src/main/java/org/apache/dubbo/rpc/cluster/support/AbstractClusterInvoker.java @@ -109,10 +109,10 @@ public void destroy() { * @param invokers invoker candidates * @param selected exclude selected invokers or not * @return the invoker which will final to do invoke. - * @throws RpcException + * @throws RpcException exception */ protected Invoker select(LoadBalance loadbalance, Invocation invocation, - List> invokers, List> selected) throws RpcException { + List> invokers, List> selected) throws RpcException { if (CollectionUtils.isEmpty(invokers)) { return null; @@ -120,7 +120,7 @@ protected Invoker select(LoadBalance loadbalance, Invocation invocation, String methodName = invocation == null ? StringUtils.EMPTY : invocation.getMethodName(); boolean sticky = invokers.get(0).getUrl() - .getMethodParameter(methodName, Constants.CLUSTER_STICKY_KEY, Constants.DEFAULT_CLUSTER_STICKY); + .getMethodParameter(methodName, Constants.CLUSTER_STICKY_KEY, Constants.DEFAULT_CLUSTER_STICKY); //ignore overloaded method if (stickyInvoker != null && !invokers.contains(stickyInvoker)) { @@ -142,7 +142,7 @@ protected Invoker select(LoadBalance loadbalance, Invocation invocation, } private Invoker doSelect(LoadBalance loadbalance, Invocation invocation, - List> invokers, List> selected) throws RpcException { + List> invokers, List> selected) throws RpcException { if (CollectionUtils.isEmpty(invokers)) { return null; @@ -180,19 +180,20 @@ private Invoker doSelect(LoadBalance loadbalance, Invocation invocation, * Reselect, use invokers not in `selected` first, if all invokers are in `selected`, * just pick an available one using loadbalance policy. * - * @param loadbalance - * @param invocation - * @param invokers - * @param selected - * @return - * @throws RpcException + * @param loadbalance load balance policy + * @param invocation invocation + * @param invokers invoker candidates + * @param selected exclude selected invokers or not + * @param availablecheck check invoker available if true + * @return the reselect result to do invoke + * @throws RpcException exception */ private Invoker reselect(LoadBalance loadbalance, Invocation invocation, - List> invokers, List> selected, boolean availablecheck) throws RpcException { + List> invokers, List> selected, boolean availablecheck) throws RpcException { //Allocating one in advance, this list is certain to be used. List> reselectInvokers = new ArrayList<>( - invokers.size() > 1 ? (invokers.size() - 1) : invokers.size()); + invokers.size() > 1 ? (invokers.size() - 1) : invokers.size()); // First, try picking a invoker not in `selected`. for (Invoker invoker : invokers) { @@ -242,7 +243,6 @@ public Result invoke(final Invocation invocation) throws RpcException { } protected void checkWhetherDestroyed() { - if (destroyed.get()) { throw new RpcException("Rpc cluster invoker for " + getInterface() + " on consumer " + NetUtils.getLocalHost() + " use dubbo version " + Version.getVersion() diff --git a/dubbo-cluster/src/main/java/org/apache/dubbo/rpc/cluster/support/ClusterUtils.java b/dubbo-cluster/src/main/java/org/apache/dubbo/rpc/cluster/support/ClusterUtils.java index da5e04d13d6..8901e4cacec 100644 --- a/dubbo-cluster/src/main/java/org/apache/dubbo/rpc/cluster/support/ClusterUtils.java +++ b/dubbo-cluster/src/main/java/org/apache/dubbo/rpc/cluster/support/ClusterUtils.java @@ -18,6 +18,7 @@ import org.apache.dubbo.common.Constants; import org.apache.dubbo.common.URL; +import org.apache.dubbo.common.utils.StringUtils; import java.util.HashMap; import java.util.HashSet; @@ -81,8 +82,14 @@ public static URL mergeUrl(URL remoteUrl, Map localMap) { // So, generally, we don't need to care about the group value here. // But when comes to group merger, there is an exception, the consumer group may be '*' while the provider group can be empty or any other values. String remoteGroup = map.get(Constants.GROUP_KEY); + String remoteRelease = map.get(Constants.RELEASE_KEY); map.putAll(localMap); map.put(Constants.GROUP_KEY, remoteGroup); + // we should always keep the Provider RELEASE_KEY not overrode by the the value on Consumer side. + map.remove(Constants.RELEASE_KEY); + if (StringUtils.isNotEmpty(remoteRelease)) { + map.put(Constants.RELEASE_KEY, remoteRelease); + } } if (remoteMap != null && remoteMap.size() > 0) { // Use version passed from provider side diff --git a/dubbo-cluster/src/test/java/org/apache/dubbo/rpc/cluster/router/ConfigConditionRouterTest.java b/dubbo-cluster/src/test/java/org/apache/dubbo/rpc/cluster/router/ConfigConditionRouterTest.java index 4480e159fb4..1235869a2e7 100644 --- a/dubbo-cluster/src/test/java/org/apache/dubbo/rpc/cluster/router/ConfigConditionRouterTest.java +++ b/dubbo-cluster/src/test/java/org/apache/dubbo/rpc/cluster/router/ConfigConditionRouterTest.java @@ -20,11 +20,10 @@ import org.apache.curator.framework.CuratorFrameworkFactory; import org.apache.curator.retry.ExponentialBackoffRetry; import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Disabled; import org.junit.jupiter.api.Test; -/** - * FIXME This is not a formal UT - */ +@Disabled("FIXME This is not a formal UT") public class ConfigConditionRouterTest { private static CuratorFramework client; @@ -48,7 +47,7 @@ public void normalConditionRuleApplicationLevelTest() { " - method=notExitMethod => \n" + "..."; try { - String servicePath = "/dubbo/config/demo-consumer/routers"; + String servicePath = "/dubbo/config/demo-consumer/condition-router"; if (client.checkExists().forPath(servicePath) == null) { client.create().creatingParentsIfNeeded().forPath(servicePath); } @@ -72,7 +71,7 @@ public void normalConditionRuleApplicationServiceLevelTest() { " - method=routeMethod1 => host=30.5.120.37\n" + "..."; try { - String servicePath = "/dubbo/config/demo-consumer/routers"; + String servicePath = "/dubbo/config/demo-consumer/condition-router"; if (client.checkExists().forPath(servicePath) == null) { client.create().creatingParentsIfNeeded().forPath(servicePath); } @@ -97,7 +96,7 @@ public void normalConditionRuleServiceLevelTest() { "..."; // String serviceStr = ""; try { - String servicePath = "/dubbo/config/org.apache.dubbo.demo.DemoService/routers"; + String servicePath = "/dubbo/config/org.apache.dubbo.demo.DemoService/condition-router"; if (client.checkExists().forPath(servicePath) == null) { client.create().creatingParentsIfNeeded().forPath(servicePath); } @@ -118,7 +117,7 @@ public void abnormalNoruleConditionRuleTest() { "key: org.apache.dubbo.demo.DemoService\n" + "..."; try { - String servicePath = "/dubbo/config/org.apache.dubbo.demo.DemoService/routers"; + String servicePath = "/dubbo/config/org.apache.dubbo.demo.DemoService/condition-router"; if (client.checkExists().forPath(servicePath) == null) { client.create().creatingParentsIfNeeded().forPath(servicePath); } diff --git a/dubbo-cluster/src/test/java/org/apache/dubbo/rpc/cluster/router/TagRouterTest.java b/dubbo-cluster/src/test/java/org/apache/dubbo/rpc/cluster/router/TagRouterTest.java index d2ec5b90006..98cdaf4d4df 100644 --- a/dubbo-cluster/src/test/java/org/apache/dubbo/rpc/cluster/router/TagRouterTest.java +++ b/dubbo-cluster/src/test/java/org/apache/dubbo/rpc/cluster/router/TagRouterTest.java @@ -20,11 +20,10 @@ import org.apache.curator.framework.CuratorFrameworkFactory; import org.apache.curator.retry.ExponentialBackoffRetry; import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Disabled; import org.junit.jupiter.api.Test; -/** - * FIXME This is not a formal UT - */ +@Disabled("FIXME This is not a formal UT") public class TagRouterTest { private static CuratorFramework client; @@ -51,7 +50,7 @@ public void normalTagRuleTest() { "..."; // String serviceStr = ""; try { - String servicePath = "/dubbo/config/demo-provider/tagrouters"; + String servicePath = "/dubbo/config/demo-provider/tag-router"; if (client.checkExists().forPath(servicePath) == null) { client.create().creatingParentsIfNeeded().forPath(servicePath); } diff --git a/dubbo-cluster/src/test/java/org/apache/dubbo/rpc/cluster/support/AbstractClusterInvokerTest.java b/dubbo-cluster/src/test/java/org/apache/dubbo/rpc/cluster/support/AbstractClusterInvokerTest.java index 149d019c0dd..130cdb5dd81 100644 --- a/dubbo-cluster/src/test/java/org/apache/dubbo/rpc/cluster/support/AbstractClusterInvokerTest.java +++ b/dubbo-cluster/src/test/java/org/apache/dubbo/rpc/cluster/support/AbstractClusterInvokerTest.java @@ -223,7 +223,7 @@ public void testSelect_multiInvokers() throws Exception { public void testCloseAvailablecheck() { LoadBalance lb = mock(LoadBalance.class); Map queryMap = StringUtils.parseQueryString(url.getParameterAndDecoded(Constants.REFER_KEY)); - URL tmpUrl = url.clearParameters().addParameters(queryMap).removeParameter(Constants.MONITOR_KEY); + URL tmpUrl = url.addParameters(queryMap).removeParameter(Constants.MONITOR_KEY); given(lb.select(invokers, tmpUrl, invocation)).willReturn(invoker1); initlistsize5(); diff --git a/dubbo-cluster/src/test/resources/log4j.xml b/dubbo-cluster/src/test/resources/log4j.xml index df9d68a0fab..eb0c9f105de 100644 --- a/dubbo-cluster/src/test/resources/log4j.xml +++ b/dubbo-cluster/src/test/resources/log4j.xml @@ -18,6 +18,7 @@ + diff --git a/dubbo-common/pom.xml b/dubbo-common/pom.xml index 22a13222fe2..bd3347f5240 100644 --- a/dubbo-common/pom.xml +++ b/dubbo-common/pom.xml @@ -20,7 +20,7 @@ org.apache.dubbo dubbo-parent - 2.7.0-SNAPSHOT + 2.7.1-SNAPSHOT dubbo-common jar diff --git a/dubbo-common/src/main/java/org/apache/dubbo/common/Constants.java b/dubbo-common/src/main/java/org/apache/dubbo/common/Constants.java index b0df6360c07..948082991c7 100644 --- a/dubbo-common/src/main/java/org/apache/dubbo/common/Constants.java +++ b/dubbo-common/src/main/java/org/apache/dubbo/common/Constants.java @@ -62,10 +62,10 @@ public class Constants { public static final String CONFIG_NAMESPACE_KEY = "config.namespace"; public static final String CONFIG_GROUP_KEY = "config.group"; public static final String CONFIG_CHECK_KEY = "config.check"; - public static final String CONFIG_CONFIGFILE_KEY = "config.configFile"; - public static final String CONFIG_ENABLE_KEY = "config.highestPriority"; + public static final String CONFIG_CONFIGFILE_KEY = "config.config-file"; + public static final String CONFIG_ENABLE_KEY = "config.highest-priority"; public static final String CONFIG_TIMEOUT_KEY = "config.timeout"; - public static final String CONFIG_APPNAME_KEY = "config.appName"; + public static final String CONFIG_APPNAME_KEY = "config.app-name"; public static final String DEFAULT_CATEGORY = PROVIDERS_CATEGORY; @@ -163,6 +163,8 @@ public class Constants { public static final int DEFAULT_FAILBACK_TIMES = 3; + public static final int MAX_PROXY_COUNT = 65535; + // default buffer size is 8k. public static final int DEFAULT_BUFFER_SIZE = 8 * 1024; @@ -176,6 +178,8 @@ public class Constants { public static final String REMOVE_VALUE_PREFIX = "-"; + public static final String PROPERTIES_CHAR_SEPERATOR = "-"; + public static final String HIDE_KEY_PREFIX = "."; public static final String DEFAULT_KEY_PREFIX = "default."; @@ -296,9 +300,9 @@ public class Constants { public static final long LEAST_HEARTBEAT_DURATION = 1000; /** - * ticks per wheel. Currently only contains two tasks, so 16 locations are enough + * ticks per wheel. */ - public static final int TICKS_PER_WHEEL = 16; + public static final int TICKS_PER_WHEEL = 128; public static final String HEARTBEAT_TIMEOUT_KEY = "heartbeat.timeout"; @@ -480,25 +484,17 @@ public class Constants { /** * simple the registry for provider. + * * @since 2.7.0 */ - public static final String SIMPLE_PROVIDER_CONFIG_KEY = "simple.provider.config"; - /** - * simple the registry for consumer. - * @since 2.7.0 - */ - public static final String SIMPLE_CONSUMER_CONFIG_KEY = "simple.consumer.config"; - /** - * After simplify the registry, should add some parameter individually for provider. - * @since 2.7.0 - */ - public static final String EXTRA_PROVIDER_CONFIG_KEYS_KEY = "extra.provider.keys"; + public static final String SIMPLIFIED_KEY = "simplified"; + /** - * After simplify the registry, should add some parameter individually for consumer. + * After simplify the registry, should add some paramter individually for provider. * * @since 2.7.0 */ - public static final String EXTRA_CONSUMER_CONFIG_KEYS_KEY = "extra.consumer.keys"; + public static final String EXTRA_KEYS_KEY = "extra-keys"; /** * To decide whether to exclude unavailable invoker from the cluster @@ -757,9 +753,9 @@ public class Constants { public static final String COMPATIBLE_CONFIG_KEY = "compatible_config"; // package version in the manifest - public static final String SPECIFICATION_VERSION_KEY = "specVersion"; + public static final String RELEASE_KEY = "release"; - public static final String OVERRIDE_PROVIDERS_KEY = "providerAddreses"; + public static final String OVERRIDE_PROVIDERS_KEY = "providerAddresses"; public static final String PROTOCOLS_SUFFIX = "dubbo.protocols."; @@ -768,9 +764,9 @@ public class Constants { public static final String REGISTRIES_SUFFIX = "dubbo.registries."; public static final String[] DEFAULT_REGISTER_PROVIDER_KEYS = {APPLICATION_KEY, CODEC_KEY, EXCHANGER_KEY, SERIALIZATION_KEY, CLUSTER_KEY, CONNECTIONS_KEY, DEPRECATED_KEY, - GROUP_KEY, LOADBALANCE_KEY, MOCK_KEY, PATH_KEY, TIMEOUT_KEY, TOKEN_KEY, VERSION_KEY, WARMUP_KEY, WEIGHT_KEY, TIMESTAMP_KEY, DUBBO_VERSION_KEY, SPECIFICATION_VERSION_KEY}; + GROUP_KEY, LOADBALANCE_KEY, MOCK_KEY, PATH_KEY, TIMEOUT_KEY, TOKEN_KEY, VERSION_KEY, WARMUP_KEY, WEIGHT_KEY, TIMESTAMP_KEY, DUBBO_VERSION_KEY, RELEASE_KEY}; - public static final String[] DEFAULT_REGISTER_CONSUMER_KEYS = {APPLICATION_KEY, VERSION_KEY, GROUP_KEY, DUBBO_VERSION_KEY, SPECIFICATION_VERSION_KEY}; + public static final String[] DEFAULT_REGISTER_CONSUMER_KEYS = {APPLICATION_KEY, VERSION_KEY, GROUP_KEY, DUBBO_VERSION_KEY, RELEASE_KEY}; public static final String TELNET = "telnet"; diff --git a/dubbo-common/src/main/java/org/apache/dubbo/common/URL.java b/dubbo-common/src/main/java/org/apache/dubbo/common/URL.java index cee9c863434..6e71e749d8c 100644 --- a/dubbo-common/src/main/java/org/apache/dubbo/common/URL.java +++ b/dubbo-common/src/main/java/org/apache/dubbo/common/URL.java @@ -500,6 +500,15 @@ public String[] getParameter(String key, String[] defaultValue) { return Constants.COMMA_SPLIT_PATTERN.split(value); } + public List getParameter(String key, List defaultValue) { + String value = getParameter(key); + if (value == null || value.length() == 0) { + return defaultValue; + } + String[] strArray = Constants.COMMA_SPLIT_PATTERN.split(value); + return Arrays.asList(strArray); + } + private Map getNumbers() { if (numbers == null) { // concurrent initialization is tolerant numbers = new ConcurrentHashMap(); @@ -727,7 +736,7 @@ public double getMethodParameter(String method, String key, double defaultValue) String methodKey = method + "." + key; Number n = getNumbers().get(methodKey); if (n != null) { - return n.intValue(); + return n.doubleValue(); } String value = getMethodParameter(method, key); if (StringUtils.isEmpty(value)) { @@ -742,7 +751,7 @@ public float getMethodParameter(String method, String key, float defaultValue) { String methodKey = method + "." + key; Number n = getNumbers().get(methodKey); if (n != null) { - return n.intValue(); + return n.floatValue(); } String value = getMethodParameter(method, key); if (StringUtils.isEmpty(value)) { @@ -757,7 +766,7 @@ public long getMethodParameter(String method, String key, long defaultValue) { String methodKey = method + "." + key; Number n = getNumbers().get(methodKey); if (n != null) { - return n.intValue(); + return n.longValue(); } String value = getMethodParameter(method, key); if (StringUtils.isEmpty(value)) { @@ -1269,6 +1278,7 @@ private String buildString(boolean appendUser, boolean appendParameter, boolean buf.append("/"); buf.append(path); } + if (appendParameter) { buildParameters(buf, true, parameters); } diff --git a/dubbo-common/src/main/java/org/apache/dubbo/common/Version.java b/dubbo-common/src/main/java/org/apache/dubbo/common/Version.java index 7f859fbb62b..099b2bb536e 100644 --- a/dubbo-common/src/main/java/org/apache/dubbo/common/Version.java +++ b/dubbo-common/src/main/java/org/apache/dubbo/common/Version.java @@ -42,9 +42,10 @@ public final class Version { /** * For protocol compatibility purpose. - * Because {@link #isSupportResponseAttachment} is checked for every call, int compare expect to has higher performance than string. + * Because {@link #isSupportResponseAttachment} is checked for every call, int compare expect to has higher + * performance than string. */ - private static final int LOWEST_VERSION_FOR_RESPONSE_ATTACHMENT = 20002; // 2.0.2 + private static final int LOWEST_VERSION_FOR_RESPONSE_ATTACHMENT = 2000200; // 2.0.2 private static final Map VERSION2INT = new HashMap(); static { @@ -63,13 +64,38 @@ public static String getVersion() { return VERSION; } + /** + * Check the framework release version number to decide if it's 2.7.0 or higher + */ + public static boolean isRelease270OrHigher(String version) { + if (StringUtils.isEmpty(version)) { + return false; + } + if (getIntVersion(version) >= 2070000) { + return true; + } + return false; + } + + /** + * Check the framework release version number to decide if it's 2.6.3 or higher + * + * Because response attachments feature is firstly introduced in 2.6.3 + * and moreover we have no other approach to know the framework's version, so we use + * isSupportResponseAttachment to decide if it's v2.6.3. + */ + public static boolean isRelease263OrHigher(String version) { + return isSupportResponseAttachment(version); + } + public static boolean isSupportResponseAttachment(String version) { if (StringUtils.isEmpty(version)) { return false; } - // for previous dubbo version(2.0.10/020010~2.6.2/020602), this version is the jar's version, so they need to be ignore + // for previous dubbo version(2.0.10/020010~2.6.2/020602), this version is the jar's version, so they need to + // be ignore int iVersion = getIntVersion(version); - if (iVersion >= 20010 && iVersion <= 20602) { + if (iVersion >= 2001000 && iVersion <= 2060200) { return false; } @@ -80,6 +106,10 @@ public static int getIntVersion(String version) { Integer v = VERSION2INT.get(version); if (v == null) { v = parseInt(version); + // e.g., version number 2.6.3 will convert to 2060300 + if (version.split("\\.").length == 3) { + v = v * 100; + } VERSION2INT.put(version, v); } return v; diff --git a/dubbo-common/src/main/java/org/apache/dubbo/common/bytecode/Proxy.java b/dubbo-common/src/main/java/org/apache/dubbo/common/bytecode/Proxy.java index 150e946b690..e72faae2cb1 100644 --- a/dubbo-common/src/main/java/org/apache/dubbo/common/bytecode/Proxy.java +++ b/dubbo-common/src/main/java/org/apache/dubbo/common/bytecode/Proxy.java @@ -16,6 +16,7 @@ */ package org.apache.dubbo.common.bytecode; +import org.apache.dubbo.common.Constants; import org.apache.dubbo.common.utils.ClassHelper; import org.apache.dubbo.common.utils.ReflectUtils; @@ -38,12 +39,7 @@ */ public abstract class Proxy { - public static final InvocationHandler RETURN_NULL_INVOKER = new InvocationHandler() { - @Override - public Object invoke(Object proxy, Method method, Object[] args) { - return null; - } - }; + public static final InvocationHandler RETURN_NULL_INVOKER = (proxy, method, args) -> null; public static final InvocationHandler THROW_UNSUPPORTED_INVOKER = new InvocationHandler() { @Override public Object invoke(Object proxy, Method method, Object[] args) { @@ -77,7 +73,7 @@ public static Proxy getProxy(Class... ics) { * @return Proxy instance. */ public static Proxy getProxy(ClassLoader cl, Class... ics) { - if (ics.length > 65535) { + if (ics.length > Constants.MAX_PROXY_COUNT) { throw new IllegalArgumentException("interface limit exceeded"); } @@ -107,11 +103,7 @@ public static Proxy getProxy(ClassLoader cl, Class... ics) { // get cache by class loader. Map cache; synchronized (ProxyCacheMap) { - cache = ProxyCacheMap.get(cl); - if (cache == null) { - cache = new HashMap(); - ProxyCacheMap.put(cl, cache); - } + cache = ProxyCacheMap.computeIfAbsent(cl, k -> new HashMap<>()); } Proxy proxy = null; @@ -144,8 +136,8 @@ public static Proxy getProxy(ClassLoader cl, Class... ics) { try { ccp = ClassGenerator.newInstance(cl); - Set worked = new HashSet(); - List methods = new ArrayList(); + Set worked = new HashSet<>(); + List methods = new ArrayList<>(); for (int i = 0; i < ics.length; i++) { if (!Modifier.isPublic(ics[i].getModifiers())) { @@ -175,7 +167,7 @@ public static Proxy getProxy(ClassLoader cl, Class... ics) { for (int j = 0; j < pts.length; j++) { code.append(" args[").append(j).append("] = ($w)$").append(j + 1).append(";"); } - code.append(" Object ret = handler.invoke(this, methods[" + ix + "], args);"); + code.append(" Object ret = handler.invoke(this, methods[").append(ix).append("], args);"); if (!Void.TYPE.equals(rt)) { code.append(" return ").append(asArgument(rt, "ret")).append(";"); } diff --git a/dubbo-common/src/main/java/org/apache/dubbo/common/bytecode/Wrapper.java b/dubbo-common/src/main/java/org/apache/dubbo/common/bytecode/Wrapper.java index 76113ba2e7b..6d3f42bd8fe 100644 --- a/dubbo-common/src/main/java/org/apache/dubbo/common/bytecode/Wrapper.java +++ b/dubbo-common/src/main/java/org/apache/dubbo/common/bytecode/Wrapper.java @@ -137,10 +137,10 @@ private static Wrapper makeWrapper(Class c) { c2.append(name).append(" w; try{ w = ((").append(name).append(")$1); }catch(Throwable e){ throw new IllegalArgumentException(e); }"); c3.append(name).append(" w; try{ w = ((").append(name).append(")$1); }catch(Throwable e){ throw new IllegalArgumentException(e); }"); - Map> pts = new HashMap>(); // - Map ms = new LinkedHashMap(); // - List mns = new ArrayList(); // method names. - List dmns = new ArrayList(); // declaring method names. + Map> pts = new HashMap<>(); // + Map ms = new LinkedHashMap<>(); // + List mns = new ArrayList<>(); // method names. + List dmns = new ArrayList<>(); // declaring method names. // get all public field. for (Field f : c.getFields()) { @@ -160,51 +160,49 @@ private static Wrapper makeWrapper(Class c) { boolean hasMethod = hasMethods(methods); if (hasMethod) { c3.append(" try{"); - } - for (Method m : methods) { - if (m.getDeclaringClass() == Object.class) //ignore Object's method. - { - continue; - } + for (Method m : methods) { + //ignore Object's method. + if (m.getDeclaringClass() == Object.class) { + continue; + } - String mn = m.getName(); - c3.append(" if( \"").append(mn).append("\".equals( $2 ) "); - int len = m.getParameterTypes().length; - c3.append(" && ").append(" $3.length == ").append(len); + String mn = m.getName(); + c3.append(" if( \"").append(mn).append("\".equals( $2 ) "); + int len = m.getParameterTypes().length; + c3.append(" && ").append(" $3.length == ").append(len); - boolean override = false; - for (Method m2 : methods) { - if (m != m2 && m.getName().equals(m2.getName())) { - override = true; - break; + boolean override = false; + for (Method m2 : methods) { + if (m != m2 && m.getName().equals(m2.getName())) { + override = true; + break; + } } - } - if (override) { - if (len > 0) { - for (int l = 0; l < len; l++) { - c3.append(" && ").append(" $3[").append(l).append("].getName().equals(\"") - .append(m.getParameterTypes()[l].getName()).append("\")"); + if (override) { + if (len > 0) { + for (int l = 0; l < len; l++) { + c3.append(" && ").append(" $3[").append(l).append("].getName().equals(\"") + .append(m.getParameterTypes()[l].getName()).append("\")"); + } } } - } - c3.append(" ) { "); + c3.append(" ) { "); - if (m.getReturnType() == Void.TYPE) { - c3.append(" w.").append(mn).append('(').append(args(m.getParameterTypes(), "$4")).append(");").append(" return null;"); - } else { - c3.append(" return ($w)w.").append(mn).append('(').append(args(m.getParameterTypes(), "$4")).append(");"); - } + if (m.getReturnType() == Void.TYPE) { + c3.append(" w.").append(mn).append('(').append(args(m.getParameterTypes(), "$4")).append(");").append(" return null;"); + } else { + c3.append(" return ($w)w.").append(mn).append('(').append(args(m.getParameterTypes(), "$4")).append(");"); + } - c3.append(" }"); + c3.append(" }"); - mns.add(mn); - if (m.getDeclaringClass() == c) { - dmns.add(mn); + mns.add(mn); + if (m.getDeclaringClass() == c) { + dmns.add(mn); + } + ms.put(ReflectUtils.getDesc(m), m); } - ms.put(ReflectUtils.getDesc(m), m); - } - if (hasMethod) { c3.append(" } catch(Throwable e) { "); c3.append(" throw new java.lang.reflect.InvocationTargetException(e); "); c3.append(" }"); @@ -216,7 +214,7 @@ private static Wrapper makeWrapper(Class c) { Matcher matcher; for (Map.Entry entry : ms.entrySet()) { String md = entry.getKey(); - Method method = (Method) entry.getValue(); + Method method = entry.getValue(); if ((matcher = ReflectUtils.GETTER_METHOD_DESC_PATTERN.matcher(md)).matches()) { String pn = propertyName(matcher.group(1)); c2.append(" if( $2.equals(\"").append(pn).append("\") ){ return ($w)w.").append(method.getName()).append("(); }"); diff --git a/dubbo-common/src/main/java/org/apache/dubbo/common/concurrent/ExecutionList.java b/dubbo-common/src/main/java/org/apache/dubbo/common/concurrent/ExecutionList.java deleted file mode 100644 index c88626cbe6a..00000000000 --- a/dubbo-common/src/main/java/org/apache/dubbo/common/concurrent/ExecutionList.java +++ /dev/null @@ -1,180 +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.common.concurrent; - -import org.apache.dubbo.common.logger.Logger; -import org.apache.dubbo.common.logger.LoggerFactory; -import org.apache.dubbo.common.utils.NamedThreadFactory; - -import java.util.concurrent.Executor; -import java.util.concurrent.SynchronousQueue; -import java.util.concurrent.ThreadPoolExecutor; -import java.util.concurrent.TimeUnit; - -/** - *

A list of listeners, each with an associated {@code Executor}, that - * guarantees that every {@code Runnable} that is {@linkplain #add added} will - * be executed after {@link #execute()} is called. Any {@code Runnable} added - * after the call to {@code execute} is still guaranteed to execute. There is no - * guarantee, however, that listeners will be executed in the order that they - * are added. - *

- *

Exceptions thrown by a listener will be propagated up to the executor. - * Any exception thrown during {@code Executor.execute} (e.g., a {@code - * RejectedExecutionException} or an exception thrown by {@linkplain - * MoreExecutors#sameThreadExecutor inline execution}) will be caught and - * logged. - */ -public final class ExecutionList { - // Logger to log exceptions caught when running runnables. - static final Logger logger = LoggerFactory.getLogger(ExecutionList.class.getName()); - - /** - * The runnable, executor pairs to execute. This acts as a stack threaded through the - * {@link RunnableExecutorPair#next} field. - */ - private RunnableExecutorPair runnables; - - private boolean executed; - - private static final Executor DEFAULT_EXECUTOR = new ThreadPoolExecutor(1, 10, 60000L, TimeUnit.MILLISECONDS, new SynchronousQueue(), new NamedThreadFactory("DubboFutureCallbackDefault", true)); - - /** - * Creates a new, empty {@link ExecutionList}. - */ - public ExecutionList() { - } - - /** - * Adds the {@code Runnable} and accompanying {@code Executor} to the list of - * listeners to execute. If execution has already begun, the listener is - * executed immediately. - *

- *

Note: For fast, lightweight listeners that would be safe to execute in - * any thread, consider {@link MoreExecutors#sameThreadExecutor}. For heavier - * listeners, {@code sameThreadExecutor()} carries some caveats: First, the - * thread that the listener runs in depends on whether the {@code - * ExecutionList} has been executed at the time it is added. In particular, - * listeners may run in the thread that calls {@code add}. Second, the thread - * that calls {@link #execute} may be an internal implementation thread, such - * as an RPC network thread, and {@code sameThreadExecutor()} listeners may - * run in this thread. Finally, during the execution of a {@code - * sameThreadExecutor} listener, all other registered but unexecuted - * listeners are prevented from running, even if those listeners are to run - * in other executors. - */ - public void add(Runnable runnable, Executor executor) { - // Fail fast on a null. We throw NPE here because the contract of - // Executor states that it throws NPE on null listener, so we propagate - // that contract up into the add method as well. - if (runnable == null) { - throw new NullPointerException("Runnable can not be null!"); - } - if (executor == null) { - logger.info("Executor for listenablefuture is null, will use default executor!"); - executor = DEFAULT_EXECUTOR; - } - // Lock while we check state. We must maintain the lock while adding the - // new pair so that another thread can't run the list out from under us. - // We only add to the list if we have not yet started execution. - synchronized (this) { - if (!executed) { - runnables = new RunnableExecutorPair(runnable, executor, runnables); - return; - } - } - // Execute the runnable immediately. Because of scheduling this may end up - // getting called before some of the previously added runnables, but we're - // OK with that. If we want to change the contract to guarantee ordering - // among runnables we'd have to modify the logic here to allow it. - executeListener(runnable, executor); - } - - /** - * Runs this execution list, executing all existing pairs in the order they - * were added. However, note that listeners added after this point may be - * executed before those previously added, and note that the execution order - * of all listeners is ultimately chosen by the implementations of the - * supplied executors. - *

- *

This method is idempotent. Calling it several times in parallel is - * semantically equivalent to calling it exactly once. - * - * @since 10.0 (present in 1.0 as {@code run}) - */ - public void execute() { - // Lock while we update our state so the add method above will finish adding - // any listeners before we start to run them. - RunnableExecutorPair list; - synchronized (this) { - if (executed) { - return; - } - executed = true; - list = runnables; - runnables = null; // allow GC to free listeners even if this stays around for a while. - } - // If we succeeded then list holds all the runnables we to execute. The pairs in the stack are - // in the opposite order from how they were added so we need to reverse the list to fulfill our - // contract. - // This is somewhat annoying, but turns out to be very fast in practice. Alternatively, we - // could drop the contract on the method that enforces this queue like behavior since depending - // on it is likely to be a bug anyway. - - // N.B. All writes to the list and the next pointers must have happened before the above - // synchronized block, so we can iterate the list without the lock held here. - RunnableExecutorPair reversedList = null; - while (list != null) { - RunnableExecutorPair tmp = list; - list = list.next; - tmp.next = reversedList; - reversedList = tmp; - } - while (reversedList != null) { - executeListener(reversedList.runnable, reversedList.executor); - reversedList = reversedList.next; - } - } - - /** - * Submits the given runnable to the given {@link Executor} catching and logging all - * {@linkplain RuntimeException runtime exceptions} thrown by the executor. - */ - private static void executeListener(Runnable runnable, Executor executor) { - try { - executor.execute(runnable); - } catch (RuntimeException e) { - // Log it and keep going, bad runnable and/or executor. Don't - // punish the other runnables if we're given a bad one. We only - // catch RuntimeException because we want Errors to propagate up. - logger.error("RuntimeException while executing runnable " - + runnable + " with executor " + executor, e); - } - } - - private static final class RunnableExecutorPair { - final Runnable runnable; - final Executor executor; - RunnableExecutorPair next; - - RunnableExecutorPair(Runnable runnable, Executor executor, RunnableExecutorPair next) { - this.runnable = runnable; - this.executor = executor; - this.next = next; - } - } -} diff --git a/dubbo-common/src/main/java/org/apache/dubbo/common/config/ConfigurationUtils.java b/dubbo-common/src/main/java/org/apache/dubbo/common/config/ConfigurationUtils.java index a69a6cfae6d..572296c18d0 100644 --- a/dubbo-common/src/main/java/org/apache/dubbo/common/config/ConfigurationUtils.java +++ b/dubbo-common/src/main/java/org/apache/dubbo/common/config/ConfigurationUtils.java @@ -17,11 +17,22 @@ package org.apache.dubbo.common.config; import org.apache.dubbo.common.Constants; +import org.apache.dubbo.common.logger.Logger; +import org.apache.dubbo.common.logger.LoggerFactory; +import org.apache.dubbo.common.utils.StringUtils; + +import java.io.IOException; +import java.io.StringReader; +import java.util.HashMap; +import java.util.Map; +import java.util.Properties; /** * Utilities for manipulating configurations from different sources */ public class ConfigurationUtils { + private static final Logger logger = LoggerFactory.getLogger(ConfigurationUtils.class); + // FIXME @SuppressWarnings("deprecation") public static int getServerShutdownTimeout() { @@ -56,4 +67,18 @@ public static String getProperty(String property, String defaultValue) { return Environment.getInstance().getConfiguration().getString(property, defaultValue); } + public static Map parseProperties(String content) throws IOException { + Map map = new HashMap<>(); + if (StringUtils.isEmpty(content)) { + logger.warn("You specified the config centre, but there's not even one single config item in it."); + } else { + Properties properties = new Properties(); + properties.load(new StringReader(content)); + properties.stringPropertyNames().forEach( + k -> map.put(k, properties.getProperty(k)) + ); + } + return map; + } + } diff --git a/dubbo-common/src/main/java/org/apache/dubbo/common/config/Environment.java b/dubbo-common/src/main/java/org/apache/dubbo/common/config/Environment.java index 4526fbca659..8369b997a49 100644 --- a/dubbo-common/src/main/java/org/apache/dubbo/common/config/Environment.java +++ b/dubbo-common/src/main/java/org/apache/dubbo/common/config/Environment.java @@ -163,10 +163,12 @@ public void setDynamicConfiguration(Configuration dynamicConfiguration) { // For test public void clearExternalConfigs() { this.externalConfigs.clear(); + this.externalConfigurationMap.clear(); } // For test public void clearAppExternalConfigs() { this.appExternalConfigs.clear(); + this.appExternalConfigurationMap.clear(); } } diff --git a/dubbo-common/src/main/java/org/apache/dubbo/common/extension/ExtensionLoader.java b/dubbo-common/src/main/java/org/apache/dubbo/common/extension/ExtensionLoader.java index 42fa01bb25f..aa32b8f0fbb 100644 --- a/dubbo-common/src/main/java/org/apache/dubbo/common/extension/ExtensionLoader.java +++ b/dubbo-common/src/main/java/org/apache/dubbo/common/extension/ExtensionLoader.java @@ -110,10 +110,10 @@ public static ExtensionLoader getExtensionLoader(Class type) { throw new IllegalArgumentException("Extension type == null"); } if (!type.isInterface()) { - throw new IllegalArgumentException("Extension type(" + type + ") is not interface!"); + throw new IllegalArgumentException("Extension type (" + type + ") is not interface!"); } if (!withExtensionAnnotation(type)) { - throw new IllegalArgumentException("Extension type(" + type + + throw new IllegalArgumentException("Extension type (" + type + ") is not extension, because WITHOUT @" + SPI.class.getSimpleName() + " Annotation!"); } @@ -354,8 +354,7 @@ public T getExtension(String name) { */ public T getDefaultExtension() { getExtensionClasses(); - if (null == cachedDefaultName || cachedDefaultName.length() == 0 - || "true".equals(cachedDefaultName)) { + if (StringUtils.isBlank(cachedDefaultName) || "true".equals(cachedDefaultName)) { return null; } return getExtension(cachedDefaultName); @@ -394,11 +393,11 @@ public void addExtension(String name, Class clazz) { if (!type.isAssignableFrom(clazz)) { throw new IllegalStateException("Input type " + - clazz + "not implement Extension " + type); + clazz + " doesn't implement the Extension " + type); } if (clazz.isInterface()) { throw new IllegalStateException("Input type " + - clazz + "can not be interface!"); + clazz + " can't be interface!"); } if (!clazz.isAnnotationPresent(Adaptive.class)) { @@ -407,14 +406,14 @@ public void addExtension(String name, Class clazz) { } if (cachedClasses.get().containsKey(name)) { throw new IllegalStateException("Extension name " + - name + " already existed(Extension " + type + ")!"); + name + " already exists (Extension " + type + ")!"); } cachedNames.put(clazz, name); cachedClasses.get().put(name, clazz); } else { if (cachedAdaptiveClass != null) { - throw new IllegalStateException("Adaptive Extension already existed(Extension " + type + ")!"); + throw new IllegalStateException("Adaptive Extension already exists (Extension " + type + ")!"); } cachedAdaptiveClass = clazz; @@ -435,11 +434,11 @@ public void replaceExtension(String name, Class clazz) { if (!type.isAssignableFrom(clazz)) { throw new IllegalStateException("Input type " + - clazz + "not implement Extension " + type); + clazz + " doesn't implement Extension " + type); } if (clazz.isInterface()) { throw new IllegalStateException("Input type " + - clazz + "can not be interface!"); + clazz + " can't be interface!"); } if (!clazz.isAnnotationPresent(Adaptive.class)) { @@ -448,7 +447,7 @@ public void replaceExtension(String name, Class clazz) { } if (!cachedClasses.get().containsKey(name)) { throw new IllegalStateException("Extension name " + - name + " not existed(Extension " + type + ")!"); + name + " doesn't exist (Extension " + type + ")!"); } cachedNames.put(clazz, name); @@ -456,7 +455,7 @@ public void replaceExtension(String name, Class clazz) { cachedInstances.remove(name); } else { if (cachedAdaptiveClass == null) { - throw new IllegalStateException("Adaptive Extension not existed(Extension " + type + ")!"); + throw new IllegalStateException("Adaptive Extension doesn't exist (Extension " + type + ")!"); } cachedAdaptiveClass = clazz; @@ -477,12 +476,12 @@ public T getAdaptiveExtension() { cachedAdaptiveInstance.set(instance); } catch (Throwable t) { createAdaptiveInstanceError = t; - throw new IllegalStateException("fail to create adaptive instance: " + t.toString(), t); + throw new IllegalStateException("Failed to create adaptive instance: " + t.toString(), t); } } } } else { - throw new IllegalStateException("fail to create adaptive instance: " + createAdaptiveInstanceError.toString(), createAdaptiveInstanceError); + throw new IllegalStateException("Failed to create adaptive instance: " + createAdaptiveInstanceError.toString(), createAdaptiveInstanceError); } } @@ -535,8 +534,8 @@ private T createExtension(String name) { } return instance; } catch (Throwable t) { - throw new IllegalStateException("Extension instance(name: " + name + ", class: " + - type + ") could not be instantiated: " + t.getMessage(), t); + throw new IllegalStateException("Extension instance (name: " + name + ", class: " + + type + ") couldn't be instantiated: " + t.getMessage(), t); } } @@ -564,7 +563,7 @@ private T injectExtension(T instance) { method.invoke(instance, object); } } catch (Exception e) { - logger.error("fail to inject via method " + method.getName() + logger.error("Failed to inject via method " + method.getName() + " of interface " + type.getName() + ": " + e.getMessage(), e); } } @@ -608,7 +607,7 @@ private Map> loadExtensionClasses() { if ((value = value.trim()).length() > 0) { String[] names = NAME_SEPARATOR.split(value); if (names.length > 1) { - throw new IllegalStateException("more than 1 default extension name on extension " + type.getName() + throw new IllegalStateException("More than 1 default extension name on extension " + type.getName() + ": " + Arrays.toString(names)); } if (names.length == 1) { @@ -644,7 +643,7 @@ private void loadDirectory(Map> extensionClasses, String dir, S } } } catch (Throwable t) { - logger.error("Exception when load extension class(interface: " + + logger.error("Exception occurred when loading extension class (interface: " + type + ", description file: " + fileName + ").", t); } } @@ -672,7 +671,7 @@ private void loadResource(Map> extensionClasses, ClassLoader cl loadClass(extensionClasses, resourceURL, Class.forName(line, true, classLoader), name); } } catch (Throwable t) { - IllegalStateException e = new IllegalStateException("Failed to load extension class(interface: " + type + ", class line: " + line + ") in " + resourceURL + ", cause: " + t.getMessage(), t); + IllegalStateException e = new IllegalStateException("Failed to load extension class (interface: " + type + ", class line: " + line + ") in " + resourceURL + ", cause: " + t.getMessage(), t); exceptions.put(line, e); } } @@ -681,16 +680,16 @@ private void loadResource(Map> extensionClasses, ClassLoader cl reader.close(); } } catch (Throwable t) { - logger.error("Exception when load extension class(interface: " + + logger.error("Exception occurred when loading extension class (interface: " + type + ", class file: " + resourceURL + ") in " + resourceURL, t); } } private void loadClass(Map> extensionClasses, java.net.URL resourceURL, Class clazz, String name) throws NoSuchMethodException { if (!type.isAssignableFrom(clazz)) { - throw new IllegalStateException("Error when load extension class(interface: " + + throw new IllegalStateException("Error occurred when loading extension class (interface: " + type + ", class line: " + clazz.getName() + "), class " - + clazz.getName() + "is not subtype of interface."); + + clazz.getName() + " is not subtype of interface."); } if (clazz.isAnnotationPresent(Adaptive.class)) { if (cachedAdaptiveClass == null) { @@ -703,7 +702,7 @@ private void loadClass(Map> extensionClasses, java.net.URL reso } else if (isWrapperClass(clazz)) { Set> wrappers = cachedWrapperClasses; if (wrappers == null) { - cachedWrapperClasses = new ConcurrentHashSet>(); + cachedWrapperClasses = new ConcurrentHashSet<>(); wrappers = cachedWrapperClasses; } wrappers.add(clazz); @@ -769,7 +768,7 @@ private T createAdaptiveExtension() { try { return injectExtension((T) getAdaptiveExtensionClass().newInstance()); } catch (Exception e) { - throw new IllegalStateException("Can not create adaptive extension " + type + ", cause: " + e.getMessage(), e); + throw new IllegalStateException("Can't create adaptive extension " + type + ", cause: " + e.getMessage(), e); } } @@ -800,7 +799,7 @@ private String createAdaptiveExtensionClassCode() { } // no need to generate adaptive class since there's no adaptive method found. if (!hasAdaptiveAnnotation) { - throw new IllegalStateException("No adaptive method on extension " + type.getName() + ", refuse to create the adaptive class!"); + throw new IllegalStateException("No adaptive method exist on extension " + type.getName() + ", refuse to create the adaptive class!"); } codeBuilder.append("package ").append(type.getPackage().getName()).append(";"); @@ -815,7 +814,7 @@ private String createAdaptiveExtensionClassCode() { Adaptive adaptiveAnnotation = method.getAnnotation(Adaptive.class); StringBuilder code = new StringBuilder(512); if (adaptiveAnnotation == null) { - code.append("throw new UnsupportedOperationException(\"method ") + code.append("throw new UnsupportedOperationException(\"The method ") .append(method.toString()).append(" of interface ") .append(type.getName()).append(" is not adaptive method!\");"); } else { @@ -858,7 +857,7 @@ private String createAdaptiveExtensionClassCode() { } } if (attribMethod == null) { - throw new IllegalStateException("fail to create adaptive class for interface " + type.getName() + throw new IllegalStateException("Failed to create adaptive class for interface " + type.getName() + ": not found url parameter or url attribute in parameters of method " + method.getName()); } @@ -934,7 +933,7 @@ private String createAdaptiveExtensionClassCode() { code.append("\nString extName = ").append(getNameCode).append(";"); // check extName == null? String s = String.format("\nif(extName == null) " + - "throw new IllegalStateException(\"Fail to get extension(%s) name from url(\" + url.toString() + \") use keys(%s)\");", + "throw new IllegalStateException(\"Failed to get extension (%s) name from url (\" + url.toString() + \") use keys(%s)\");", type.getName(), Arrays.toString(value)); code.append(s); diff --git a/dubbo-common/src/main/java/org/apache/dubbo/common/logger/LoggerFactory.java b/dubbo-common/src/main/java/org/apache/dubbo/common/logger/LoggerFactory.java index ec98755000b..41d1632eacc 100644 --- a/dubbo-common/src/main/java/org/apache/dubbo/common/logger/LoggerFactory.java +++ b/dubbo-common/src/main/java/org/apache/dubbo/common/logger/LoggerFactory.java @@ -25,6 +25,8 @@ import org.apache.dubbo.common.logger.support.FailsafeLogger; import java.io.File; +import java.util.Arrays; +import java.util.List; import java.util.Map; import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.ConcurrentMap; @@ -34,40 +36,43 @@ */ public class LoggerFactory { - private static final ConcurrentMap LOGGERS = new ConcurrentHashMap(); + private static final ConcurrentMap LOGGERS = new ConcurrentHashMap<>(); private static volatile LoggerAdapter LOGGER_ADAPTER; // search common-used logging frameworks static { - String logger = System.getProperty("dubbo.application.logger"); - if ("slf4j".equals(logger)) { - setLoggerAdapter(new Slf4jLoggerAdapter()); - } else if ("jcl".equals(logger)) { - setLoggerAdapter(new JclLoggerAdapter()); - } else if ("log4j".equals(logger)) { - setLoggerAdapter(new Log4jLoggerAdapter()); - } else if ("jdk".equals(logger)) { - setLoggerAdapter(new JdkLoggerAdapter()); - } else if ("log4j2".equals(logger)) { - setLoggerAdapter(new Log4j2LoggerAdapter()); - } else { - try { + String logger = System.getProperty("dubbo.application.logger", ""); + switch (logger) { + case "slf4j": + setLoggerAdapter(new Slf4jLoggerAdapter()); + break; + case "jcl": + setLoggerAdapter(new JclLoggerAdapter()); + break; + case "log4j": setLoggerAdapter(new Log4jLoggerAdapter()); - } catch (Throwable e1) { - try { - setLoggerAdapter(new Slf4jLoggerAdapter()); - } catch (Throwable e2) { + break; + case "jdk": + setLoggerAdapter(new JdkLoggerAdapter()); + break; + case "log4j2": + setLoggerAdapter(new Log4j2LoggerAdapter()); + break; + default: + List> candidates = Arrays.asList( + Log4jLoggerAdapter.class, + Slf4jLoggerAdapter.class, + Log4j2LoggerAdapter.class, + JclLoggerAdapter.class, + JdkLoggerAdapter.class + ); + for (Class clazz : candidates) { try { - setLoggerAdapter(new Log4j2LoggerAdapter()); - } catch (Throwable e3) { - try { - setLoggerAdapter(new JclLoggerAdapter()); - } catch (Throwable e4) { - setLoggerAdapter(new JdkLoggerAdapter()); - } + setLoggerAdapter(clazz.newInstance()); + break; + } catch (Throwable ignored) { } } - } } } @@ -103,12 +108,7 @@ public static void setLoggerAdapter(LoggerAdapter loggerAdapter) { * @return logger */ public static Logger getLogger(Class key) { - FailsafeLogger logger = LOGGERS.get(key.getName()); - if (logger == null) { - LOGGERS.putIfAbsent(key.getName(), new FailsafeLogger(LOGGER_ADAPTER.getLogger(key))); - logger = LOGGERS.get(key.getName()); - } - return logger; + return LOGGERS.computeIfAbsent(key.getName(), name -> new FailsafeLogger(LOGGER_ADAPTER.getLogger(name))); } /** @@ -118,12 +118,7 @@ public static Logger getLogger(Class key) { * @return logger provider */ public static Logger getLogger(String key) { - FailsafeLogger logger = LOGGERS.get(key); - if (logger == null) { - LOGGERS.putIfAbsent(key, new FailsafeLogger(LOGGER_ADAPTER.getLogger(key))); - logger = LOGGERS.get(key); - } - return logger; + return LOGGERS.computeIfAbsent(key, k -> new FailsafeLogger(LOGGER_ADAPTER.getLogger(k))); } /** @@ -153,4 +148,4 @@ public static File getFile() { return LOGGER_ADAPTER.getFile(); } -} \ No newline at end of file +} diff --git a/dubbo-common/src/main/java/org/apache/dubbo/common/time/DateParser.java b/dubbo-common/src/main/java/org/apache/dubbo/common/time/DateParser.java deleted file mode 100644 index 36b6b0c2c39..00000000000 --- a/dubbo-common/src/main/java/org/apache/dubbo/common/time/DateParser.java +++ /dev/null @@ -1,120 +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.common.time; - -import java.text.ParseException; -import java.text.ParsePosition; -import java.util.Calendar; -import java.util.Date; -import java.util.Locale; -import java.util.TimeZone; - -/** - * DateParser interface - */ -public interface DateParser { - - /** - * Equivalent to DateFormat.parse(String). - * - * See {@link java.text.DateFormat#parse(String)} for more information. - * @param source A String whose beginning should be parsed. - * @return A Date parsed from the string - * @throws ParseException if the beginning of the specified string cannot be parsed. - */ - Date parse(String source) throws ParseException; - - /** - * Equivalent to DateFormat.parse(String, ParsePosition). - * - * See {@link java.text.DateFormat#parse(String, ParsePosition)} for more information. - * - * @param source A String, part of which should be parsed. - * @param pos A ParsePosition object with index and error index information - * as described above. - * @return A Date parsed from the string. In case of error, returns null. - * @throws NullPointerException if text or pos is null. - */ - Date parse(String source, ParsePosition pos); - - /** - * Parses a formatted date string according to the format. Updates the Calendar with parsed fields. - * Upon success, the ParsePosition index is updated to indicate how much of the source text was consumed. - * Not all source text needs to be consumed. Upon parse failure, ParsePosition error index is updated to - * the offset of the source text which does not match the supplied format. - * - * @param source The text to parse. - * @param pos On input, the position in the source to start parsing, on output, updated position. - * @param calendar The calendar into which to set parsed fields. - * @return true, if source has been parsed (pos parsePosition is updated); otherwise false (and pos errorIndex is updated) - * @throws IllegalArgumentException when Calendar has been set to be not lenient, and a parsed field is - * out of range. - * - * @since 3.5 - */ - boolean parse(String source, ParsePosition pos, Calendar calendar); - - // Accessors - //----------------------------------------------------------------------- - /** - *

Gets the pattern used by this parser.

- * - * @return the pattern, {@link java.text.SimpleDateFormat} compatible - */ - String getPattern(); - - /** - *

- * Gets the time zone used by this parser. - *

- * - *

- * The default {@link TimeZone} used to create a {@link Date} when the {@link TimeZone} is not specified by - * the format pattern. - *

- * - * @return the time zone - */ - TimeZone getTimeZone(); - - /** - *

Gets the locale used by this parser.

- * - * @return the locale - */ - Locale getLocale(); - - /** - * Parses text from a string to produce a Date. - * - * @param source A String whose beginning should be parsed. - * @return a java.util.Date object - * @throws ParseException if the beginning of the specified string cannot be parsed. - * @see java.text.DateFormat#parseObject(String) - */ - Object parseObject(String source) throws ParseException; - - /** - * Parses a date/time string according to the given parse position. - * - * @param source A String whose beginning should be parsed. - * @param pos the parse position - * @return a java.util.Date object - * @see java.text.DateFormat#parseObject(String, ParsePosition) - */ - Object parseObject(String source, ParsePosition pos); -} \ No newline at end of file diff --git a/dubbo-common/src/main/java/org/apache/dubbo/common/time/DatePrinter.java b/dubbo-common/src/main/java/org/apache/dubbo/common/time/DatePrinter.java deleted file mode 100644 index 8b3b5e4645c..00000000000 --- a/dubbo-common/src/main/java/org/apache/dubbo/common/time/DatePrinter.java +++ /dev/null @@ -1,171 +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.common.time; - -import java.text.FieldPosition; -import java.util.Calendar; -import java.util.Date; -import java.util.Locale; -import java.util.TimeZone; - -/** - * DatePrinter interface - */ -public interface DatePrinter { - - /** - *

Formats a millisecond {@code long} value.

- * - * @param millis the millisecond value to format - * @return the formatted string - * @since 2.1 - */ - String format(long millis); - - /** - *

Formats a {@code Date} object using a {@code GregorianCalendar}.

- * - * @param date the date to format - * @return the formatted string - */ - String format(Date date); - - /** - *

Formats a {@code Calendar} object.

- * The TimeZone set on the Calendar is only used to adjust the time offset. - * The TimeZone specified during the construction of the Parser will determine the TimeZone - * used in the formatted string. - * - * @param calendar the calendar to format. - * @return the formatted string - */ - String format(Calendar calendar); - - /** - *

Formats a millisecond {@code long} value into the - * supplied {@code StringBuffer}.

- * - * @param millis the millisecond value to format - * @param buf the buffer to format into - * @return the specified string buffer - * @deprecated Use {{@link #format(long, Appendable)}. - */ - @Deprecated - StringBuffer format(long millis, StringBuffer buf); - - /** - *

Formats a {@code Date} object into the - * supplied {@code StringBuffer} using a {@code GregorianCalendar}.

- * - * @param date the date to format - * @param buf the buffer to format into - * @return the specified string buffer - * @deprecated Use {{@link #format(Date, Appendable)}. - */ - @Deprecated - StringBuffer format(Date date, StringBuffer buf); - - /** - *

Formats a {@code Calendar} object into the supplied {@code StringBuffer}.

- * The TimeZone set on the Calendar is only used to adjust the time offset. - * The TimeZone specified during the construction of the Parser will determine the TimeZone - * used in the formatted string. - * - * @param calendar the calendar to format - * @param buf the buffer to format into - * @return the specified string buffer - * @deprecated Use {{@link #format(Calendar, Appendable)}. - */ - @Deprecated - StringBuffer format(Calendar calendar, StringBuffer buf); - - /** - *

Formats a millisecond {@code long} value into the - * supplied {@code Appendable}.

- * - * @param millis the millisecond value to format - * @param buf the buffer to format into - * @param the Appendable class type, usually StringBuilder or StringBuffer. - * @return the specified string buffer - * @since 3.5 - */ - B format(long millis, B buf); - - /** - *

Formats a {@code Date} object into the - * supplied {@code Appendable} using a {@code GregorianCalendar}.

- * - * @param date the date to format - * @param buf the buffer to format into - * @param the Appendable class type, usually StringBuilder or StringBuffer. - * @return the specified string buffer - * @since 3.5 - */ - B format(Date date, B buf); - - /** - *

Formats a {@code Calendar} object into the supplied {@code Appendable}.

- * The TimeZone set on the Calendar is only used to adjust the time offset. - * The TimeZone specified during the construction of the Parser will determine the TimeZone - * used in the formatted string. - * - * @param calendar the calendar to format - * @param buf the buffer to format into - * @param the Appendable class type, usually StringBuilder or StringBuffer. - * @return the specified string buffer - * @since 3.5 - */ - B format(Calendar calendar, B buf); - - - // Accessors - //----------------------------------------------------------------------- - /** - *

Gets the pattern used by this printer.

- * - * @return the pattern, {@link java.text.SimpleDateFormat} compatible - */ - String getPattern(); - - /** - *

Gets the time zone used by this printer.

- * - *

This zone is always used for {@code Date} printing.

- * - * @return the time zone - */ - TimeZone getTimeZone(); - - /** - *

Gets the locale used by this printer.

- * - * @return the locale - */ - Locale getLocale(); - - /** - *

Formats a {@code Date}, {@code Calendar} or - * {@code Long} (milliseconds) object.

- * - * @param obj the object to format - * @param toAppendTo the buffer to append to - * @param pos the position - ignored - * @return the buffer passed in - * @see java.text.DateFormat#format(Object, StringBuffer, FieldPosition) - */ - StringBuffer format(Object obj, StringBuffer toAppendTo, FieldPosition pos); -} \ No newline at end of file diff --git a/dubbo-common/src/main/java/org/apache/dubbo/common/time/FastDateFormat.java b/dubbo-common/src/main/java/org/apache/dubbo/common/time/FastDateFormat.java deleted file mode 100644 index 99b492d9c49..00000000000 --- a/dubbo-common/src/main/java/org/apache/dubbo/common/time/FastDateFormat.java +++ /dev/null @@ -1,380 +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.common.time; - -import java.text.FieldPosition; -import java.text.Format; -import java.text.ParseException; -import java.text.ParsePosition; -import java.util.Calendar; -import java.util.Date; -import java.util.Locale; -import java.util.TimeZone; - -/** - * FastDateFormat - */ -public class FastDateFormat extends Format implements DateParser, DatePrinter { - - /** - * Required for serialization support. - * - * @see java.io.Serializable - */ - private static final long serialVersionUID = 2L; - - private static final FormatCache cache= new FormatCache() { - @Override - protected FastDateFormat createInstance(final String pattern, final TimeZone timeZone, final Locale locale) { - return new FastDateFormat(pattern, timeZone, locale); - } - }; - - private final FastDatePrinter printer; - private final FastDateParser parser; - - //----------------------------------------------------------------------- - /** - *

Gets a formatter instance using the default pattern in the - * default locale.

- * - * @return a date/time formatter - */ - public static FastDateFormat getInstance() { - return cache.getInstance(); - } - - /** - *

Gets a formatter instance using the specified pattern in the - * default locale.

- * - * @param pattern {@link java.text.SimpleDateFormat} compatible - * pattern - * @return a pattern based date/time formatter - * @throws IllegalArgumentException if pattern is invalid - */ - public static FastDateFormat getInstance(final String pattern) { - return cache.getInstance(pattern, null, null); - } - - - // Constructor - //----------------------------------------------------------------------- - /** - *

Constructs a new FastDateFormat.

- * - * @param pattern {@link java.text.SimpleDateFormat} compatible pattern - * @param timeZone non-null time zone to use - * @param locale non-null locale to use - * @throws NullPointerException if pattern, timeZone, or locale is null. - */ - protected FastDateFormat(final String pattern, final TimeZone timeZone, final Locale locale) { - this(pattern, timeZone, locale, null); - } - - // Constructor - //----------------------------------------------------------------------- - /** - *

Constructs a new FastDateFormat.

- * - * @param pattern {@link java.text.SimpleDateFormat} compatible pattern - * @param timeZone non-null time zone to use - * @param locale non-null locale to use - * @param centuryStart The start of the 100 year period to use as the "default century" for 2 digit year parsing. If centuryStart is null, defaults to now - 80 years - * @throws NullPointerException if pattern, timeZone, or locale is null. - */ - protected FastDateFormat(final String pattern, final TimeZone timeZone, final Locale locale, final Date centuryStart) { - printer= new FastDatePrinter(pattern, timeZone, locale); - parser= new FastDateParser(pattern, timeZone, locale, centuryStart); - } - - // Format methods - //----------------------------------------------------------------------- - /** - *

Formats a {@code Date}, {@code Calendar} or - * {@code Long} (milliseconds) object.

- * This method is an implementation of {@link Format#format(Object, StringBuffer, FieldPosition)} - * - * @param obj the object to format - * @param toAppendTo the buffer to append to - * @param pos the position - ignored - * @return the buffer passed in - */ - @Override - public StringBuffer format(final Object obj, final StringBuffer toAppendTo, final FieldPosition pos) { - return toAppendTo.append(printer.format(obj)); - } - - /** - *

Formats a millisecond {@code long} value.

- * - * @param millis the millisecond value to format - * @return the formatted string - * @since 2.1 - */ - @Override - public String format(final long millis) { - return printer.format(millis); - } - - /** - *

Formats a {@code Date} object using a {@code GregorianCalendar}.

- * - * @param date the date to format - * @return the formatted string - */ - @Override - public String format(final Date date) { - return printer.format(date); - } - - /** - *

Formats a {@code Calendar} object.

- * - * @param calendar the calendar to format - * @return the formatted string - */ - @Override - public String format(final Calendar calendar) { - return printer.format(calendar); - } - - /** - *

Formats a millisecond {@code long} value into the - * supplied {@code StringBuffer}.

- * - * @param millis the millisecond value to format - * @param buf the buffer to format into - * @return the specified string buffer - * @since 2.1 - * @deprecated Use {{@link #format(long, Appendable)}. - */ - @Deprecated - @Override - public StringBuffer format(final long millis, final StringBuffer buf) { - return printer.format(millis, buf); - } - - /** - *

Formats a {@code Date} object into the - * supplied {@code StringBuffer} using a {@code GregorianCalendar}.

- * - * @param date the date to format - * @param buf the buffer to format into - * @return the specified string buffer - * @deprecated Use {{@link #format(Date, Appendable)}. - */ - @Deprecated - @Override - public StringBuffer format(final Date date, final StringBuffer buf) { - return printer.format(date, buf); - } - - /** - *

Formats a {@code Calendar} object into the - * supplied {@code StringBuffer}.

- * - * @param calendar the calendar to format - * @param buf the buffer to format into - * @return the specified string buffer - * @deprecated Use {{@link #format(Calendar, Appendable)}. - */ - @Deprecated - @Override - public StringBuffer format(final Calendar calendar, final StringBuffer buf) { - return printer.format(calendar, buf); - } - - /** - *

Formats a millisecond {@code long} value into the - * supplied {@code StringBuffer}.

- * - * @param millis the millisecond value to format - * @param buf the buffer to format into - * @return the specified string buffer - * @since 3.5 - */ - @Override - public B format(final long millis, final B buf) { - return printer.format(millis, buf); - } - - /** - *

Formats a {@code Date} object into the - * supplied {@code StringBuffer} using a {@code GregorianCalendar}.

- * - * @param date the date to format - * @param buf the buffer to format into - * @return the specified string buffer - * @since 3.5 - */ - @Override - public B format(final Date date, final B buf) { - return printer.format(date, buf); - } - - /** - *

Formats a {@code Calendar} object into the - * supplied {@code StringBuffer}.

- * - * @param calendar the calendar to format - * @param buf the buffer to format into - * @return the specified string buffer - * @since 3.5 - */ - @Override - public B format(final Calendar calendar, final B buf) { - return printer.format(calendar, buf); - } - - // Parsing - //----------------------------------------------------------------------- - - - /* (non-Javadoc) - * @see DateParser#parse(java.lang.String) - */ - @Override - public Date parse(final String source) throws ParseException { - return parser.parse(source); - } - - /* (non-Javadoc) - * @see DateParser#parse(java.lang.String, java.text.ParsePosition) - */ - @Override - public Date parse(final String source, final ParsePosition pos) { - return parser.parse(source, pos); - } - - /* - * (non-Javadoc) - * @see org.apache.commons.lang3.time.DateParser#parse(java.lang.String, java.text.ParsePosition, java.util.Calendar) - */ - @Override - public boolean parse(final String source, final ParsePosition pos, final Calendar calendar) { - return parser.parse(source, pos, calendar); - } - - /* (non-Javadoc) - * @see java.text.Format#parseObject(java.lang.String, java.text.ParsePosition) - */ - @Override - public Object parseObject(final String source, final ParsePosition pos) { - return parser.parseObject(source, pos); - } - - // Accessors - //----------------------------------------------------------------------- - /** - *

Gets the pattern used by this formatter.

- * - * @return the pattern, {@link java.text.SimpleDateFormat} compatible - */ - @Override - public String getPattern() { - return printer.getPattern(); - } - - /** - *

Gets the time zone used by this formatter.

- * - *

This zone is always used for {@code Date} formatting.

- * - * @return the time zone - */ - @Override - public TimeZone getTimeZone() { - return printer.getTimeZone(); - } - - /** - *

Gets the locale used by this formatter.

- * - * @return the locale - */ - @Override - public Locale getLocale() { - return printer.getLocale(); - } - - /** - *

Gets an estimate for the maximum string length that the - * formatter will produce.

- * - *

The actual formatted length will almost always be less than or - * equal to this amount.

- * - * @return the maximum formatted length - */ - public int getMaxLengthEstimate() { - return printer.getMaxLengthEstimate(); - } - - // Basics - //----------------------------------------------------------------------- - /** - *

Compares two objects for equality.

- * - * @param obj the object to compare to - * @return {@code true} if equal - */ - @Override - public boolean equals(final Object obj) { - if (!(obj instanceof FastDateFormat)) { - return false; - } - final FastDateFormat other = (FastDateFormat) obj; - // no need to check parser, as it has same invariants as printer - return printer.equals(other.printer); - } - - /** - *

Returns a hash code compatible with equals.

- * - * @return a hash code compatible with equals - */ - @Override - public int hashCode() { - return printer.hashCode(); - } - - /** - *

Gets a debugging string version of this formatter.

- * - * @return a debugging string - */ - @Override - public String toString() { - return "FastDateFormat[" + printer.getPattern() + "," + printer.getLocale() + "," + printer.getTimeZone().getID() + "]"; - } - - /** - *

Performs the formatting by applying the rules to the - * specified calendar.

- * - * @param calendar the calendar to format - * @param buf the buffer to format into - * @return the specified string buffer - * @deprecated Use {@link #format(Calendar, Appendable)} - */ - @Deprecated - protected StringBuffer applyRules(final Calendar calendar, final StringBuffer buf) { - return printer.applyRules(calendar, buf); - } -} diff --git a/dubbo-common/src/main/java/org/apache/dubbo/common/time/FastDateParser.java b/dubbo-common/src/main/java/org/apache/dubbo/common/time/FastDateParser.java deleted file mode 100644 index 62a64f8d8b4..00000000000 --- a/dubbo-common/src/main/java/org/apache/dubbo/common/time/FastDateParser.java +++ /dev/null @@ -1,954 +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.common.time; - -import java.io.IOException; -import java.io.ObjectInputStream; -import java.io.Serializable; -import java.text.DateFormatSymbols; -import java.text.ParseException; -import java.text.ParsePosition; -import java.util.ArrayList; -import java.util.Calendar; -import java.util.Comparator; -import java.util.Date; -import java.util.HashMap; -import java.util.List; -import java.util.ListIterator; -import java.util.Locale; -import java.util.Map; -import java.util.Set; -import java.util.TimeZone; -import java.util.TreeSet; -import java.util.concurrent.ConcurrentHashMap; -import java.util.concurrent.ConcurrentMap; -import java.util.regex.Matcher; -import java.util.regex.Pattern; - -/** - *

FastDateParser is a fast and thread-safe version of SimpleDateFormat - */ -public class FastDateParser implements DateParser, Serializable { - - /** - * Required for serialization support. - * - * @see java.io.Serializable - */ - private static final long serialVersionUID = 3L; - - static final Locale JAPANESE_IMPERIAL = new Locale("ja", "JP", "JP"); - - // defining fields - private final String pattern; - private final TimeZone timeZone; - private final Locale locale; - private final int century; - private final int startYear; - - // derived fields - private transient List patterns; - - // comparator used to sort regex alternatives - // alternatives should be ordered longer first, and shorter last. ('february' before 'feb') - // all entries must be lowercase by locale. - private static final Comparator LONGER_FIRST_LOWERCASE = new Comparator() { - @Override - public int compare(final String left, final String right) { - return right.compareTo(left); - } - }; - - /** - *

Constructs a new FastDateParser.

- * - * @param pattern non-null {@link java.text.SimpleDateFormat} compatible - * pattern - * @param timeZone non-null time zone to use - * @param locale non-null locale - * @param centuryStart The start of the century for 2 digit year parsing - * - * @since 3.5 - */ - protected FastDateParser(final String pattern, final TimeZone timeZone, final Locale locale, final Date centuryStart) { - this.pattern = pattern; - this.timeZone = timeZone; - this.locale = locale; - - final Calendar definingCalendar = Calendar.getInstance(timeZone, locale); - - int centuryStartYear; - if (centuryStart!=null) { - definingCalendar.setTime(centuryStart); - centuryStartYear= definingCalendar.get(Calendar.YEAR); - } else if (locale.equals(JAPANESE_IMPERIAL)) { - centuryStartYear= 0; - } else { - // from 80 years ago to 20 years from now - definingCalendar.setTime(new Date()); - centuryStartYear= definingCalendar.get(Calendar.YEAR)-80; - } - century= centuryStartYear / 100 * 100; - startYear= centuryStartYear - century; - - init(definingCalendar); - } - - /** - * Initialize derived fields from defining fields. - * This is called from constructor and from readObject (de-serialization) - * - * @param definingCalendar the {@link java.util.Calendar} instance used to initialize this FastDateParser - */ - private void init(final Calendar definingCalendar) { - patterns = new ArrayList<>(); - - final StrategyParser fm = new StrategyParser(definingCalendar); - for (;;) { - final StrategyAndWidth field = fm.getNextStrategy(); - if (field==null) { - break; - } - patterns.add(field); - } - } - - // helper classes to parse the format string - //----------------------------------------------------------------------- - - /** - * Holds strategy and field width - */ - private static class StrategyAndWidth { - final Strategy strategy; - final int width; - - StrategyAndWidth(final Strategy strategy, final int width) { - this.strategy = strategy; - this.width = width; - } - - int getMaxWidth(final ListIterator lt) { - if (!strategy.isNumber() || !lt.hasNext()) { - return 0; - } - final Strategy nextStrategy = lt.next().strategy; - lt.previous(); - return nextStrategy.isNumber() ?width :0; - } - } - - /** - * Parse format into Strategies - */ - private class StrategyParser { - private final Calendar definingCalendar; - private int currentIdx; - - StrategyParser(final Calendar definingCalendar) { - this.definingCalendar = definingCalendar; - } - - StrategyAndWidth getNextStrategy() { - if (currentIdx >= pattern.length()) { - return null; - } - - final char c = pattern.charAt(currentIdx); - if (isFormatLetter(c)) { - return letterPattern(c); - } - return literal(); - } - - private StrategyAndWidth letterPattern(final char c) { - final int begin = currentIdx; - while (++currentIdx < pattern.length()) { - if (pattern.charAt(currentIdx) != c) { - break; - } - } - - final int width = currentIdx - begin; - return new StrategyAndWidth(getStrategy(c, width, definingCalendar), width); - } - - private StrategyAndWidth literal() { - boolean activeQuote = false; - - final StringBuilder sb = new StringBuilder(); - while (currentIdx < pattern.length()) { - final char c = pattern.charAt(currentIdx); - if (!activeQuote && isFormatLetter(c)) { - break; - } else if (c == '\'' && (++currentIdx == pattern.length() || pattern.charAt(currentIdx) != '\'')) { - activeQuote = !activeQuote; - continue; - } - ++currentIdx; - sb.append(c); - } - - if (activeQuote) { - throw new IllegalArgumentException("Unterminated quote"); - } - - final String formatField = sb.toString(); - return new StrategyAndWidth(new CopyQuotedStrategy(formatField), formatField.length()); - } - } - - private static boolean isFormatLetter(final char c) { - return c >= 'A' && c <= 'Z' || c >= 'a' && c <= 'z'; - } - - // Accessors - //----------------------------------------------------------------------- - /* (non-Javadoc) - * @see org.apache.commons.lang3.time.DateParser#getPattern() - */ - @Override - public String getPattern() { - return pattern; - } - - /* (non-Javadoc) - * @see org.apache.commons.lang3.time.DateParser#getTimeZone() - */ - @Override - public TimeZone getTimeZone() { - return timeZone; - } - - /* (non-Javadoc) - * @see org.apache.commons.lang3.time.DateParser#getLocale() - */ - @Override - public Locale getLocale() { - return locale; - } - - - // Basics - //----------------------------------------------------------------------- - /** - *

Compare another object for equality with this object.

- * - * @param obj the object to compare to - * @return trueif equal to this instance - */ - @Override - public boolean equals(final Object obj) { - if (!(obj instanceof FastDateParser)) { - return false; - } - final FastDateParser other = (FastDateParser) obj; - return pattern.equals(other.pattern) - && timeZone.equals(other.timeZone) - && locale.equals(other.locale); - } - - /** - *

Return a hash code compatible with equals.

- * - * @return a hash code compatible with equals - */ - @Override - public int hashCode() { - return pattern.hashCode() + 13 * (timeZone.hashCode() + 13 * locale.hashCode()); - } - - /** - *

Get a string version of this formatter.

- * - * @return a debugging string - */ - @Override - public String toString() { - return "FastDateParser[" + pattern + "," + locale + "," + timeZone.getID() + "]"; - } - - // Serializing - //----------------------------------------------------------------------- - /** - * Create the object after serialization. This implementation reinitializes the - * transient properties. - * - * @param in ObjectInputStream from which the object is being deserialized. - * @throws IOException if there is an IO issue. - * @throws ClassNotFoundException if a class cannot be found. - */ - private void readObject(final ObjectInputStream in) throws IOException, ClassNotFoundException { - in.defaultReadObject(); - - final Calendar definingCalendar = Calendar.getInstance(timeZone, locale); - init(definingCalendar); - } - - /* (non-Javadoc) - * @see org.apache.commons.lang3.time.DateParser#parseObject(java.lang.String) - */ - @Override - public Object parseObject(final String source) throws ParseException { - return parse(source); - } - - /* (non-Javadoc) - * @see org.apache.commons.lang3.time.DateParser#parse(java.lang.String) - */ - @Override - public Date parse(final String source) throws ParseException { - final ParsePosition pp = new ParsePosition(0); - final Date date= parse(source, pp); - if (date == null) { - // Add a note re supported date range - if (locale.equals(JAPANESE_IMPERIAL)) { - throw new ParseException( - "(The " +locale + " locale does not support dates before 1868 AD)\n" + - "Unparseable date: \""+source, pp.getErrorIndex()); - } - throw new ParseException("Unparseable date: "+source, pp.getErrorIndex()); - } - return date; - } - - /* (non-Javadoc) - * @see org.apache.commons.lang3.time.DateParser#parseObject(java.lang.String, java.text.ParsePosition) - */ - @Override - public Object parseObject(final String source, final ParsePosition pos) { - return parse(source, pos); - } - - /** - * This implementation updates the ParsePosition if the parse succeeds. - * However, it sets the error index to the position before the failed field unlike - * the method {@link java.text.SimpleDateFormat#parse(String, ParsePosition)} which sets - * the error index to after the failed field. - *

- * To determine if the parse has succeeded, the caller must check if the current parse position - * given by {@link ParsePosition#getIndex()} has been updated. If the input buffer has been fully - * parsed, then the index will point to just after the end of the input buffer. - */ - @Override - public Date parse(final String source, final ParsePosition pos) { - // timing tests indicate getting new instance is 19% faster than cloning - final Calendar cal= Calendar.getInstance(timeZone, locale); - cal.clear(); - - return parse(source, pos, cal) ? cal.getTime() : null; - } - - /** - * Parse a formatted date string according to the format. Updates the Calendar with parsed fields. - * Upon success, the ParsePosition index is updated to indicate how much of the source text was consumed. - * Not all source text needs to be consumed. Upon parse failure, ParsePosition error index is updated to - * the offset of the source text which does not match the supplied format. - * - * @param source The text to parse. - * @param pos On input, the position in the source to start parsing, on output, updated position. - * @param calendar The calendar into which to set parsed fields. - * @return true, if source has been parsed (pos parsePosition is updated); otherwise false (and pos errorIndex is updated) - * @throws IllegalArgumentException when Calendar has been set to be not lenient, and a parsed field is - * out of range. - */ - @Override - public boolean parse(final String source, final ParsePosition pos, final Calendar calendar) { - final ListIterator lt = patterns.listIterator(); - while (lt.hasNext()) { - final StrategyAndWidth strategyAndWidth = lt.next(); - final int maxWidth = strategyAndWidth.getMaxWidth(lt); - if (!strategyAndWidth.strategy.parse(this, calendar, source, pos, maxWidth)) { - return false; - } - } - return true; - } - - // Support for strategies - //----------------------------------------------------------------------- - - private static StringBuilder simpleQuote(final StringBuilder sb, final String value) { - for (int i = 0; i < value.length(); ++i) { - final char c = value.charAt(i); - switch (c) { - case '\\': - case '^': - case '$': - case '.': - case '|': - case '?': - case '*': - case '+': - case '(': - case ')': - case '[': - case '{': - sb.append('\\'); - default: - sb.append(c); - } - } - if (sb.charAt(sb.length() - 1) == '.') { - // trailing '.' is optional - sb.append('?'); - } - return sb; - } - - /** - * Get the short and long values displayed for a field - * @param cal The calendar to obtain the short and long values - * @param locale The locale of display names - * @param field The field of interest - * @param regex The regular expression to build - * @return The map of string display names to field values - */ - private static Map appendDisplayNames(final Calendar cal, final Locale locale, final int field, final StringBuilder regex) { - final Map values = new HashMap<>(); - - final Map displayNames = cal.getDisplayNames(field, Calendar.ALL_STYLES, locale); - final TreeSet sorted = new TreeSet<>(LONGER_FIRST_LOWERCASE); - for (final Map.Entry displayName : displayNames.entrySet()) { - final String key = displayName.getKey().toLowerCase(locale); - if (sorted.add(key)) { - values.put(key, displayName.getValue()); - } - } - for (final String symbol : sorted) { - simpleQuote(regex, symbol).append('|'); - } - return values; - } - - /** - * Adjust dates to be within appropriate century - * @param twoDigitYear The year to adjust - * @return A value between centuryStart(inclusive) to centuryStart+100(exclusive) - */ - private int adjustYear(final int twoDigitYear) { - final int trial = century + twoDigitYear; - return twoDigitYear >= startYear ? trial : trial + 100; - } - - /** - * A strategy to parse a single field from the parsing pattern - */ - private abstract static class Strategy { - /** - * Is this field a number? - * The default implementation returns false. - * - * @return true, if field is a number - */ - boolean isNumber() { - return false; - } - - abstract boolean parse(FastDateParser parser, Calendar calendar, String source, ParsePosition pos, int maxWidth); - } - - /** - * A strategy to parse a single field from the parsing pattern - */ - private abstract static class PatternStrategy extends Strategy { - - private Pattern pattern; - - void createPattern(final StringBuilder regex) { - createPattern(regex.toString()); - } - - void createPattern(final String regex) { - this.pattern = Pattern.compile(regex); - } - - /** - * Is this field a number? - * The default implementation returns false. - * - * @return true, if field is a number - */ - @Override - boolean isNumber() { - return false; - } - - @Override - boolean parse(final FastDateParser parser, final Calendar calendar, final String source, final ParsePosition pos, final int maxWidth) { - final Matcher matcher = pattern.matcher(source.substring(pos.getIndex())); - if (!matcher.lookingAt()) { - pos.setErrorIndex(pos.getIndex()); - return false; - } - pos.setIndex(pos.getIndex() + matcher.end(1)); - setCalendar(parser, calendar, matcher.group(1)); - return true; - } - - abstract void setCalendar(FastDateParser parser, Calendar cal, String value); - } - - /** - * Obtain a Strategy given a field from a SimpleDateFormat pattern - * @param f A sub-sequence of the SimpleDateFormat pattern - * @param definingCalendar The calendar to obtain the short and long values - * @return The Strategy that will handle parsing for the field - */ - private Strategy getStrategy(final char f, final int width, final Calendar definingCalendar) { - switch(f) { - default: - throw new IllegalArgumentException("Format '"+f+"' not supported"); - case 'D': - return DAY_OF_YEAR_STRATEGY; - case 'E': - return getLocaleSpecificStrategy(Calendar.DAY_OF_WEEK, definingCalendar); - case 'F': - return DAY_OF_WEEK_IN_MONTH_STRATEGY; - case 'G': - return getLocaleSpecificStrategy(Calendar.ERA, definingCalendar); - case 'H': // Hour in day (0-23) - return HOUR_OF_DAY_STRATEGY; - case 'K': // Hour in am/pm (0-11) - return HOUR_STRATEGY; - case 'M': - return width>=3 ?getLocaleSpecificStrategy(Calendar.MONTH, definingCalendar) :NUMBER_MONTH_STRATEGY; - case 'S': - return MILLISECOND_STRATEGY; - case 'W': - return WEEK_OF_MONTH_STRATEGY; - case 'a': - return getLocaleSpecificStrategy(Calendar.AM_PM, definingCalendar); - case 'd': - return DAY_OF_MONTH_STRATEGY; - case 'h': // Hour in am/pm (1-12), i.e. midday/midnight is 12, not 0 - return HOUR12_STRATEGY; - case 'k': // Hour in day (1-24), i.e. midnight is 24, not 0 - return HOUR24_OF_DAY_STRATEGY; - case 'm': - return MINUTE_STRATEGY; - case 's': - return SECOND_STRATEGY; - case 'u': - return DAY_OF_WEEK_STRATEGY; - case 'w': - return WEEK_OF_YEAR_STRATEGY; - case 'y': - case 'Y': - return width>2 ?LITERAL_YEAR_STRATEGY :ABBREVIATED_YEAR_STRATEGY; - case 'X': - return ISO8601TimeZoneStrategy.getStrategy(width); - case 'Z': - if (width==2) { - return ISO8601TimeZoneStrategy.ISO_8601_3_STRATEGY; - } - //$FALL-THROUGH$ - case 'z': - return getLocaleSpecificStrategy(Calendar.ZONE_OFFSET, definingCalendar); - } - } - - @SuppressWarnings("unchecked") // OK because we are creating an array with no entries - private static final ConcurrentMap[] caches = new ConcurrentMap[Calendar.FIELD_COUNT]; - - /** - * Get a cache of Strategies for a particular field - * @param field The Calendar field - * @return a cache of Locale to Strategy - */ - private static ConcurrentMap getCache(final int field) { - synchronized (caches) { - if (caches[field] == null) { - caches[field] = new ConcurrentHashMap<>(3); - } - return caches[field]; - } - } - - /** - * Construct a Strategy that parses a Text field - * @param field The Calendar field - * @param definingCalendar The calendar to obtain the short and long values - * @return a TextStrategy for the field and Locale - */ - private Strategy getLocaleSpecificStrategy(final int field, final Calendar definingCalendar) { - final ConcurrentMap cache = getCache(field); - Strategy strategy = cache.get(locale); - if (strategy == null) { - strategy = field == Calendar.ZONE_OFFSET - ? new TimeZoneStrategy(locale) - : new CaseInsensitiveTextStrategy(field, definingCalendar, locale); - final Strategy inCache = cache.putIfAbsent(locale, strategy); - if (inCache != null) { - return inCache; - } - } - return strategy; - } - - /** - * A strategy that copies the static or quoted field in the parsing pattern - */ - private static class CopyQuotedStrategy extends Strategy { - - private final String formatField; - - /** - * Construct a Strategy that ensures the formatField has literal text - * @param formatField The literal text to match - */ - CopyQuotedStrategy(final String formatField) { - this.formatField = formatField; - } - - /** - * {@inheritDoc} - */ - @Override - boolean isNumber() { - return false; - } - - @Override - boolean parse(final FastDateParser parser, final Calendar calendar, final String source, final ParsePosition pos, final int maxWidth) { - for (int idx = 0; idx < formatField.length(); ++idx) { - final int sIdx = idx + pos.getIndex(); - if (sIdx == source.length()) { - pos.setErrorIndex(sIdx); - return false; - } - if (formatField.charAt(idx) != source.charAt(sIdx)) { - pos.setErrorIndex(sIdx); - return false; - } - } - pos.setIndex(formatField.length() + pos.getIndex()); - return true; - } - } - - /** - * A strategy that handles a text field in the parsing pattern - */ - private static class CaseInsensitiveTextStrategy extends PatternStrategy { - private final int field; - final Locale locale; - private final Map lKeyValues; - - /** - * Construct a Strategy that parses a Text field - * @param field The Calendar field - * @param definingCalendar The Calendar to use - * @param locale The Locale to use - */ - CaseInsensitiveTextStrategy(final int field, final Calendar definingCalendar, final Locale locale) { - this.field = field; - this.locale = locale; - - final StringBuilder regex = new StringBuilder(); - regex.append("((?iu)"); - lKeyValues = appendDisplayNames(definingCalendar, locale, field, regex); - regex.setLength(regex.length()-1); - regex.append(")"); - createPattern(regex); - } - - /** - * {@inheritDoc} - */ - @Override - void setCalendar(final FastDateParser parser, final Calendar cal, final String value) { - final String lowerCase = value.toLowerCase(locale); - Integer iVal = lKeyValues.get(lowerCase); - if (iVal == null) { - // match missing the optional trailing period - iVal = lKeyValues.get(lowerCase + '.'); - } - cal.set(field, iVal.intValue()); - } - } - - - /** - * A strategy that handles a number field in the parsing pattern - */ - private static class NumberStrategy extends Strategy { - private final int field; - - /** - * Construct a Strategy that parses a Number field - * @param field The Calendar field - */ - NumberStrategy(final int field) { - this.field= field; - } - - /** - * {@inheritDoc} - */ - @Override - boolean isNumber() { - return true; - } - - @Override - boolean parse(final FastDateParser parser, final Calendar calendar, final String source, final ParsePosition pos, final int maxWidth) { - int idx = pos.getIndex(); - int last = source.length(); - - if (maxWidth == 0) { - // if no maxWidth, strip leading white space - for (; idx < last; ++idx) { - final char c = source.charAt(idx); - if (!Character.isWhitespace(c)) { - break; - } - } - pos.setIndex(idx); - } else { - final int end = idx + maxWidth; - if (last > end) { - last = end; - } - } - - for (; idx < last; ++idx) { - final char c = source.charAt(idx); - if (!Character.isDigit(c)) { - break; - } - } - - if (pos.getIndex() == idx) { - pos.setErrorIndex(idx); - return false; - } - - final int value = Integer.parseInt(source.substring(pos.getIndex(), idx)); - pos.setIndex(idx); - - calendar.set(field, modify(parser, value)); - return true; - } - - /** - * Make any modifications to parsed integer - * @param parser The parser - * @param iValue The parsed integer - * @return The modified value - */ - int modify(final FastDateParser parser, final int iValue) { - return iValue; - } - - } - - private static final Strategy ABBREVIATED_YEAR_STRATEGY = new NumberStrategy(Calendar.YEAR) { - /** - * {@inheritDoc} - */ - @Override - int modify(final FastDateParser parser, final int iValue) { - return iValue < 100 ? parser.adjustYear(iValue) : iValue; - } - }; - - /** - * A strategy that handles a timezone field in the parsing pattern - */ - static class TimeZoneStrategy extends PatternStrategy { - private static final String RFC_822_TIME_ZONE = "[+-]\\d{4}"; - private static final String GMT_OPTION = FastTimeZone.GMT_ID + "[+-]\\d{1,2}:\\d{2}"; - - private final Locale locale; - private final Map tzNames= new HashMap<>(); - - private static class TzInfo { - TimeZone zone; - int dstOffset; - - TzInfo(final TimeZone tz, final boolean useDst) { - zone = tz; - dstOffset = useDst ?tz.getDSTSavings() :0; - } - } - - /** - * Index of zone id - */ - private static final int ID = 0; - - /** - * Construct a Strategy that parses a TimeZone - * @param locale The Locale - */ - TimeZoneStrategy(final Locale locale) { - this.locale = locale; - - final StringBuilder sb = new StringBuilder(); - sb.append("((?iu)" + RFC_822_TIME_ZONE + "|" + GMT_OPTION ); - - final Set sorted = new TreeSet<>(LONGER_FIRST_LOWERCASE); - - final String[][] zones = DateFormatSymbols.getInstance(locale).getZoneStrings(); - for (final String[] zoneNames : zones) { - // offset 0 is the time zone ID and is not localized - final String tzId = zoneNames[ID]; - if (tzId.equalsIgnoreCase(FastTimeZone.GMT_ID)) { - continue; - } - final TimeZone tz = TimeZone.getTimeZone(tzId); - // offset 1 is long standard name - // offset 2 is short standard name - final TzInfo standard = new TzInfo(tz, false); - TzInfo tzInfo = standard; - for (int i = 1; i < zoneNames.length; ++i) { - switch (i) { - case 3: // offset 3 is long daylight savings (or summertime) name - // offset 4 is the short summertime name - tzInfo = new TzInfo(tz, true); - break; - case 5: // offset 5 starts additional names, probably standard time - tzInfo = standard; - break; - default: - break; - } - if (zoneNames[i] != null) { - final String key = zoneNames[i].toLowerCase(locale); - // ignore the data associated with duplicates supplied in - // the additional names - if (sorted.add(key)) { - tzNames.put(key, tzInfo); - } - } - } - } - // order the regex alternatives with longer strings first, greedy - // match will ensure longest string will be consumed - for (final String zoneName : sorted) { - simpleQuote(sb.append('|'), zoneName); - } - sb.append(")"); - createPattern(sb); - } - - /** - * {@inheritDoc} - */ - @Override - void setCalendar(final FastDateParser parser, final Calendar cal, final String timeZone) { - final TimeZone tz = FastTimeZone.getGmtTimeZone(timeZone); - if (tz != null) { - cal.setTimeZone(tz); - } else { - final String lowerCase = timeZone.toLowerCase(locale); - TzInfo tzInfo = tzNames.get(lowerCase); - if (tzInfo == null) { - // match missing the optional trailing period - tzInfo = tzNames.get(lowerCase + '.'); - } - cal.set(Calendar.DST_OFFSET, tzInfo.dstOffset); - cal.set(Calendar.ZONE_OFFSET, tzInfo.zone.getRawOffset()); - } - } - } - - private static class ISO8601TimeZoneStrategy extends PatternStrategy { - // Z, +hh, -hh, +hhmm, -hhmm, +hh:mm or -hh:mm - - /** - * Construct a Strategy that parses a TimeZone - * @param pattern The Pattern - */ - ISO8601TimeZoneStrategy(final String pattern) { - createPattern(pattern); - } - - /** - * {@inheritDoc} - */ - @Override - void setCalendar(final FastDateParser parser, final Calendar cal, final String value) { - cal.setTimeZone(FastTimeZone.getGmtTimeZone(value)); - } - - private static final Strategy ISO_8601_1_STRATEGY = new ISO8601TimeZoneStrategy("(Z|(?:[+-]\\d{2}))"); - private static final Strategy ISO_8601_2_STRATEGY = new ISO8601TimeZoneStrategy("(Z|(?:[+-]\\d{2}\\d{2}))"); - private static final Strategy ISO_8601_3_STRATEGY = new ISO8601TimeZoneStrategy("(Z|(?:[+-]\\d{2}(?::)\\d{2}))"); - - /** - * Factory method for ISO8601TimeZoneStrategies. - * - * @param tokenLen a token indicating the length of the TimeZone String to be formatted. - * @return a ISO8601TimeZoneStrategy that can format TimeZone String of length {@code tokenLen}. If no such - * strategy exists, an IllegalArgumentException will be thrown. - */ - static Strategy getStrategy(final int tokenLen) { - switch(tokenLen) { - case 1: - return ISO_8601_1_STRATEGY; - case 2: - return ISO_8601_2_STRATEGY; - case 3: - return ISO_8601_3_STRATEGY; - default: - throw new IllegalArgumentException("invalid number of X"); - } - } - } - - private static final Strategy NUMBER_MONTH_STRATEGY = new NumberStrategy(Calendar.MONTH) { - @Override - int modify(final FastDateParser parser, final int iValue) { - return iValue-1; - } - }; - - private static final Strategy LITERAL_YEAR_STRATEGY = new NumberStrategy(Calendar.YEAR); - private static final Strategy WEEK_OF_YEAR_STRATEGY = new NumberStrategy(Calendar.WEEK_OF_YEAR); - private static final Strategy WEEK_OF_MONTH_STRATEGY = new NumberStrategy(Calendar.WEEK_OF_MONTH); - private static final Strategy DAY_OF_YEAR_STRATEGY = new NumberStrategy(Calendar.DAY_OF_YEAR); - private static final Strategy DAY_OF_MONTH_STRATEGY = new NumberStrategy(Calendar.DAY_OF_MONTH); - private static final Strategy DAY_OF_WEEK_STRATEGY = new NumberStrategy(Calendar.DAY_OF_WEEK) { - @Override - int modify(final FastDateParser parser, final int iValue) { - return iValue == 7 ? Calendar.SUNDAY : iValue + 1; - } - }; - - private static final Strategy DAY_OF_WEEK_IN_MONTH_STRATEGY = new NumberStrategy(Calendar.DAY_OF_WEEK_IN_MONTH); - private static final Strategy HOUR_OF_DAY_STRATEGY = new NumberStrategy(Calendar.HOUR_OF_DAY); - private static final Strategy HOUR24_OF_DAY_STRATEGY = new NumberStrategy(Calendar.HOUR_OF_DAY) { - @Override - int modify(final FastDateParser parser, final int iValue) { - return iValue == 24 ? 0 : iValue; - } - }; - - private static final Strategy HOUR12_STRATEGY = new NumberStrategy(Calendar.HOUR) { - @Override - int modify(final FastDateParser parser, final int iValue) { - return iValue == 12 ? 0 : iValue; - } - }; - - private static final Strategy HOUR_STRATEGY = new NumberStrategy(Calendar.HOUR); - private static final Strategy MINUTE_STRATEGY = new NumberStrategy(Calendar.MINUTE); - private static final Strategy SECOND_STRATEGY = new NumberStrategy(Calendar.SECOND); - private static final Strategy MILLISECOND_STRATEGY = new NumberStrategy(Calendar.MILLISECOND); -} \ No newline at end of file diff --git a/dubbo-common/src/main/java/org/apache/dubbo/common/time/FastDatePrinter.java b/dubbo-common/src/main/java/org/apache/dubbo/common/time/FastDatePrinter.java deleted file mode 100644 index ee9644f082e..00000000000 --- a/dubbo-common/src/main/java/org/apache/dubbo/common/time/FastDatePrinter.java +++ /dev/null @@ -1,1514 +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.common.time; - -import java.io.IOException; -import java.io.ObjectInputStream; -import java.io.Serializable; -import java.text.DateFormatSymbols; -import java.text.FieldPosition; -import java.util.ArrayList; -import java.util.Calendar; -import java.util.Date; -import java.util.List; -import java.util.Locale; -import java.util.TimeZone; -import java.util.concurrent.ConcurrentHashMap; -import java.util.concurrent.ConcurrentMap; - -/** - *

FastDatePrinter is a fast and thread-safe version

- */ -public class FastDatePrinter implements DatePrinter, Serializable { - // A lot of the speed in this class comes from caching, but some comes - // from the special int to StringBuffer conversion. - // - // The following produces a padded 2 digit number: - // buffer.append((char)(value / 10 + '0')); - // buffer.append((char)(value % 10 + '0')); - // - // Note that the fastest append to StringBuffer is a single char (used here). - // Note that Integer.toString() is not called, the conversion is simply - // taking the value and adding (mathematically) the ASCII value for '0'. - // So, don't change this code! It works and is very fast. - - /** - * Required for serialization support. - * - * @see java.io.Serializable - */ - private static final long serialVersionUID = 1L; - - - /** - * The pattern. - */ - private final String mPattern; - /** - * The time zone. - */ - private final TimeZone mTimeZone; - /** - * The locale. - */ - private final Locale mLocale; - /** - * The parsed rules. - */ - private transient Rule[] mRules; - /** - * The estimated maximum length. - */ - private transient int mMaxLengthEstimate; - - // Constructor - //----------------------------------------------------------------------- - /** - *

Constructs a new FastDatePrinter.

- * factory methods of {@link FastDateFormat} to get a cached FastDatePrinter instance. - * - * @param pattern {@link java.text.SimpleDateFormat} compatible pattern - * @param timeZone non-null time zone to use - * @param locale non-null locale to use - * @throws NullPointerException if pattern, timeZone, or locale is null. - */ - protected FastDatePrinter(final String pattern, final TimeZone timeZone, final Locale locale) { - mPattern = pattern; - mTimeZone = timeZone; - mLocale = locale; - - init(); - } - - /** - *

Initializes the instance for first use.

- */ - private void init() { - final List rulesList = parsePattern(); - mRules = rulesList.toArray(new Rule[rulesList.size()]); - - int len = 0; - for (int i=mRules.length; --i >= 0; ) { - len += mRules[i].estimateLength(); - } - - mMaxLengthEstimate = len; - } - - // Parse the pattern - //----------------------------------------------------------------------- - /** - *

Returns a list of Rules given a pattern.

- * - * @return a {@code List} of Rule objects - * @throws IllegalArgumentException if pattern is invalid - */ - protected List parsePattern() { - final DateFormatSymbols symbols = new DateFormatSymbols(mLocale); - final List rules = new ArrayList<>(); - - final String[] ERAs = symbols.getEras(); - final String[] months = symbols.getMonths(); - final String[] shortMonths = symbols.getShortMonths(); - final String[] weekdays = symbols.getWeekdays(); - final String[] shortWeekdays = symbols.getShortWeekdays(); - final String[] AmPmStrings = symbols.getAmPmStrings(); - - final int length = mPattern.length(); - final int[] indexRef = new int[1]; - - for (int i = 0; i < length; i++) { - indexRef[0] = i; - final String token = parseToken(mPattern, indexRef); - i = indexRef[0]; - - final int tokenLen = token.length(); - if (tokenLen == 0) { - break; - } - - Rule rule; - final char c = token.charAt(0); - - switch (c) { - case 'G': // era designator (text) - rule = new TextField(Calendar.ERA, ERAs); - break; - case 'y': // year (number) - case 'Y': // week year - if (tokenLen == 2) { - rule = TwoDigitYearField.INSTANCE; - } else { - rule = selectNumberRule(Calendar.YEAR, tokenLen < 4 ? 4 : tokenLen); - } - if (c == 'Y') { - rule = new WeekYear((NumberRule) rule); - } - break; - case 'M': // month in year (text and number) - if (tokenLen >= 4) { - rule = new TextField(Calendar.MONTH, months); - } else if (tokenLen == 3) { - rule = new TextField(Calendar.MONTH, shortMonths); - } else if (tokenLen == 2) { - rule = TwoDigitMonthField.INSTANCE; - } else { - rule = UnpaddedMonthField.INSTANCE; - } - break; - case 'd': // day in month (number) - rule = selectNumberRule(Calendar.DAY_OF_MONTH, tokenLen); - break; - case 'h': // hour in am/pm (number, 1..12) - rule = new TwelveHourField(selectNumberRule(Calendar.HOUR, tokenLen)); - break; - case 'H': // hour in day (number, 0..23) - rule = selectNumberRule(Calendar.HOUR_OF_DAY, tokenLen); - break; - case 'm': // minute in hour (number) - rule = selectNumberRule(Calendar.MINUTE, tokenLen); - break; - case 's': // second in minute (number) - rule = selectNumberRule(Calendar.SECOND, tokenLen); - break; - case 'S': // millisecond (number) - rule = selectNumberRule(Calendar.MILLISECOND, tokenLen); - break; - case 'E': // day in week (text) - rule = new TextField(Calendar.DAY_OF_WEEK, tokenLen < 4 ? shortWeekdays : weekdays); - break; - case 'u': // day in week (number) - rule = new DayInWeekField(selectNumberRule(Calendar.DAY_OF_WEEK, tokenLen)); - break; - case 'D': // day in year (number) - rule = selectNumberRule(Calendar.DAY_OF_YEAR, tokenLen); - break; - case 'F': // day of week in month (number) - rule = selectNumberRule(Calendar.DAY_OF_WEEK_IN_MONTH, tokenLen); - break; - case 'w': // week in year (number) - rule = selectNumberRule(Calendar.WEEK_OF_YEAR, tokenLen); - break; - case 'W': // week in month (number) - rule = selectNumberRule(Calendar.WEEK_OF_MONTH, tokenLen); - break; - case 'a': // am/pm marker (text) - rule = new TextField(Calendar.AM_PM, AmPmStrings); - break; - case 'k': // hour in day (1..24) - rule = new TwentyFourHourField(selectNumberRule(Calendar.HOUR_OF_DAY, tokenLen)); - break; - case 'K': // hour in am/pm (0..11) - rule = selectNumberRule(Calendar.HOUR, tokenLen); - break; - case 'X': // ISO 8601 - rule = Iso8601_Rule.getRule(tokenLen); - break; - case 'z': // time zone (text) - if (tokenLen >= 4) { - rule = new TimeZoneNameRule(mTimeZone, mLocale, TimeZone.LONG); - } else { - rule = new TimeZoneNameRule(mTimeZone, mLocale, TimeZone.SHORT); - } - break; - case 'Z': // time zone (value) - if (tokenLen == 1) { - rule = TimeZoneNumberRule.INSTANCE_NO_COLON; - } else if (tokenLen == 2) { - rule = Iso8601_Rule.ISO8601_HOURS_COLON_MINUTES; - } else { - rule = TimeZoneNumberRule.INSTANCE_COLON; - } - break; - case '\'': // literal text - final String sub = token.substring(1); - if (sub.length() == 1) { - rule = new CharacterLiteral(sub.charAt(0)); - } else { - rule = new StringLiteral(sub); - } - break; - default: - throw new IllegalArgumentException("Illegal pattern component: " + token); - } - - rules.add(rule); - } - - return rules; - } - - /** - *

Performs the parsing of tokens.

- * - * @param pattern the pattern - * @param indexRef index references - * @return parsed token - */ - protected String parseToken(final String pattern, final int[] indexRef) { - final StringBuilder buf = new StringBuilder(); - - int i = indexRef[0]; - final int length = pattern.length(); - - char c = pattern.charAt(i); - if (c >= 'A' && c <= 'Z' || c >= 'a' && c <= 'z') { - // Scan a run of the same character, which indicates a time - // pattern. - buf.append(c); - - while (i + 1 < length) { - final char peek = pattern.charAt(i + 1); - if (peek == c) { - buf.append(c); - i++; - } else { - break; - } - } - } else { - // This will identify token as text. - buf.append('\''); - - boolean inLiteral = false; - - for (; i < length; i++) { - c = pattern.charAt(i); - - if (c == '\'') { - if (i + 1 < length && pattern.charAt(i + 1) == '\'') { - // '' is treated as escaped ' - i++; - buf.append(c); - } else { - inLiteral = !inLiteral; - } - } else if (!inLiteral && - (c >= 'A' && c <= 'Z' || c >= 'a' && c <= 'z')) { - i--; - break; - } else { - buf.append(c); - } - } - } - - indexRef[0] = i; - return buf.toString(); - } - - /** - *

Gets an appropriate rule for the padding required.

- * - * @param field the field to get a rule for - * @param padding the padding required - * @return a new rule with the correct padding - */ - protected NumberRule selectNumberRule(final int field, final int padding) { - switch (padding) { - case 1: - return new UnpaddedNumberField(field); - case 2: - return new TwoDigitNumberField(field); - default: - return new PaddedNumberField(field, padding); - } - } - - // Format methods - //----------------------------------------------------------------------- - /** - *

Formats a {@code Date}, {@code Calendar} or - * {@code Long} (milliseconds) object.

- * @deprecated Use {{@link #format(Date)}, {{@link #format(Calendar)}, {{@link #format(long)}, or {{@link #format(Object)} - * @param obj the object to format - * @param toAppendTo the buffer to append to - * @param pos the position - ignored - * @return the buffer passed in - */ - @Deprecated - @Override - public StringBuffer format(final Object obj, final StringBuffer toAppendTo, final FieldPosition pos) { - if (obj instanceof Date) { - return format((Date) obj, toAppendTo); - } else if (obj instanceof Calendar) { - return format((Calendar) obj, toAppendTo); - } else if (obj instanceof Long) { - return format(((Long) obj).longValue(), toAppendTo); - } else { - throw new IllegalArgumentException("Unknown class: " + - (obj == null ? "" : obj.getClass().getName())); - } - } - - /** - *

Formats a {@code Date}, {@code Calendar} or - * {@code Long} (milliseconds) object.

- * @since 3.5 - * @param obj the object to format - * @return The formatted value. - */ - String format(final Object obj) { - if (obj instanceof Date) { - return format((Date) obj); - } else if (obj instanceof Calendar) { - return format((Calendar) obj); - } else if (obj instanceof Long) { - return format(((Long) obj).longValue()); - } else { - throw new IllegalArgumentException("Unknown class: " + - (obj == null ? "" : obj.getClass().getName())); - } - } - - /* (non-Javadoc) - * @see org.apache.commons.lang3.time.DatePrinter#format(long) - */ - @Override - public String format(final long millis) { - final Calendar c = newCalendar(); - c.setTimeInMillis(millis); - return applyRulesToString(c); - } - - /** - * Creates a String representation of the given Calendar by applying the rules of this printer to it. - * @param c the Calender to apply the rules to. - * @return a String representation of the given Calendar. - */ - private String applyRulesToString(final Calendar c) { - return applyRules(c, new StringBuilder(mMaxLengthEstimate)).toString(); - } - - /** - * Creation method for new calender instances. - * @return a new Calendar instance. - */ - private Calendar newCalendar() { - return Calendar.getInstance(mTimeZone, mLocale); - } - - /* (non-Javadoc) - * @see org.apache.commons.lang3.time.DatePrinter#format(java.util.Date) - */ - @Override - public String format(final Date date) { - final Calendar c = newCalendar(); - c.setTime(date); - return applyRulesToString(c); - } - - /* (non-Javadoc) - * @see org.apache.commons.lang3.time.DatePrinter#format(java.util.Calendar) - */ - @Override - public String format(final Calendar calendar) { - return format(calendar, new StringBuilder(mMaxLengthEstimate)).toString(); - } - - /* (non-Javadoc) - * @see org.apache.commons.lang3.time.DatePrinter#format(long, java.lang.StringBuffer) - */ - @Override - public StringBuffer format(final long millis, final StringBuffer buf) { - final Calendar c = newCalendar(); - c.setTimeInMillis(millis); - return (StringBuffer) applyRules(c, (Appendable) buf); - } - - /* (non-Javadoc) - * @see org.apache.commons.lang3.time.DatePrinter#format(java.util.Date, java.lang.StringBuffer) - */ - @Override - public StringBuffer format(final Date date, final StringBuffer buf) { - final Calendar c = newCalendar(); - c.setTime(date); - return (StringBuffer) applyRules(c, (Appendable) buf); - } - - /* (non-Javadoc) - * @see org.apache.commons.lang3.time.DatePrinter#format(java.util.Calendar, java.lang.StringBuffer) - */ - @Override - public StringBuffer format(final Calendar calendar, final StringBuffer buf) { - // do not pass in calendar directly, this will cause TimeZone of FastDatePrinter to be ignored - return format(calendar.getTime(), buf); - } - - /* (non-Javadoc) - * @see org.apache.commons.lang3.time.DatePrinter#format(long, java.lang.Appendable) - */ - @Override - public B format(final long millis, final B buf) { - final Calendar c = newCalendar(); - c.setTimeInMillis(millis); - return applyRules(c, buf); - } - - /* (non-Javadoc) - * @see org.apache.commons.lang3.time.DatePrinter#format(java.util.Date, java.lang.Appendable) - */ - @Override - public B format(final Date date, final B buf) { - final Calendar c = newCalendar(); - c.setTime(date); - return applyRules(c, buf); - } - - /* (non-Javadoc) - * @see org.apache.commons.lang3.time.DatePrinter#format(java.util.Calendar, java.lang.Appendable) - */ - @Override - public B format(Calendar calendar, final B buf) { - // do not pass in calendar directly, this will cause TimeZone of FastDatePrinter to be ignored - if (!calendar.getTimeZone().equals(mTimeZone)) { - calendar = (Calendar) calendar.clone(); - calendar.setTimeZone(mTimeZone); - } - return applyRules(calendar, buf); - } - - /** - * Performs the formatting by applying the rules to the - * specified calendar. - * - * @param calendar the calendar to format - * @param buf the buffer to format into - * @return the specified string buffer - * - * @deprecated use {@link #format(Calendar)} or {@link #format(Calendar, Appendable)} - */ - @Deprecated - protected StringBuffer applyRules(final Calendar calendar, final StringBuffer buf) { - return (StringBuffer) applyRules(calendar, (Appendable) buf); - } - - /** - *

Performs the formatting by applying the rules to the - * specified calendar.

- * - * @param calendar the calendar to format - * @param buf the buffer to format into - * @param the Appendable class type, usually StringBuilder or StringBuffer. - * @return the specified string buffer - */ - private B applyRules(final Calendar calendar, final B buf) { - try { - for (final Rule rule : mRules) { - rule.appendTo(buf, calendar); - } - } catch (final IOException ioe) { - throw new RuntimeException(ioe); - } - return buf; - } - - // Accessors - //----------------------------------------------------------------------- - /* (non-Javadoc) - * @see org.apache.commons.lang3.time.DatePrinter#getPattern() - */ - @Override - public String getPattern() { - return mPattern; - } - - /* (non-Javadoc) - * @see org.apache.commons.lang3.time.DatePrinter#getTimeZone() - */ - @Override - public TimeZone getTimeZone() { - return mTimeZone; - } - - /* (non-Javadoc) - * @see org.apache.commons.lang3.time.DatePrinter#getLocale() - */ - @Override - public Locale getLocale() { - return mLocale; - } - - /** - *

Gets an estimate for the maximum string length that the - * formatter will produce.

- * - *

The actual formatted length will almost always be less than or - * equal to this amount.

- * - * @return the maximum formatted length - */ - public int getMaxLengthEstimate() { - return mMaxLengthEstimate; - } - - // Basics - //----------------------------------------------------------------------- - /** - *

Compares two objects for equality.

- * - * @param obj the object to compare to - * @return {@code true} if equal - */ - @Override - public boolean equals(final Object obj) { - if (!(obj instanceof FastDatePrinter)) { - return false; - } - final FastDatePrinter other = (FastDatePrinter) obj; - return mPattern.equals(other.mPattern) - && mTimeZone.equals(other.mTimeZone) - && mLocale.equals(other.mLocale); - } - - /** - *

Returns a hash code compatible with equals.

- * - * @return a hash code compatible with equals - */ - @Override - public int hashCode() { - return mPattern.hashCode() + 13 * (mTimeZone.hashCode() + 13 * mLocale.hashCode()); - } - - /** - *

Gets a debugging string version of this formatter.

- * - * @return a debugging string - */ - @Override - public String toString() { - return "FastDatePrinter[" + mPattern + "," + mLocale + "," + mTimeZone.getID() + "]"; - } - - // Serializing - //----------------------------------------------------------------------- - /** - * Create the object after serialization. This implementation reinitializes the - * transient properties. - * - * @param in ObjectInputStream from which the object is being deserialized. - * @throws IOException if there is an IO issue. - * @throws ClassNotFoundException if a class cannot be found. - */ - private void readObject(final ObjectInputStream in) throws IOException, ClassNotFoundException { - in.defaultReadObject(); - init(); - } - - /** - * Appends two digits to the given buffer. - * - * @param buffer the buffer to append to. - * @param value the value to append digits from. - */ - private static void appendDigits(final Appendable buffer, final int value) throws IOException { - buffer.append((char) (value / 10 + '0')); - buffer.append((char) (value % 10 + '0')); - } - - private static final int MAX_DIGITS = 10; // log10(Integer.MAX_VALUE) ~= 9.3 - - /** - * Appends all digits to the given buffer. - * - * @param buffer the buffer to append to. - * @param value the value to append digits from. - */ - private static void appendFullDigits(final Appendable buffer, int value, int minFieldWidth) throws IOException { - // specialized paths for 1 to 4 digits -> avoid the memory allocation from the temporary work array - // see LANG-1248 - if (value < 10000) { - // less memory allocation path works for four digits or less - - int nDigits = 4; - if (value < 1000) { - --nDigits; - if (value < 100) { - --nDigits; - if (value < 10) { - --nDigits; - } - } - } - // left zero pad - for (int i = minFieldWidth - nDigits; i > 0; --i) { - buffer.append('0'); - } - - switch (nDigits) { - case 4: - buffer.append((char) (value / 1000 + '0')); - value %= 1000; - case 3: - if (value >= 100) { - buffer.append((char) (value / 100 + '0')); - value %= 100; - } else { - buffer.append('0'); - } - case 2: - if (value >= 10) { - buffer.append((char) (value / 10 + '0')); - value %= 10; - } else { - buffer.append('0'); - } - case 1: - buffer.append((char) (value + '0')); - } - } else { - // more memory allocation path works for any digits - - // build up decimal representation in reverse - final char[] work = new char[MAX_DIGITS]; - int digit = 0; - while (value != 0) { - work[digit++] = (char) (value % 10 + '0'); - value = value / 10; - } - - // pad with zeros - while (digit < minFieldWidth) { - buffer.append('0'); - --minFieldWidth; - } - - // reverse - while (--digit >= 0) { - buffer.append(work[digit]); - } - } - } - - // Rules - //----------------------------------------------------------------------- - /** - *

Inner class defining a rule.

- */ - private interface Rule { - /** - * Returns the estimated length of the result. - * - * @return the estimated length - */ - int estimateLength(); - - /** - * Appends the value of the specified calendar to the output buffer based on the rule implementation. - * - * @param buf the output buffer - * @param calendar calendar to be appended - * @throws IOException if an I/O error occurs - */ - void appendTo(Appendable buf, Calendar calendar) throws IOException; - } - - /** - *

Inner class defining a numeric rule.

- */ - private interface NumberRule extends Rule { - /** - * Appends the specified value to the output buffer based on the rule implementation. - * - * @param buffer the output buffer - * @param value the value to be appended - * @throws IOException if an I/O error occurs - */ - void appendTo(Appendable buffer, int value) throws IOException; - } - - /** - *

Inner class to output a constant single character.

- */ - private static class CharacterLiteral implements Rule { - private final char mValue; - - /** - * Constructs a new instance of {@code CharacterLiteral} - * to hold the specified value. - * - * @param value the character literal - */ - CharacterLiteral(final char value) { - mValue = value; - } - - /** - * {@inheritDoc} - */ - @Override - public int estimateLength() { - return 1; - } - - /** - * {@inheritDoc} - */ - @Override - public void appendTo(final Appendable buffer, final Calendar calendar) throws IOException { - buffer.append(mValue); - } - } - - /** - *

Inner class to output a constant string.

- */ - private static class StringLiteral implements Rule { - private final String mValue; - - /** - * Constructs a new instance of {@code StringLiteral} - * to hold the specified value. - * - * @param value the string literal - */ - StringLiteral(final String value) { - mValue = value; - } - - /** - * {@inheritDoc} - */ - @Override - public int estimateLength() { - return mValue.length(); - } - - /** - * {@inheritDoc} - */ - @Override - public void appendTo(final Appendable buffer, final Calendar calendar) throws IOException { - buffer.append(mValue); - } - } - - /** - *

Inner class to output one of a set of values.

- */ - private static class TextField implements Rule { - private final int mField; - private final String[] mValues; - - /** - * Constructs an instance of {@code TextField} - * with the specified field and values. - * - * @param field the field - * @param values the field values - */ - TextField(final int field, final String[] values) { - mField = field; - mValues = values; - } - - /** - * {@inheritDoc} - */ - @Override - public int estimateLength() { - int max = 0; - for (int i=mValues.length; --i >= 0; ) { - final int len = mValues[i].length(); - if (len > max) { - max = len; - } - } - return max; - } - - /** - * {@inheritDoc} - */ - @Override - public void appendTo(final Appendable buffer, final Calendar calendar) throws IOException { - buffer.append(mValues[calendar.get(mField)]); - } - } - - /** - *

Inner class to output an unpadded number.

- */ - private static class UnpaddedNumberField implements NumberRule { - private final int mField; - - /** - * Constructs an instance of {@code UnpadedNumberField} with the specified field. - * - * @param field the field - */ - UnpaddedNumberField(final int field) { - mField = field; - } - - /** - * {@inheritDoc} - */ - @Override - public int estimateLength() { - return 4; - } - - /** - * {@inheritDoc} - */ - @Override - public void appendTo(final Appendable buffer, final Calendar calendar) throws IOException { - appendTo(buffer, calendar.get(mField)); - } - - /** - * {@inheritDoc} - */ - @Override - public final void appendTo(final Appendable buffer, final int value) throws IOException { - if (value < 10) { - buffer.append((char) (value + '0')); - } else if (value < 100) { - appendDigits(buffer, value); - } else { - appendFullDigits(buffer, value, 1); - } - } - } - - /** - *

Inner class to output an unpadded month.

- */ - private static class UnpaddedMonthField implements NumberRule { - static final UnpaddedMonthField INSTANCE = new UnpaddedMonthField(); - - /** - * Constructs an instance of {@code UnpaddedMonthField}. - * - */ - UnpaddedMonthField() { - super(); - } - - /** - * {@inheritDoc} - */ - @Override - public int estimateLength() { - return 2; - } - - /** - * {@inheritDoc} - */ - @Override - public void appendTo(final Appendable buffer, final Calendar calendar) throws IOException { - appendTo(buffer, calendar.get(Calendar.MONTH) + 1); - } - - /** - * {@inheritDoc} - */ - @Override - public final void appendTo(final Appendable buffer, final int value) throws IOException { - if (value < 10) { - buffer.append((char) (value + '0')); - } else { - appendDigits(buffer, value); - } - } - } - - /** - *

Inner class to output a padded number.

- */ - private static class PaddedNumberField implements NumberRule { - private final int mField; - private final int mSize; - - /** - * Constructs an instance of {@code PaddedNumberField}. - * - * @param field the field - * @param size size of the output field - */ - PaddedNumberField(final int field, final int size) { - if (size < 3) { - // Should use UnpaddedNumberField or TwoDigitNumberField. - throw new IllegalArgumentException(); - } - mField = field; - mSize = size; - } - - /** - * {@inheritDoc} - */ - @Override - public int estimateLength() { - return mSize; - } - - /** - * {@inheritDoc} - */ - @Override - public void appendTo(final Appendable buffer, final Calendar calendar) throws IOException { - appendTo(buffer, calendar.get(mField)); - } - - /** - * {@inheritDoc} - */ - @Override - public final void appendTo(final Appendable buffer, final int value) throws IOException { - appendFullDigits(buffer, value, mSize); - } - } - - /** - *

Inner class to output a two digit number.

- */ - private static class TwoDigitNumberField implements NumberRule { - private final int mField; - - /** - * Constructs an instance of {@code TwoDigitNumberField} with the specified field. - * - * @param field the field - */ - TwoDigitNumberField(final int field) { - mField = field; - } - - /** - * {@inheritDoc} - */ - @Override - public int estimateLength() { - return 2; - } - - /** - * {@inheritDoc} - */ - @Override - public void appendTo(final Appendable buffer, final Calendar calendar) throws IOException { - appendTo(buffer, calendar.get(mField)); - } - - /** - * {@inheritDoc} - */ - @Override - public final void appendTo(final Appendable buffer, final int value) throws IOException { - if (value < 100) { - appendDigits(buffer, value); - } else { - appendFullDigits(buffer, value, 2); - } - } - } - - /** - *

Inner class to output a two digit year.

- */ - private static class TwoDigitYearField implements NumberRule { - static final TwoDigitYearField INSTANCE = new TwoDigitYearField(); - - /** - * Constructs an instance of {@code TwoDigitYearField}. - */ - TwoDigitYearField() { - super(); - } - - /** - * {@inheritDoc} - */ - @Override - public int estimateLength() { - return 2; - } - - /** - * {@inheritDoc} - */ - @Override - public void appendTo(final Appendable buffer, final Calendar calendar) throws IOException { - appendTo(buffer, calendar.get(Calendar.YEAR) % 100); - } - - /** - * {@inheritDoc} - */ - @Override - public final void appendTo(final Appendable buffer, final int value) throws IOException { - appendDigits(buffer, value); - } - } - - /** - *

Inner class to output a two digit month.

- */ - private static class TwoDigitMonthField implements NumberRule { - static final TwoDigitMonthField INSTANCE = new TwoDigitMonthField(); - - /** - * Constructs an instance of {@code TwoDigitMonthField}. - */ - TwoDigitMonthField() { - super(); - } - - /** - * {@inheritDoc} - */ - @Override - public int estimateLength() { - return 2; - } - - /** - * {@inheritDoc} - */ - @Override - public void appendTo(final Appendable buffer, final Calendar calendar) throws IOException { - appendTo(buffer, calendar.get(Calendar.MONTH) + 1); - } - - /** - * {@inheritDoc} - */ - @Override - public final void appendTo(final Appendable buffer, final int value) throws IOException { - appendDigits(buffer, value); - } - } - - /** - *

Inner class to output the twelve hour field.

- */ - private static class TwelveHourField implements NumberRule { - private final NumberRule mRule; - - /** - * Constructs an instance of {@code TwelveHourField} with the specified - * {@code NumberRule}. - * - * @param rule the rule - */ - TwelveHourField(final NumberRule rule) { - mRule = rule; - } - - /** - * {@inheritDoc} - */ - @Override - public int estimateLength() { - return mRule.estimateLength(); - } - - /** - * {@inheritDoc} - */ - @Override - public void appendTo(final Appendable buffer, final Calendar calendar) throws IOException { - int value = calendar.get(Calendar.HOUR); - if (value == 0) { - value = calendar.getLeastMaximum(Calendar.HOUR) + 1; - } - mRule.appendTo(buffer, value); - } - - /** - * {@inheritDoc} - */ - @Override - public void appendTo(final Appendable buffer, final int value) throws IOException { - mRule.appendTo(buffer, value); - } - } - - /** - *

Inner class to output the twenty four hour field.

- */ - private static class TwentyFourHourField implements NumberRule { - private final NumberRule mRule; - - /** - * Constructs an instance of {@code TwentyFourHourField} with the specified - * {@code NumberRule}. - * - * @param rule the rule - */ - TwentyFourHourField(final NumberRule rule) { - mRule = rule; - } - - /** - * {@inheritDoc} - */ - @Override - public int estimateLength() { - return mRule.estimateLength(); - } - - /** - * {@inheritDoc} - */ - @Override - public void appendTo(final Appendable buffer, final Calendar calendar) throws IOException { - int value = calendar.get(Calendar.HOUR_OF_DAY); - if (value == 0) { - value = calendar.getMaximum(Calendar.HOUR_OF_DAY) + 1; - } - mRule.appendTo(buffer, value); - } - - /** - * {@inheritDoc} - */ - @Override - public void appendTo(final Appendable buffer, final int value) throws IOException { - mRule.appendTo(buffer, value); - } - } - - /** - *

Inner class to output the numeric day in week.

- */ - private static class DayInWeekField implements NumberRule { - private final NumberRule mRule; - - DayInWeekField(final NumberRule rule) { - mRule = rule; - } - - @Override - public int estimateLength() { - return mRule.estimateLength(); - } - - @Override - public void appendTo(final Appendable buffer, final Calendar calendar) throws IOException { - final int value = calendar.get(Calendar.DAY_OF_WEEK); - mRule.appendTo(buffer, value == Calendar.SUNDAY ? 7 : value - 1); - } - - @Override - public void appendTo(final Appendable buffer, final int value) throws IOException { - mRule.appendTo(buffer, value); - } - } - - /** - *

Inner class to output the numeric day in week.

- */ - private static class WeekYear implements NumberRule { - private final NumberRule mRule; - - WeekYear(final NumberRule rule) { - mRule = rule; - } - - @Override - public int estimateLength() { - return mRule.estimateLength(); - } - - @Override - public void appendTo(final Appendable buffer, final Calendar calendar) throws IOException { - mRule.appendTo(buffer, calendar.getWeekYear()); - } - - @Override - public void appendTo(final Appendable buffer, final int value) throws IOException { - mRule.appendTo(buffer, value); - } - } - - //----------------------------------------------------------------------- - - private static final ConcurrentMap cTimeZoneDisplayCache = - new ConcurrentHashMap<>(7); - /** - *

Gets the time zone display name, using a cache for performance.

- * - * @param tz the zone to query - * @param daylight true if daylight savings - * @param style the style to use {@code TimeZone.LONG} or {@code TimeZone.SHORT} - * @param locale the locale to use - * @return the textual name of the time zone - */ - static String getTimeZoneDisplay(final TimeZone tz, final boolean daylight, final int style, final Locale locale) { - final TimeZoneDisplayKey key = new TimeZoneDisplayKey(tz, daylight, style, locale); - String value = cTimeZoneDisplayCache.get(key); - if (value == null) { - // This is a very slow call, so cache the results. - value = tz.getDisplayName(daylight, style, locale); - final String prior = cTimeZoneDisplayCache.putIfAbsent(key, value); - if (prior != null) { - value= prior; - } - } - return value; - } - - /** - *

Inner class to output a time zone name.

- */ - private static class TimeZoneNameRule implements Rule { - private final Locale mLocale; - private final int mStyle; - private final String mStandard; - private final String mDaylight; - - /** - * Constructs an instance of {@code TimeZoneNameRule} with the specified properties. - * - * @param timeZone the time zone - * @param locale the locale - * @param style the style - */ - TimeZoneNameRule(final TimeZone timeZone, final Locale locale, final int style) { - mLocale = locale; - mStyle = style; - - mStandard = getTimeZoneDisplay(timeZone, false, style, locale); - mDaylight = getTimeZoneDisplay(timeZone, true, style, locale); - } - - /** - * {@inheritDoc} - */ - @Override - public int estimateLength() { - // We have no access to the Calendar object that will be passed to - // appendTo so base estimate on the TimeZone passed to the - // constructor - return Math.max(mStandard.length(), mDaylight.length()); - } - - /** - * {@inheritDoc} - */ - @Override - public void appendTo(final Appendable buffer, final Calendar calendar) throws IOException { - final TimeZone zone = calendar.getTimeZone(); - if (calendar.get(Calendar.DST_OFFSET) == 0) { - buffer.append(getTimeZoneDisplay(zone, false, mStyle, mLocale)); - } else { - buffer.append(getTimeZoneDisplay(zone, true, mStyle, mLocale)); - } - } - } - - /** - *

Inner class to output a time zone as a number {@code +/-HHMM} - * or {@code +/-HH:MM}.

- */ - private static class TimeZoneNumberRule implements Rule { - static final TimeZoneNumberRule INSTANCE_COLON = new TimeZoneNumberRule(true); - static final TimeZoneNumberRule INSTANCE_NO_COLON = new TimeZoneNumberRule(false); - - final boolean mColon; - - /** - * Constructs an instance of {@code TimeZoneNumberRule} with the specified properties. - * - * @param colon add colon between HH and MM in the output if {@code true} - */ - TimeZoneNumberRule(final boolean colon) { - mColon = colon; - } - - /** - * {@inheritDoc} - */ - @Override - public int estimateLength() { - return 5; - } - - /** - * {@inheritDoc} - */ - @Override - public void appendTo(final Appendable buffer, final Calendar calendar) throws IOException { - - int offset = calendar.get(Calendar.ZONE_OFFSET) + calendar.get(Calendar.DST_OFFSET); - - if (offset < 0) { - buffer.append('-'); - offset = -offset; - } else { - buffer.append('+'); - } - - final int hours = offset / (60 * 60 * 1000); - appendDigits(buffer, hours); - - if (mColon) { - buffer.append(':'); - } - - final int minutes = offset / (60 * 1000) - 60 * hours; - appendDigits(buffer, minutes); - } - } - - /** - *

Inner class to output a time zone as a number {@code +/-HHMM} - * or {@code +/-HH:MM}.

- */ - private static class Iso8601_Rule implements Rule { - - // Sign TwoDigitHours or Z - static final Iso8601_Rule ISO8601_HOURS = new Iso8601_Rule(3); - // Sign TwoDigitHours Minutes or Z - static final Iso8601_Rule ISO8601_HOURS_MINUTES = new Iso8601_Rule(5); - // Sign TwoDigitHours : Minutes or Z - static final Iso8601_Rule ISO8601_HOURS_COLON_MINUTES = new Iso8601_Rule(6); - - /** - * Factory method for Iso8601_Rules. - * - * @param tokenLen a token indicating the length of the TimeZone String to be formatted. - * @return a Iso8601_Rule that can format TimeZone String of length {@code tokenLen}. If no such - * rule exists, an IllegalArgumentException will be thrown. - */ - static Iso8601_Rule getRule(final int tokenLen) { - switch(tokenLen) { - case 1: - return ISO8601_HOURS; - case 2: - return ISO8601_HOURS_MINUTES; - case 3: - return ISO8601_HOURS_COLON_MINUTES; - default: - throw new IllegalArgumentException("invalid number of X"); - } - } - - final int length; - - /** - * Constructs an instance of {@code Iso8601_Rule} with the specified properties. - * - * @param length The number of characters in output (unless Z is output) - */ - Iso8601_Rule(final int length) { - this.length = length; - } - - /** - * {@inheritDoc} - */ - @Override - public int estimateLength() { - return length; - } - - /** - * {@inheritDoc} - */ - @Override - public void appendTo(final Appendable buffer, final Calendar calendar) throws IOException { - int offset = calendar.get(Calendar.ZONE_OFFSET) + calendar.get(Calendar.DST_OFFSET); - if (offset == 0) { - buffer.append("Z"); - return; - } - - if (offset < 0) { - buffer.append('-'); - offset = -offset; - } else { - buffer.append('+'); - } - - final int hours = offset / (60 * 60 * 1000); - appendDigits(buffer, hours); - - if (length<5) { - return; - } - - if (length==6) { - buffer.append(':'); - } - - final int minutes = offset / (60 * 1000) - 60 * hours; - appendDigits(buffer, minutes); - } - } - - // ---------------------------------------------------------------------- - /** - *

Inner class that acts as a compound key for time zone names.

- */ - private static class TimeZoneDisplayKey { - private final TimeZone mTimeZone; - private final int mStyle; - private final Locale mLocale; - - /** - * Constructs an instance of {@code TimeZoneDisplayKey} with the specified properties. - * - * @param timeZone the time zone - * @param daylight adjust the style for daylight saving time if {@code true} - * @param style the timezone style - * @param locale the timezone locale - */ - TimeZoneDisplayKey(final TimeZone timeZone, - final boolean daylight, final int style, final Locale locale) { - mTimeZone = timeZone; - if (daylight) { - mStyle = style | 0x80000000; - } else { - mStyle = style; - } - mLocale = locale; - } - - /** - * {@inheritDoc} - */ - @Override - public int hashCode() { - return (mStyle * 31 + mLocale.hashCode() ) * 31 + mTimeZone.hashCode(); - } - - /** - * {@inheritDoc} - */ - @Override - public boolean equals(final Object obj) { - if (this == obj) { - return true; - } - if (obj instanceof TimeZoneDisplayKey) { - final TimeZoneDisplayKey other = (TimeZoneDisplayKey) obj; - return - mTimeZone.equals(other.mTimeZone) && - mStyle == other.mStyle && - mLocale.equals(other.mLocale); - } - return false; - } - } -} \ No newline at end of file diff --git a/dubbo-common/src/main/java/org/apache/dubbo/common/time/FastTimeZone.java b/dubbo-common/src/main/java/org/apache/dubbo/common/time/FastTimeZone.java deleted file mode 100644 index 9babe929048..00000000000 --- a/dubbo-common/src/main/java/org/apache/dubbo/common/time/FastTimeZone.java +++ /dev/null @@ -1,97 +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.common.time; - -import java.util.TimeZone; -import java.util.regex.Matcher; -import java.util.regex.Pattern; - -/** - * Faster methods to produce custom time zones. - * - * @since 3.7 - */ -public class FastTimeZone { - public static final String GMT_ID = "GMT"; - private static final Pattern GMT_PATTERN = Pattern.compile("^(?:(?i)GMT)?([+-])?(\\d\\d?)?(:?(\\d\\d?))?$"); - - private static final TimeZone GREENWICH = new GmtTimeZone(false, 0, 0); - - /** - * Gets the GMT TimeZone. - * - * @return A TimeZone with a raw offset of zero. - */ - public static TimeZone getGmtTimeZone() { - return GREENWICH; - } - - /** - * Gets a TimeZone with GMT offsets. A GMT offset must be either 'Z', or 'UTC', or match - * (GMT)? hh?(:?mm?)?, where h and m are digits representing hours and minutes. - * - * @param pattern The GMT offset - * @return A TimeZone with offset from GMT or null, if pattern does not match. - */ - public static TimeZone getGmtTimeZone(final String pattern) { - if ("Z".equals(pattern) || "UTC".equals(pattern)) { - return GREENWICH; - } - - final Matcher m = GMT_PATTERN.matcher(pattern); - if (m.matches()) { - final int hours = parseInt(m.group(2)); - final int minutes = parseInt(m.group(4)); - if (hours == 0 && minutes == 0) { - return GREENWICH; - } - return new GmtTimeZone(parseSign(m.group(1)), hours, minutes); - } - return null; - } - - /** - * Gets a TimeZone, looking first for GMT custom ids, then falling back to Olson ids. - * A GMT custom id can be 'Z', or 'UTC', or has an optional prefix of GMT, - * followed by sign, hours digit(s), optional colon(':'), and optional minutes digits. - * i.e. [GMT] (+|-) Hours [[:] Minutes] - * - * @param id A GMT custom id (or Olson id - * @return A timezone - */ - public static TimeZone getTimeZone(final String id) { - final TimeZone tz = getGmtTimeZone(id); - if (tz != null) { - return tz; - } - return TimeZone.getTimeZone(id); - } - - private static int parseInt(final String group) { - return group != null ? Integer.parseInt(group) : 0; - } - - private static boolean parseSign(final String group) { - return group != null && group.charAt(0) == '-'; - } - - // do not instantiate - private FastTimeZone() { - } - - -} \ No newline at end of file diff --git a/dubbo-common/src/main/java/org/apache/dubbo/common/time/FormatCache.java b/dubbo-common/src/main/java/org/apache/dubbo/common/time/FormatCache.java deleted file mode 100644 index 8aa1f908f59..00000000000 --- a/dubbo-common/src/main/java/org/apache/dubbo/common/time/FormatCache.java +++ /dev/null @@ -1,211 +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.common.time; - -import org.apache.dubbo.common.utils.Assert; - -import java.text.DateFormat; -import java.text.Format; -import java.text.SimpleDateFormat; -import java.util.Arrays; -import java.util.Locale; -import java.util.TimeZone; -import java.util.concurrent.ConcurrentHashMap; -import java.util.concurrent.ConcurrentMap; - -/** - *

FormatCache is a cache and factory for {@link Format}s.

- */ -// TODO: Before making public move from getDateTimeInstance(Integer, ...) to int; or some other approach. -abstract class FormatCache { - - /** - * No date or no time. Used in same parameters as DateFormat.SHORT or DateFormat.LONG - */ - static final int NONE= -1; - - private final ConcurrentMap cInstanceCache - = new ConcurrentHashMap<>(7); - - private static final ConcurrentMap cDateTimeInstanceCache - = new ConcurrentHashMap<>(7); - - /** - *

Gets a formatter instance using the default pattern in the - * default timezone and locale.

- * - * @return a date/time formatter - */ - public F getInstance() { - return getDateTimeInstance(DateFormat.SHORT, DateFormat.SHORT, TimeZone.getDefault(), Locale.getDefault()); - } - - /** - *

Gets a formatter instance using the specified pattern, time zone - * and locale.

- * - * @param pattern {@link java.text.SimpleDateFormat} compatible - * pattern, non-null - * @param timeZone the time zone, null means use the default TimeZone - * @param locale the locale, null means use the default Locale - * @return a pattern based date/time formatter - * @throws IllegalArgumentException if pattern is invalid - * or null - */ - public F getInstance(final String pattern, TimeZone timeZone, Locale locale) { - Assert.notNull(pattern, "Pattern must not be null"); - if (timeZone == null) { - timeZone = TimeZone.getDefault(); - } - if (locale == null) { - locale = Locale.getDefault(); - } - final MultipartKey key = new MultipartKey(pattern, timeZone, locale); - F format = cInstanceCache.get(key); - if (format == null) { - format = createInstance(pattern, timeZone, locale); - final F previousValue= cInstanceCache.putIfAbsent(key, format); - if (previousValue != null) { - // another thread snuck in and did the same work - // we should return the instance that is in ConcurrentMap - format= previousValue; - } - } - return format; - } - - /** - *

Create a format instance using the specified pattern, time zone - * and locale.

- * - * @param pattern {@link java.text.SimpleDateFormat} compatible pattern, this will not be null. - * @param timeZone time zone, this will not be null. - * @param locale locale, this will not be null. - * @return a pattern based date/time formatter - * @throws IllegalArgumentException if pattern is invalid - * or null - */ - protected abstract F createInstance(String pattern, TimeZone timeZone, Locale locale); - - /** - *

Gets a date/time formatter instance using the specified style, - * time zone and locale.

- * - * @param dateStyle date style: FULL, LONG, MEDIUM, or SHORT, null indicates no date in format - * @param timeStyle time style: FULL, LONG, MEDIUM, or SHORT, null indicates no time in format - * @param timeZone optional time zone, overrides time zone of - * formatted date, null means use default Locale - * @param locale optional locale, overrides system locale - * @return a localized standard date/time formatter - * @throws IllegalArgumentException if the Locale has no date/time - * pattern defined - */ - // This must remain private, see LANG-884 - private F getDateTimeInstance(final Integer dateStyle, final Integer timeStyle, final TimeZone timeZone, Locale locale) { - if (locale == null) { - locale = Locale.getDefault(); - } - final String pattern = getPatternForStyle(dateStyle, timeStyle, locale); - return getInstance(pattern, timeZone, locale); - } - - - /** - *

Gets a date/time format for the specified styles and locale.

- * - * @param dateStyle date style: FULL, LONG, MEDIUM, or SHORT, null indicates no date in format - * @param timeStyle time style: FULL, LONG, MEDIUM, or SHORT, null indicates no time in format - * @param locale The non-null locale of the desired format - * @return a localized standard date/time format - * @throws IllegalArgumentException if the Locale has no date/time pattern defined - */ - // package protected, for access from test code; do not make public or protected - static String getPatternForStyle(final Integer dateStyle, final Integer timeStyle, final Locale locale) { - final MultipartKey key = new MultipartKey(dateStyle, timeStyle, locale); - - String pattern = cDateTimeInstanceCache.get(key); - if (pattern == null) { - try { - DateFormat formatter; - if (dateStyle == null) { - formatter = DateFormat.getTimeInstance(timeStyle.intValue(), locale); - } else if (timeStyle == null) { - formatter = DateFormat.getDateInstance(dateStyle.intValue(), locale); - } else { - formatter = DateFormat.getDateTimeInstance(dateStyle.intValue(), timeStyle.intValue(), locale); - } - pattern = ((SimpleDateFormat) formatter).toPattern(); - final String previous = cDateTimeInstanceCache.putIfAbsent(key, pattern); - if (previous != null) { - // even though it doesn't matter if another thread put the pattern - // it's still good practice to return the String instance that is - // actually in the ConcurrentMap - pattern= previous; - } - } catch (final ClassCastException ex) { - throw new IllegalArgumentException("No date time pattern for locale: " + locale); - } - } - return pattern; - } - - // ---------------------------------------------------------------------- - /** - *

Helper class to hold multi-part Map keys

- */ - private static class MultipartKey { - private final Object[] keys; - private int hashCode; - - /** - * Constructs an instance of MultipartKey to hold the specified objects. - * @param keys the set of objects that make up the key. Each key may be null. - */ - MultipartKey(final Object... keys) { - this.keys = keys; - } - - /** - * {@inheritDoc} - */ - @Override - public boolean equals(final Object obj) { - // Eliminate the usual boilerplate because - // this inner static class is only used in a generic ConcurrentHashMap - // which will not compare against other Object types - return Arrays.equals(keys, ((MultipartKey) obj).keys); - } - - /** - * {@inheritDoc} - */ - @Override - public int hashCode() { - if (hashCode==0) { - int rc= 0; - for (final Object key : keys) { - if (key!=null) { - rc= rc*7 + key.hashCode(); - } - } - hashCode= rc; - } - return hashCode; - } - } - -} \ No newline at end of file diff --git a/dubbo-common/src/main/java/org/apache/dubbo/common/time/GmtTimeZone.java b/dubbo-common/src/main/java/org/apache/dubbo/common/time/GmtTimeZone.java deleted file mode 100644 index da0ba8b4afa..00000000000 --- a/dubbo-common/src/main/java/org/apache/dubbo/common/time/GmtTimeZone.java +++ /dev/null @@ -1,104 +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.common.time; - -import java.util.Date; -import java.util.TimeZone; - -/** - * Custom timezone that contains offset from GMT. - */ -class GmtTimeZone extends TimeZone { - - private static final int MILLISECONDS_PER_MINUTE = 60 * 1000; - private static final int MINUTES_PER_HOUR = 60; - private static final int HOURS_PER_DAY = 24; - - // Serializable! - static final long serialVersionUID = 1L; - - private final int offset; - private final String zoneId; - - GmtTimeZone(final boolean negate, final int hours, final int minutes) { - if (hours >= HOURS_PER_DAY) { - throw new IllegalArgumentException(hours + " hours out of range"); - } - if (minutes >= MINUTES_PER_HOUR) { - throw new IllegalArgumentException(minutes + " minutes out of range"); - } - final int milliseconds = (minutes + (hours * MINUTES_PER_HOUR)) * MILLISECONDS_PER_MINUTE; - offset = negate ? -milliseconds : milliseconds; - zoneId = twoDigits( - twoDigits(new StringBuilder(9).append("GMT").append(negate ? '-' : '+'), hours) - .append(':'), minutes).toString(); - - } - - private static StringBuilder twoDigits(final StringBuilder sb, final int n) { - return sb.append((char) ('0' + (n / 10))).append((char) ('0' + (n % 10))); - } - - @Override - public int getOffset(final int era, final int year, final int month, final int day, final int dayOfWeek, final int milliseconds) { - return offset; - } - - @Override - public void setRawOffset(final int offsetMillis) { - throw new UnsupportedOperationException(); - } - - @Override - public int getRawOffset() { - return offset; - } - - @Override - public String getID() { - return zoneId; - } - - @Override - public boolean useDaylightTime() { - return false; - } - - @Override - public boolean inDaylightTime(final Date date) { - return false; - } - - @Override - public String toString() { - return "[GmtTimeZone id=\"" + zoneId + "\",offset=" + offset + ']'; - } - - @Override - public int hashCode() { - return offset; - } - - @Override - public boolean equals(final Object other) { - if (!(other instanceof GmtTimeZone)) { - return false; - } - return zoneId == ((GmtTimeZone) other).zoneId; - } -} \ No newline at end of file diff --git a/dubbo-common/src/main/java/org/apache/dubbo/common/utils/DateUtil.java b/dubbo-common/src/main/java/org/apache/dubbo/common/utils/DateUtil.java deleted file mode 100644 index 2c4e8361039..00000000000 --- a/dubbo-common/src/main/java/org/apache/dubbo/common/utils/DateUtil.java +++ /dev/null @@ -1,43 +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.common.utils; - -import org.apache.dubbo.common.time.FastDateFormat; - -import java.util.Date; - -/** - * This class is utility to provide dubbo date formatting and parsing. - */ -public final class DateUtil { - - private DateUtil() { - - }; - - /** - * This method used to return a formatted string of a given date object. - * @param date Input data object - * @param format format of data. - * @return - */ - public static String format(Date date, String format) { - Assert.notNull(date, "Given date can't be null"); - Assert.notEmptyString(format, "Given date format can't be null or empty"); - return FastDateFormat.getInstance(format).format(date); - } -} diff --git a/dubbo-common/src/main/java/org/apache/dubbo/common/utils/DubboAppender.java b/dubbo-common/src/main/java/org/apache/dubbo/common/utils/DubboAppender.java index da3968e9f6e..e2b1940a7e4 100644 --- a/dubbo-common/src/main/java/org/apache/dubbo/common/utils/DubboAppender.java +++ b/dubbo-common/src/main/java/org/apache/dubbo/common/utils/DubboAppender.java @@ -16,17 +16,24 @@ */ package org.apache.dubbo.common.utils; -import org.apache.log4j.ConsoleAppender; +import org.apache.log4j.FileAppender; import org.apache.log4j.spi.LoggingEvent; import java.util.ArrayList; import java.util.List; -public class DubboAppender extends ConsoleAppender { +public class DubboAppender extends FileAppender { + + private static final String DEFAULT_FILE_NAME = "dubbo.log"; + + public DubboAppender() { + super(); + setFile(DEFAULT_FILE_NAME); + } public static boolean available = false; - public static List logList = new ArrayList(); + public static List logList = new ArrayList<>(); public static void doStart() { available = true; diff --git a/dubbo-common/src/main/java/org/apache/dubbo/common/utils/NetUtils.java b/dubbo-common/src/main/java/org/apache/dubbo/common/utils/NetUtils.java index fafe1518f91..06450e2ef72 100644 --- a/dubbo-common/src/main/java/org/apache/dubbo/common/utils/NetUtils.java +++ b/dubbo-common/src/main/java/org/apache/dubbo/common/utils/NetUtils.java @@ -22,9 +22,11 @@ import org.apache.dubbo.common.logger.LoggerFactory; import java.io.IOException; +import java.net.Inet4Address; import java.net.Inet6Address; import java.net.InetAddress; import java.net.InetSocketAddress; +import java.net.MulticastSocket; import java.net.NetworkInterface; import java.net.ServerSocket; import java.net.UnknownHostException; @@ -343,4 +345,34 @@ public static String toURL(String protocol, String host, int port, String path) return sb.toString(); } -} \ No newline at end of file + public static void joinMulticastGroup (MulticastSocket multicastSocket, InetAddress multicastAddress) throws IOException { + setInterface(multicastSocket, multicastAddress instanceof Inet6Address); + multicastSocket.setLoopbackMode(false); + multicastSocket.joinGroup(multicastAddress); + } + + public static void setInterface (MulticastSocket multicastSocket, boolean preferIpv6) throws IOException{ + boolean interfaceSet = false; + Enumeration interfaces = NetworkInterface.getNetworkInterfaces(); + while (interfaces.hasMoreElements()) { + NetworkInterface i = (NetworkInterface) interfaces.nextElement(); + Enumeration addresses = i.getInetAddresses(); + while (addresses.hasMoreElements()) { + InetAddress address = (InetAddress) addresses.nextElement(); + if (preferIpv6 && address instanceof Inet6Address) { + multicastSocket.setInterface(address); + interfaceSet = true; + break; + } else if (!preferIpv6 && address instanceof Inet4Address) { + multicastSocket.setInterface(address); + interfaceSet = true; + break; + } + } + if (interfaceSet) { + break; + } + } + } + +} diff --git a/dubbo-common/src/main/java/org/apache/dubbo/common/utils/PojoUtils.java b/dubbo-common/src/main/java/org/apache/dubbo/common/utils/PojoUtils.java index 2198709fb73..18998dc6239 100644 --- a/dubbo-common/src/main/java/org/apache/dubbo/common/utils/PojoUtils.java +++ b/dubbo-common/src/main/java/org/apache/dubbo/common/utils/PojoUtils.java @@ -520,7 +520,14 @@ private static Object newInstance(Class cls) { } catch (Throwable t) { try { Constructor[] constructors = cls.getDeclaredConstructors(); - if (constructors != null && constructors.length == 0) { + /** + * From Javadoc java.lang.Class#getDeclaredConstructors + * This method returns an array of Constructor objects reflecting all the constructors + * declared by the class represented by this Class object. + * This method returns an array of length 0, + * if this Class object represents an interface, a primitive type, an array class, or void. + */ + if (constructors.length == 0) { throw new RuntimeException("Illegal constructor: " + cls.getName()); } Constructor constructor = constructors[0]; diff --git a/dubbo-common/src/main/java/org/apache/dubbo/common/utils/UrlUtils.java b/dubbo-common/src/main/java/org/apache/dubbo/common/utils/UrlUtils.java index 5c157c5a03f..23b50339f4c 100644 --- a/dubbo-common/src/main/java/org/apache/dubbo/common/utils/UrlUtils.java +++ b/dubbo-common/src/main/java/org/apache/dubbo/common/utils/UrlUtils.java @@ -467,6 +467,19 @@ public static boolean isProvider(URL url) { PROVIDERS_CATEGORY.equals(url.getParameter(CATEGORY_KEY, PROVIDERS_CATEGORY)); } + public static int getHeartbeat(URL url) { + return url.getParameter(Constants.HEARTBEAT_KEY, Constants.DEFAULT_HEARTBEAT); + } + + public static int getIdleTimeout(URL url) { + int heartBeat = getHeartbeat(url); + int idleTimeout = url.getParameter(Constants.HEARTBEAT_TIMEOUT_KEY, heartBeat * 3); + if (idleTimeout < heartBeat * 2) { + throw new IllegalStateException("idleTimeout < heartbeatInterval * 2"); + } + return idleTimeout; + } + /** * Check if the given value matches the given pattern. The pattern supports wildcard "*". * diff --git a/dubbo-common/src/test/java/org/apache/dubbo/common/concurrent/ExecutionListTest.java b/dubbo-common/src/test/java/org/apache/dubbo/common/concurrent/ExecutionListTest.java deleted file mode 100644 index a1675aca07f..00000000000 --- a/dubbo-common/src/test/java/org/apache/dubbo/common/concurrent/ExecutionListTest.java +++ /dev/null @@ -1,95 +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.common.concurrent; - -import org.junit.jupiter.api.Assertions; -import org.junit.jupiter.api.BeforeEach; -import org.junit.jupiter.api.Test; - -import java.util.concurrent.CountDownLatch; -import java.util.concurrent.Executor; - -import static org.mockito.ArgumentMatchers.any; -import static org.mockito.Mockito.doThrow; -import static org.mockito.Mockito.mock; -import static org.mockito.Mockito.times; -import static org.mockito.Mockito.verify; - -public class ExecutionListTest { - private ExecutionList executionList; - - @BeforeEach - public void setUp() throws Exception { - this.executionList = new ExecutionList(); - } - - @Test - public void testAddNullRunnable() { - Assertions.assertThrows(NullPointerException.class, () -> this.executionList.add(null, mock(Executor.class))); - } - - @Test - public void testAddRunnableToExecutor() { - Executor mockedExecutor = mock(Executor.class); - - this.executionList.add(mock(Runnable.class), mockedExecutor); - this.executionList.execute(); - - verify(mockedExecutor).execute(any(Runnable.class)); - } - - @Test - public void testExecuteRunnableWithDefaultExecutor() throws InterruptedException { - final CountDownLatch countDownLatch = new CountDownLatch(1); - this.executionList.add(countDownLatch::countDown, null); - - this.executionList.execute(); - countDownLatch.await(); - } - - @Test - public void testExceptionForExecutor() { - Executor mockedExecutor = mock(Executor.class); - doThrow(new RuntimeException()).when(mockedExecutor).execute(any(Runnable.class)); - - this.executionList.add(mock(Runnable.class), mockedExecutor); - this.executionList.execute(); - } - - @Test - public void testNotRunSameRunnableTwice() { - Executor mockedExecutor = mock(Executor.class); - - this.executionList.add(mock(Runnable.class), mockedExecutor); - - this.executionList.execute(); - this.executionList.execute(); - - verify(mockedExecutor).execute(any(Runnable.class)); - } - - @Test - public void testRunImmediatelyAfterExecuted() { - Executor mockedExecutor = mock(Executor.class); - - this.executionList.add(mock(Runnable.class), mockedExecutor); - this.executionList.execute(); - this.executionList.add(mock(Runnable.class), mockedExecutor); - - verify(mockedExecutor, times(2)).execute(any(Runnable.class)); - } -} \ No newline at end of file diff --git a/dubbo-common/src/test/java/org/apache/dubbo/common/extension/ExtensionLoaderTest.java b/dubbo-common/src/test/java/org/apache/dubbo/common/extension/ExtensionLoaderTest.java index 3f767e802b0..b0e878ce60e 100644 --- a/dubbo-common/src/test/java/org/apache/dubbo/common/extension/ExtensionLoaderTest.java +++ b/dubbo-common/src/test/java/org/apache/dubbo/common/extension/ExtensionLoaderTest.java @@ -87,7 +87,7 @@ public void test_getExtensionLoader_NotInterface() throws Exception { fail(); } catch (IllegalArgumentException expected) { assertThat(expected.getMessage(), - containsString("Extension type(class org.apache.dubbo.common.extension.ExtensionLoaderTest) is not interface")); + containsString("Extension type (class org.apache.dubbo.common.extension.ExtensionLoaderTest) is not interface")); } } @@ -263,7 +263,7 @@ public void test_AddExtension_ExceptionWhenExistedExtension() throws Exception { ExtensionLoader.getExtensionLoader(AddExt1.class).addExtension("impl1", AddExt1_ManualAdd1.class); fail(); } catch (IllegalStateException expected) { - assertThat(expected.getMessage(), containsString("Extension name impl1 already existed(Extension interface org.apache.dubbo.common.extension.ext8_add.AddExt1)!")); + assertThat(expected.getMessage(), containsString("Extension name impl1 already exists (Extension interface org.apache.dubbo.common.extension.ext8_add.AddExt1)!")); } } @@ -286,7 +286,7 @@ public void test_AddExtension_Adaptive_ExceptionWhenExistedAdaptive() throws Exc loader.addExtension(null, AddExt1_ManualAdaptive.class); fail(); } catch (IllegalStateException expected) { - assertThat(expected.getMessage(), containsString("Adaptive Extension already existed(Extension interface org.apache.dubbo.common.extension.ext8_add.AddExt1)!")); + assertThat(expected.getMessage(), containsString("Adaptive Extension already exists (Extension interface org.apache.dubbo.common.extension.ext8_add.AddExt1)!")); } } @@ -335,7 +335,7 @@ public void test_replaceExtension_ExceptionWhenNotExistedExtension() throws Exce ExtensionLoader.getExtensionLoader(AddExt1.class).replaceExtension("NotExistedExtension", AddExt1_ManualAdd1.class); fail(); } catch (IllegalStateException expected) { - assertThat(expected.getMessage(), containsString("Extension name NotExistedExtension not existed(Extension interface org.apache.dubbo.common.extension.ext8_add.AddExt1)")); + assertThat(expected.getMessage(), containsString("Extension name NotExistedExtension doesn't exist (Extension interface org.apache.dubbo.common.extension.ext8_add.AddExt1)")); } } @@ -347,7 +347,7 @@ public void test_replaceExtension_Adaptive_ExceptionWhenNotExistedExtension() th loader.replaceExtension(null, AddExt4_ManualAdaptive.class); fail(); } catch (IllegalStateException expected) { - assertThat(expected.getMessage(), containsString("Adaptive Extension not existed(Extension interface org.apache.dubbo.common.extension.ext8_add.AddExt4)")); + assertThat(expected.getMessage(), containsString("Adaptive Extension doesn't exist (Extension interface org.apache.dubbo.common.extension.ext8_add.AddExt4)")); } } @@ -361,7 +361,7 @@ public void test_InitError() throws Exception { loader.getExtension("error"); fail(); } catch (IllegalStateException expected) { - assertThat(expected.getMessage(), containsString("Failed to load extension class(interface: interface org.apache.dubbo.common.extension.ext7.InitErrorExt")); + assertThat(expected.getMessage(), containsString("Failed to load extension class (interface: interface org.apache.dubbo.common.extension.ext7.InitErrorExt")); assertThat(expected.getCause(), instanceOf(ExceptionInInitializerError.class)); } } @@ -437,4 +437,4 @@ public void testInjectExtension() { Assertions.assertNull(injectExtImpl.getGenericType()); } -} \ No newline at end of file +} diff --git a/dubbo-common/src/test/java/org/apache/dubbo/common/extension/ExtensionLoader_Adaptive_Test.java b/dubbo-common/src/test/java/org/apache/dubbo/common/extension/ExtensionLoader_Adaptive_Test.java index b4db6d49d23..fe64a63b6ed 100644 --- a/dubbo-common/src/test/java/org/apache/dubbo/common/extension/ExtensionLoader_Adaptive_Test.java +++ b/dubbo-common/src/test/java/org/apache/dubbo/common/extension/ExtensionLoader_Adaptive_Test.java @@ -147,8 +147,8 @@ public void test_getAdaptiveExtension_ExceptionWhenNoAdaptiveMethodOnInterface() fail(); } catch (IllegalStateException expected) { assertThat(expected.getMessage(), - allOf(containsString("Can not create adaptive extension interface org.apache.dubbo.common.extension.ext5.NoAdaptiveMethodExt"), - containsString("No adaptive method on extension org.apache.dubbo.common.extension.ext5.NoAdaptiveMethodExt, refuse to create the adaptive class"))); + allOf(containsString("Can't create adaptive extension interface org.apache.dubbo.common.extension.ext5.NoAdaptiveMethodExt"), + containsString("No adaptive method exist on extension org.apache.dubbo.common.extension.ext5.NoAdaptiveMethodExt, refuse to create the adaptive class"))); } // report same error when get is invoked for multiple times try { @@ -156,8 +156,8 @@ public void test_getAdaptiveExtension_ExceptionWhenNoAdaptiveMethodOnInterface() fail(); } catch (IllegalStateException expected) { assertThat(expected.getMessage(), - allOf(containsString("Can not create adaptive extension interface org.apache.dubbo.common.extension.ext5.NoAdaptiveMethodExt"), - containsString("No adaptive method on extension org.apache.dubbo.common.extension.ext5.NoAdaptiveMethodExt, refuse to create the adaptive class"))); + allOf(containsString("Can't create adaptive extension interface org.apache.dubbo.common.extension.ext5.NoAdaptiveMethodExt"), + containsString("No adaptive method exist on extension org.apache.dubbo.common.extension.ext5.NoAdaptiveMethodExt, refuse to create the adaptive class"))); } } @@ -185,7 +185,7 @@ public void test_getAdaptiveExtension_ExceptionWhenNoUrlAttribute() throws Excep ExtensionLoader.getExtensionLoader(NoUrlParamExt.class).getAdaptiveExtension(); fail(); } catch (Exception expected) { - assertThat(expected.getMessage(), containsString("fail to create adaptive class for interface ")); + assertThat(expected.getMessage(), containsString("Failed to create adaptive class for interface ")); assertThat(expected.getMessage(), containsString(": not found url parameter or url attribute in parameters of method ")); } } @@ -218,7 +218,7 @@ public void test_urlHolder_getAdaptiveExtension_noExtension() throws Exception { ext.echo(holder, "haha"); fail(); } catch (IllegalStateException expected) { - assertThat(expected.getMessage(), containsString("Fail to get extension(")); + assertThat(expected.getMessage(), containsString("Failed to get extension")); } url = url.addParameter("ext2", "XXX"); @@ -281,7 +281,7 @@ public void test_urlHolder_getAdaptiveExtension_ExceptionWhenNameNotProvided() t ext.echo(holder, "impl1"); fail(); } catch (IllegalStateException expected) { - assertThat(expected.getMessage(), containsString("Fail to get extension(")); + assertThat(expected.getMessage(), containsString("Failed to get extension")); } url = url.addParameter("key1", "impl1"); @@ -290,7 +290,7 @@ public void test_urlHolder_getAdaptiveExtension_ExceptionWhenNameNotProvided() t ext.echo(holder, "haha"); fail(); } catch (IllegalStateException expected) { - assertThat(expected.getMessage(), containsString("Fail to get extension(org.apache.dubbo.common.extension.ext2.Ext2) name from url")); + assertThat(expected.getMessage(), containsString("Failed to get extension (org.apache.dubbo.common.extension.ext2.Ext2) name from url")); } } @@ -319,4 +319,4 @@ public void test_getAdaptiveExtension_InjectNotExtFail() throws Exception { Ext6Impl2 impl = (Ext6Impl2) ext; assertNull(impl.getList()); } -} \ No newline at end of file +} diff --git a/dubbo-common/src/test/java/org/apache/dubbo/common/logger/LoggerFactoryTest.java b/dubbo-common/src/test/java/org/apache/dubbo/common/logger/LoggerFactoryTest.java index b331f7683c8..25fce0ebdfd 100644 --- a/dubbo-common/src/test/java/org/apache/dubbo/common/logger/LoggerFactoryTest.java +++ b/dubbo-common/src/test/java/org/apache/dubbo/common/logger/LoggerFactoryTest.java @@ -58,4 +58,12 @@ public void testGetLogger() { assertThat(logger1, is(logger2)); } -} \ No newline at end of file + + @Test + public void shouldReturnSameLogger() { + Logger logger1 = LoggerFactory.getLogger(this.getClass().getName()); + Logger logger2 = LoggerFactory.getLogger(this.getClass().getName()); + + assertThat(logger1, is(logger2)); + } +} diff --git a/dubbo-common/src/test/java/org/apache/dubbo/common/version/VersionTest.java b/dubbo-common/src/test/java/org/apache/dubbo/common/version/VersionTest.java index 9cfd9d38700..10da6f047ad 100644 --- a/dubbo-common/src/test/java/org/apache/dubbo/common/version/VersionTest.java +++ b/dubbo-common/src/test/java/org/apache/dubbo/common/version/VersionTest.java @@ -35,4 +35,32 @@ public void testSupportResponseAttachment() { Assertions.assertTrue(Version.isSupportResponseAttachment("2.0.3")); Assertions.assertFalse(Version.isSupportResponseAttachment("2.0.0")); } + + @Test + public void testGetIntVersion() { + Assertions.assertEquals(2060100, Version.getIntVersion("2.6.1")); + Assertions.assertEquals(2060101, Version.getIntVersion("2.6.1.1")); + Assertions.assertEquals(2070001, Version.getIntVersion("2.7.0.1")); + Assertions.assertEquals(2070000, Version.getIntVersion("2.7.0")); + } + + @Test + public void testIsFramework270OrHigher() { + Assertions.assertTrue(Version.isRelease270OrHigher("2.7.0")); + Assertions.assertTrue(Version.isRelease270OrHigher("2.7.0.1")); + Assertions.assertTrue(Version.isRelease270OrHigher("2.7.0.2")); + Assertions.assertTrue(Version.isRelease270OrHigher("2.8.0")); + Assertions.assertFalse(Version.isRelease270OrHigher("2.6.3")); + Assertions.assertFalse(Version.isRelease270OrHigher("2.6.3.1")); + } + + @Test + public void testIsFramework263OrHigher() { + Assertions.assertTrue(Version.isRelease263OrHigher("2.7.0")); + Assertions.assertTrue(Version.isRelease263OrHigher("2.7.0.1")); + Assertions.assertTrue(Version.isRelease263OrHigher("2.6.4")); + Assertions.assertFalse(Version.isRelease263OrHigher("2.6.2")); + Assertions.assertFalse(Version.isRelease263OrHigher("2.6.1.1")); + Assertions.assertTrue(Version.isRelease263OrHigher("2.6.3")); + } } diff --git a/dubbo-common/src/test/resources/log4j.xml b/dubbo-common/src/test/resources/log4j.xml index f5da181b5e3..bfb523c0cc3 100644 --- a/dubbo-common/src/test/resources/log4j.xml +++ b/dubbo-common/src/test/resources/log4j.xml @@ -1,18 +1,19 @@ @@ -20,6 +21,7 @@ + diff --git a/dubbo-compatible/pom.xml b/dubbo-compatible/pom.xml index 95be7103936..43d14f95104 100644 --- a/dubbo-compatible/pom.xml +++ b/dubbo-compatible/pom.xml @@ -20,7 +20,7 @@ org.apache.dubbo dubbo-parent - 2.7.0-SNAPSHOT + 2.7.1-SNAPSHOT dubbo-compatible jar @@ -79,6 +79,24 @@ ${project.parent.version} test
+ + org.apache.dubbo + dubbo-registry-zookeeper + ${project.parent.version} + test + + + org.apache.dubbo + dubbo-configcenter-zookeeper + ${project.parent.version} + test + + + org.apache.dubbo + dubbo-metadata-report-zookeeper + ${project.parent.version} + test + com.alibaba fastjson diff --git a/dubbo-compatible/src/main/java/com/alibaba/dubbo/common/URL.java b/dubbo-compatible/src/main/java/com/alibaba/dubbo/common/URL.java index 255481f82a1..42bab293018 100644 --- a/dubbo-compatible/src/main/java/com/alibaba/dubbo/common/URL.java +++ b/dubbo-compatible/src/main/java/com/alibaba/dubbo/common/URL.java @@ -27,6 +27,10 @@ @Deprecated public class URL extends org.apache.dubbo.common.URL { + protected URL() { + super(); + } + public URL(org.apache.dubbo.common.URL url) { super(url.getProtocol(), url.getUsername(), url.getPassword(), url.getHost(), url.getPort(), url.getPath(), url.getParameters()); } diff --git a/dubbo-compatible/src/main/java/com/alibaba/dubbo/rpc/Protocol.java b/dubbo-compatible/src/main/java/com/alibaba/dubbo/rpc/Protocol.java index 34d56a8e743..18035416da2 100644 --- a/dubbo-compatible/src/main/java/com/alibaba/dubbo/rpc/Protocol.java +++ b/dubbo-compatible/src/main/java/com/alibaba/dubbo/rpc/Protocol.java @@ -17,6 +17,22 @@ package com.alibaba.dubbo.rpc; +import com.alibaba.dubbo.common.URL; + @Deprecated public interface Protocol extends org.apache.dubbo.rpc.Protocol { + + Exporter export(Invoker invoker) throws RpcException; + + Invoker refer(Class aClass, URL url) throws RpcException; + + @Override + default org.apache.dubbo.rpc.Exporter export(org.apache.dubbo.rpc.Invoker invoker) throws RpcException { + return this.export(new Invoker.CompatibleInvoker<>(invoker)); + } + + @Override + default org.apache.dubbo.rpc.Invoker refer(Class aClass, org.apache.dubbo.common.URL url) throws RpcException { + return this.refer(aClass, new URL(url)); + } } diff --git a/dubbo-compatible/src/main/java/com/alibaba/dubbo/rpc/cluster/Router.java b/dubbo-compatible/src/main/java/com/alibaba/dubbo/rpc/cluster/Router.java index 2fb30d1bb35..d8822bcd86e 100644 --- a/dubbo-compatible/src/main/java/com/alibaba/dubbo/rpc/cluster/Router.java +++ b/dubbo-compatible/src/main/java/com/alibaba/dubbo/rpc/cluster/Router.java @@ -26,7 +26,7 @@ import java.util.stream.Collectors; @Deprecated -public interface Router extends org.apache.dubbo.rpc.cluster.Router { +public interface Router extends org.apache.dubbo.rpc.cluster.Router{ @Override com.alibaba.dubbo.common.URL getUrl(); @@ -36,7 +36,7 @@ List> route(List { + // Ignore those fields + static final String[] IGNORE_FIELD_NAMES = of("application", "module", "consumer", "monitor", "registry"); + private CompatibleReferenceBeanBuilder(Reference annotation, ClassLoader classLoader, ApplicationContext applicationContext) { super(annotation, classLoader, applicationContext); } @@ -96,20 +99,30 @@ protected ReferenceBean doBuild() { protected void preConfigureBean(Reference reference, ReferenceBean referenceBean) { Assert.notNull(interfaceClass, "The interface class must set first!"); DataBinder dataBinder = new DataBinder(referenceBean); - // Set ConversionService - dataBinder.setConversionService(getConversionService()); - // Ignore those fields - String[] ignoreAttributeNames = of("application", "module", "consumer", "monitor", "registry"); -// dataBinder.setDisallowedFields(ignoreAttributeNames); + // Register CustomEditors for special fields + dataBinder.registerCustomEditor(String.class, "filter", new StringTrimmerEditor(true)); + dataBinder.registerCustomEditor(String.class, "listener", new StringTrimmerEditor(true)); + dataBinder.registerCustomEditor(Map.class, "parameters", new PropertyEditorSupport() { + @Override + public void setAsText(String text) throws java.lang.IllegalArgumentException { + // Trim all whitespace + String content = StringUtils.trimAllWhitespace(text); + if (!StringUtils.hasText(content)) { // No content , ignore directly + return; + } + // replace "=" to "," + content = StringUtils.replace(content, "=", ","); + // replace ":" to "," + content = StringUtils.replace(content, ":", ","); + // String[] to Map + Map parameters = CollectionUtils.toStringMap(commaDelimitedListToStringArray(content)); + setValue(parameters); + } + }); + // Bind annotation attributes - dataBinder.bind(new AnnotationPropertyValuesAdapter(reference, applicationContext.getEnvironment(), ignoreAttributeNames)); - } + dataBinder.bind(new AnnotationPropertyValuesAdapter(reference, applicationContext.getEnvironment(), IGNORE_FIELD_NAMES)); - private ConversionService getConversionService() { - DefaultConversionService conversionService = new DefaultConversionService(); - conversionService.addConverter(new StringArrayToStringConverter()); - conversionService.addConverter(new StringArrayToMapConverter()); - return conversionService; } diff --git a/dubbo-compatible/src/main/java/org/apache/dubbo/config/spring/schema/CompatibleAnnotationBeanDefinitionParser.java b/dubbo-compatible/src/main/java/org/apache/dubbo/config/spring/schema/CompatibleAnnotationBeanDefinitionParser.java index 66d6ac2dcc3..1172591190a 100644 --- a/dubbo-compatible/src/main/java/org/apache/dubbo/config/spring/schema/CompatibleAnnotationBeanDefinitionParser.java +++ b/dubbo-compatible/src/main/java/org/apache/dubbo/config/spring/schema/CompatibleAnnotationBeanDefinitionParser.java @@ -16,11 +16,9 @@ */ package org.apache.dubbo.config.spring.schema; -import org.apache.dubbo.config.spring.AnnotationBean; import org.apache.dubbo.config.spring.beans.factory.annotation.CompatibleReferenceAnnotationBeanPostProcessor; import org.apache.dubbo.config.spring.beans.factory.annotation.CompatibleServiceAnnotationBeanPostProcessor; import org.apache.dubbo.config.spring.util.BeanRegistrar; - import org.springframework.beans.factory.BeanFactory; import org.springframework.beans.factory.config.BeanDefinition; import org.springframework.beans.factory.support.BeanDefinitionBuilder; @@ -34,7 +32,7 @@ import static org.springframework.util.StringUtils.trimArrayElements; /** - * {@link AnnotationBean} {@link BeanDefinitionParser} + * {@link BeanDefinitionParser} * * @see CompatibleServiceAnnotationBeanPostProcessor * @see CompatibleReferenceAnnotationBeanPostProcessor diff --git a/dubbo-compatible/src/test/java/org/apache/dubbo/config/ConfigTest.java b/dubbo-compatible/src/test/java/org/apache/dubbo/config/ConfigTest.java index 0e44297fa5b..4aadd60cf12 100644 --- a/dubbo-compatible/src/test/java/org/apache/dubbo/config/ConfigTest.java +++ b/dubbo-compatible/src/test/java/org/apache/dubbo/config/ConfigTest.java @@ -17,38 +17,46 @@ package org.apache.dubbo.config; +import org.apache.dubbo.config.context.ConfigManager; import org.apache.dubbo.service.DemoService; import org.apache.dubbo.service.DemoServiceImpl; -import com.alibaba.dubbo.config.ApplicationConfig; import com.alibaba.dubbo.config.ReferenceConfig; -import com.alibaba.dubbo.config.RegistryConfig; import com.alibaba.dubbo.config.ServiceConfig; +import org.junit.jupiter.api.AfterEach; import org.junit.jupiter.api.Assertions; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; public class ConfigTest { + private com.alibaba.dubbo.config.ApplicationConfig applicationConfig = new com.alibaba.dubbo.config.ApplicationConfig("first-dubbo-test"); + private com.alibaba.dubbo.config.RegistryConfig registryConfig = new com.alibaba.dubbo.config.RegistryConfig("multicast://224.5.6.7:1234"); + + @AfterEach + public void tearDown() { + ConfigManager.getInstance().clear(); + } @BeforeEach public void setup() { // In IDE env, make sure adding the following argument to VM options System.setProperty("java.net.preferIPv4Stack", "true"); + ConfigManager.getInstance().clear(); } @Test public void testConfig() { com.alibaba.dubbo.config.ServiceConfig service = new ServiceConfig<>(); - service.setApplication(new com.alibaba.dubbo.config.ApplicationConfig("first-dubbo-provider")); - service.setRegistry(new com.alibaba.dubbo.config.RegistryConfig("multicast://224.5.6.7:1234")); + service.setApplication(applicationConfig); + service.setRegistry(registryConfig); service.setInterface(DemoService.class); service.setRef(new DemoServiceImpl()); service.export(); com.alibaba.dubbo.config.ReferenceConfig reference = new ReferenceConfig<>(); - reference.setApplication(new ApplicationConfig("first-dubbo-client")); - reference.setRegistry(new RegistryConfig("multicast://224.5.6.7:1234")); + reference.setApplication(applicationConfig); + reference.setRegistry(registryConfig); reference.setInterface(DemoService.class); DemoService demoService = reference.get(); String message = demoService.sayHello("dubbo"); diff --git a/dubbo-compatible/src/test/java/org/apache/dubbo/config/ReferenceConfigTest.java b/dubbo-compatible/src/test/java/org/apache/dubbo/config/ReferenceConfigTest.java index bff2fb226bd..a7139ed61b9 100644 --- a/dubbo-compatible/src/test/java/org/apache/dubbo/config/ReferenceConfigTest.java +++ b/dubbo-compatible/src/test/java/org/apache/dubbo/config/ReferenceConfigTest.java @@ -17,6 +17,7 @@ package org.apache.dubbo.config; +import org.apache.dubbo.config.context.ConfigManager; import org.apache.dubbo.service.DemoService; import org.apache.dubbo.service.DemoServiceImpl; @@ -26,19 +27,31 @@ import com.alibaba.dubbo.config.RegistryConfig; import com.alibaba.dubbo.config.ServiceConfig; +import org.junit.jupiter.api.AfterEach; +import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; public class ReferenceConfigTest { + private ApplicationConfig application = new ApplicationConfig(); + private RegistryConfig registry = new RegistryConfig(); + private ProtocolConfig protocol = new ProtocolConfig(); + + @BeforeEach + public void setUp() { + ConfigManager.getInstance().clear(); + } + + @AfterEach + public void tearDown() { + ConfigManager.getInstance().clear(); + } @Test public void testInjvm() throws Exception { - ApplicationConfig application = new ApplicationConfig(); - application.setName("test-protocol-random-port"); - RegistryConfig registry = new RegistryConfig(); + application.setName("test-protocol-random-port"); registry.setAddress("multicast://224.5.6.7:1234"); - ProtocolConfig protocol = new ProtocolConfig(); protocol.setName("dubbo"); ServiceConfig demoService; diff --git a/dubbo-compatible/src/test/java/org/apache/dubbo/generic/GenericServiceTest.java b/dubbo-compatible/src/test/java/org/apache/dubbo/generic/GenericServiceTest.java index b2f22390f6d..09d62cc067c 100644 --- a/dubbo-compatible/src/test/java/org/apache/dubbo/generic/GenericServiceTest.java +++ b/dubbo-compatible/src/test/java/org/apache/dubbo/generic/GenericServiceTest.java @@ -38,12 +38,11 @@ import org.junit.jupiter.api.Assertions; import org.junit.jupiter.api.Test; +import java.util.ArrayList; import java.util.Arrays; import java.util.HashMap; -import java.util.HashSet; import java.util.List; import java.util.Map; -import java.util.Set; public class GenericServiceTest { @@ -108,20 +107,20 @@ public void testGenericComplexCompute4FullServiceMetadata() { FullServiceDefinition fullServiceDefinition = ServiceDefinitionBuilder.buildFullDefinition(DemoService.class); MethodDefinition methodDefinition = getMethod("complexCompute", fullServiceDefinition.getMethods()); - Map parm2= createComplextObject(fullServiceDefinition,var1, var2, l, var3, var4, testEnum); - ComplexObject complexObject = map2bean(parm2); + Map mapObject = createComplexObject(fullServiceDefinition,var1, var2, l, var3, var4, testEnum); + ComplexObject complexObject = map2bean(mapObject); Invoker invoker = protocol.refer(GenericService.class, url); GenericService client = proxyFactory.getProxy(invoker, true); - Object result = client.$invoke(methodDefinition.getName(), methodDefinition.getParameterTypes(), new Object[]{"haha", parm2}); + Object result = client.$invoke(methodDefinition.getName(), methodDefinition.getParameterTypes(), new Object[]{"haha", mapObject}); Assertions.assertEquals("haha###" + complexObject.toString(), result); Invoker invoker2 = protocol.refer(DemoService.class, url); GenericService client2 = (GenericService) proxyFactory.getProxy(invoker2, true); - Object result2 = client2.$invoke("complexCompute", methodDefinition.getParameterTypes(), new Object[]{"haha2", parm2}); + Object result2 = client2.$invoke("complexCompute", methodDefinition.getParameterTypes(), new Object[]{"haha2", mapObject}); Assertions.assertEquals("haha2###" + complexObject.toString(), result2); invoker.destroy(); @@ -167,7 +166,7 @@ MethodDefinition getMethod(String methodName, List list) { return null; } - Map createComplextObject(FullServiceDefinition fullServiceDefinition, String var1, int var2, long l, String[] var3, List var4, ComplexObject.TestEnum testEnum) { + Map createComplexObject(FullServiceDefinition fullServiceDefinition, String var1, int var2, long l, String[] var3, List var4, ComplexObject.TestEnum testEnum) { List typeDefinitions = fullServiceDefinition.getTypes(); TypeDefinition topTypeDefinition = null; TypeDefinition innerTypeDefinition = null; @@ -191,7 +190,7 @@ Map createComplextObject(FullServiceDefinition fullServiceDefini Assertions.assertEquals(topTypeDefinition.getProperties().get("strArrays").getType(), "java.lang.String[]"); Assertions.assertEquals(topTypeDefinition.getProperties().get("innerObject3").getType(), "org.apache.dubbo.service.ComplexObject.InnerObject3[]"); Assertions.assertEquals(topTypeDefinition.getProperties().get("testEnum").getType(), "org.apache.dubbo.service.ComplexObject.TestEnum"); - Assertions.assertEquals(topTypeDefinition.getProperties().get("innerObject2").getType(), "java.util.Set"); + Assertions.assertEquals(topTypeDefinition.getProperties().get("innerObject2").getType(), "java.util.List"); Assertions.assertSame(innerTypeDefinition.getProperties().get("innerA").getType(), "java.lang.String"); Assertions.assertSame(innerTypeDefinition.getProperties().get("innerB").getType(), "int"); @@ -216,16 +215,16 @@ Map createComplextObject(FullServiceDefinition fullServiceDefini innerObjectMap.put("innerA", var1); innerObjectMap.put("innerB", var2); - Set innerObject2Set = new HashSet<>(4); - result.put("innerObject2", innerObject2Set); + List innerObject2List = new ArrayList<>(); + result.put("innerObject2", innerObject2List); Map innerObject2Tmp1 = new HashMap<>(4); innerObject2Tmp1.put("innerA2", var1 + "_21"); innerObject2Tmp1.put("innerB2", var2 + 100000); Map innerObject2Tmp2 = new HashMap<>(4); innerObject2Tmp2.put("innerA2", var1 + "_22"); innerObject2Tmp2.put("innerB2", var2 + 200000); - innerObject2Set.add(innerObject2Tmp1); - innerObject2Set.add(innerObject2Tmp2); + innerObject2List.add(innerObject2Tmp1); + innerObject2List.add(innerObject2Tmp2); Map innerObject3Tmp1 = new HashMap<>(4); innerObject3Tmp1.put("innerA3", var1 + "_31"); diff --git a/dubbo-compatible/src/test/java/org/apache/dubbo/rpc/cluster/CompatibleRouter.java b/dubbo-compatible/src/test/java/org/apache/dubbo/rpc/cluster/CompatibleRouter.java index 14f5a0e8ed6..2351b214409 100644 --- a/dubbo-compatible/src/test/java/org/apache/dubbo/rpc/cluster/CompatibleRouter.java +++ b/dubbo-compatible/src/test/java/org/apache/dubbo/rpc/cluster/CompatibleRouter.java @@ -28,6 +28,7 @@ * */ public class CompatibleRouter implements Router { + @Override public URL getUrl() { return null; diff --git a/dubbo-config/dubbo-config-spring/src/main/java/org/apache/dubbo/config/spring/convert/converter/StringArrayToMapConverter.java b/dubbo-compatible/src/test/java/org/apache/dubbo/rpc/cluster/CompatibleRouter2.java similarity index 58% rename from dubbo-config/dubbo-config-spring/src/main/java/org/apache/dubbo/config/spring/convert/converter/StringArrayToMapConverter.java rename to dubbo-compatible/src/test/java/org/apache/dubbo/rpc/cluster/CompatibleRouter2.java index a2e4790919b..13350d4572f 100644 --- a/dubbo-config/dubbo-config-spring/src/main/java/org/apache/dubbo/config/spring/convert/converter/StringArrayToMapConverter.java +++ b/dubbo-compatible/src/test/java/org/apache/dubbo/rpc/cluster/CompatibleRouter2.java @@ -14,26 +14,32 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.apache.dubbo.config.spring.convert.converter; +package org.apache.dubbo.rpc.cluster; -import org.apache.dubbo.common.utils.CollectionUtils; +import com.alibaba.dubbo.common.URL; +import com.alibaba.dubbo.rpc.Invocation; +import com.alibaba.dubbo.rpc.Invoker; +import com.alibaba.dubbo.rpc.RpcException; +import com.alibaba.dubbo.rpc.cluster.Router; -import org.springframework.core.convert.converter.Converter; -import org.springframework.util.ObjectUtils; - -import java.util.Map; +import java.util.List; /** - * {@link String}[] to {@link Map} {@link Converter} * - * @see CollectionUtils#toStringMap(String[]) - * @since 2.5.11 */ -public class StringArrayToMapConverter implements Converter> { +public class CompatibleRouter2 implements Router { + @Override + public URL getUrl() { + return null; + } @Override - public Map convert(String[] source) { - return ObjectUtils.isEmpty(source) ? null : CollectionUtils.toStringMap(source); + public List> route(List> invokers, URL url, Invocation invocation) throws RpcException { + return null; } + @Override + public int compareTo(Router o) { + return 0; + } } diff --git a/dubbo-compatible/src/test/java/org/apache/dubbo/rpc/cluster/NewRouter.java b/dubbo-compatible/src/test/java/org/apache/dubbo/rpc/cluster/NewRouter.java new file mode 100644 index 00000000000..86269062e0a --- /dev/null +++ b/dubbo-compatible/src/test/java/org/apache/dubbo/rpc/cluster/NewRouter.java @@ -0,0 +1,54 @@ +/* + * 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 org.apache.dubbo.common.URL; +import org.apache.dubbo.rpc.Invocation; +import org.apache.dubbo.rpc.Invoker; +import org.apache.dubbo.rpc.RpcException; + +import java.util.List; + +/** + * + */ +public class NewRouter implements Router { + @Override + public URL getUrl() { + return null; + } + + @Override + public List> route(List> invokers, URL url, Invocation invocation) throws RpcException { + return null; + } + + @Override + public boolean isRuntime() { + return false; + } + + @Override + public boolean isForce() { + return false; + } + + @Override + public int getPriority() { + return 0; + } +} diff --git a/dubbo-config/dubbo-config-spring/src/test/java/org/apache/dubbo/config/spring/convert/converter/StringArrayToMapConverterTest.java b/dubbo-compatible/src/test/java/org/apache/dubbo/rpc/cluster/RouterTest.java similarity index 52% rename from dubbo-config/dubbo-config-spring/src/test/java/org/apache/dubbo/config/spring/convert/converter/StringArrayToMapConverterTest.java rename to dubbo-compatible/src/test/java/org/apache/dubbo/rpc/cluster/RouterTest.java index 74e689e454e..5288c53a231 100644 --- a/dubbo-config/dubbo-config-spring/src/test/java/org/apache/dubbo/config/spring/convert/converter/StringArrayToMapConverterTest.java +++ b/dubbo-compatible/src/test/java/org/apache/dubbo/rpc/cluster/RouterTest.java @@ -14,39 +14,40 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.apache.dubbo.config.spring.convert.converter; +package org.apache.dubbo.rpc.cluster; import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.BeforeAll; import org.junit.jupiter.api.Test; -import java.util.LinkedHashMap; -import java.util.Map; +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; /** - * {@link StringArrayToMapConverter} Test + * */ -public class StringArrayToMapConverterTest { +public class RouterTest { + + private static List routers = new ArrayList<>(); + + @BeforeAll + public static void setUp () { + CompatibleRouter compatibleRouter = new CompatibleRouter(); + routers.add(compatibleRouter); + CompatibleRouter2 compatibleRouter2 = new CompatibleRouter2(); + routers.add(compatibleRouter2); + NewRouter newRouter = new NewRouter(); + routers.add(newRouter); + } @Test - public void testConvert() { - - StringArrayToMapConverter converter = new StringArrayToMapConverter(); - - Map value = converter.convert(new String[]{"Hello", "World"}); - - Map expected = new LinkedHashMap(); - - expected.put("Hello", "World"); - - Assertions.assertEquals(expected, value); - - value = converter.convert(new String[]{}); - - Assertions.assertNull(value); - - value = converter.convert(null); - - Assertions.assertNull(value); - + public void testCompareTo () { + try { + Collections.sort(routers); + Assertions.assertTrue(true); + } catch (Exception e) { + Assertions.assertFalse(false); + } } } diff --git a/dubbo-compatible/src/test/java/org/apache/dubbo/service/ComplexObject.java b/dubbo-compatible/src/test/java/org/apache/dubbo/service/ComplexObject.java index 5c895380302..3657a03a289 100644 --- a/dubbo-compatible/src/test/java/org/apache/dubbo/service/ComplexObject.java +++ b/dubbo-compatible/src/test/java/org/apache/dubbo/service/ComplexObject.java @@ -16,13 +16,12 @@ */ package org.apache.dubbo.service; +import java.util.ArrayList; import java.util.Arrays; import java.util.HashMap; -import java.util.HashSet; import java.util.List; import java.util.Map; import java.util.Objects; -import java.util.Set; /** * ON 2018/11/5 @@ -46,7 +45,7 @@ public ComplexObject(String var1, int var2, long l, String[] var3, List InnerObject2 io22 = new InnerObject2(); io22.setInnerA2(var1 + "_22"); io22.setInnerB2(var2 + 200000); - this.setInnerObject2(new HashSet(Arrays.asList(io21, io22))); + this.setInnerObject2(new ArrayList<>(Arrays.asList(io21, io22))); InnerObject3 io31 = new InnerObject3(); io31.setInnerA3(var1 + "_31"); @@ -61,7 +60,7 @@ public ComplexObject(String var1, int var2, long l, String[] var3, List } private InnerObject innerObject; - private Set innerObject2; + private List innerObject2; private InnerObject3[] innerObject3; private String[] strArrays; private List intList; @@ -109,11 +108,11 @@ public void setTestEnum(TestEnum testEnum) { this.testEnum = testEnum; } - public Set getInnerObject2() { + public List getInnerObject2() { return innerObject2; } - public void setInnerObject2(Set innerObject2) { + public void setInnerObject2(List innerObject2) { this.innerObject2 = innerObject2; } @@ -225,7 +224,7 @@ public String getInnerA2() { return innerA2; } - public void setInnerA2(String innerA) { + public void setInnerA2(String innerA2) { this.innerA2 = innerA2; } @@ -233,7 +232,7 @@ public int getInnerB2() { return innerB2; } - public void setInnerB2(int innerB) { + public void setInnerB2(int innerB2) { this.innerB2 = innerB2; } diff --git a/dubbo-config/dubbo-config-api/pom.xml b/dubbo-config/dubbo-config-api/pom.xml index 1b2d1ff61c9..19c7aca7bb7 100644 --- a/dubbo-config/dubbo-config-api/pom.xml +++ b/dubbo-config/dubbo-config-api/pom.xml @@ -19,7 +19,7 @@ org.apache.dubbo dubbo-config - 2.7.0-SNAPSHOT + 2.7.1-SNAPSHOT dubbo-config-api jar diff --git a/dubbo-config/dubbo-config-api/src/main/java/org/apache/dubbo/config/AbstractConfig.java b/dubbo-config/dubbo-config-api/src/main/java/org/apache/dubbo/config/AbstractConfig.java index 00c6950450b..59dd13d8e41 100644 --- a/dubbo-config/dubbo-config-api/src/main/java/org/apache/dubbo/config/AbstractConfig.java +++ b/dubbo-config/dubbo-config-api/src/main/java/org/apache/dubbo/config/AbstractConfig.java @@ -140,7 +140,7 @@ private static String getTagName(Class cls) { break; } } - return tag.substring(0, 1).toLowerCase() + tag.substring(1); + return StringUtils.camelToSplitName(tag, "-"); } protected static void appendParameters(Map parameters, Object config) { @@ -638,4 +638,31 @@ private boolean isMetaMethod(Method method) { return true; } + @Override + public boolean equals(Object obj) { + if (obj == null || !(obj.getClass().getName().equals(this.getClass().getName()))) { + return false; + } + + Method[] methods = this.getClass().getMethods(); + for (Method method1 : methods) { + if (ClassHelper.isGetter(method1) && ClassHelper.isPrimitive(method1.getReturnType())) { + Parameter parameter = method1.getAnnotation(Parameter.class); + if (parameter != null && parameter.excluded()) { + continue; + } + try { + Method method2 = obj.getClass().getMethod(method1.getName(), method1.getParameterTypes()); + Object value1 = method1.invoke(this, new Object[]{}); + Object value2 = method2.invoke(obj, new Object[]{}); + if ((value1 != null && value2 != null) && !value1.equals(value2)) { + return false; + } + } catch (Exception e) { + return true; + } + } + } + return true; + } } diff --git a/dubbo-config/dubbo-config-api/src/main/java/org/apache/dubbo/config/AbstractInterfaceConfig.java b/dubbo-config/dubbo-config-api/src/main/java/org/apache/dubbo/config/AbstractInterfaceConfig.java index 8d49b9976c2..3ba300c8a80 100644 --- a/dubbo-config/dubbo-config-api/src/main/java/org/apache/dubbo/config/AbstractInterfaceConfig.java +++ b/dubbo-config/dubbo-config-api/src/main/java/org/apache/dubbo/config/AbstractInterfaceConfig.java @@ -1,763 +1,825 @@ -/* - * 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.Constants; -import org.apache.dubbo.common.URL; -import org.apache.dubbo.common.Version; -import org.apache.dubbo.common.config.Environment; -import org.apache.dubbo.common.utils.Assert; -import org.apache.dubbo.common.utils.ConfigUtils; -import org.apache.dubbo.common.utils.NetUtils; -import org.apache.dubbo.common.utils.ReflectUtils; -import org.apache.dubbo.common.utils.StringUtils; -import org.apache.dubbo.common.utils.UrlUtils; -import org.apache.dubbo.common.utils.CollectionUtils; -import org.apache.dubbo.config.support.Parameter; -import org.apache.dubbo.metadata.integration.MetadataReportService; -import org.apache.dubbo.monitor.MonitorFactory; -import org.apache.dubbo.monitor.MonitorService; -import org.apache.dubbo.registry.RegistryService; -import org.apache.dubbo.rpc.Filter; -import org.apache.dubbo.rpc.InvokerListener; -import org.apache.dubbo.rpc.ProxyFactory; -import org.apache.dubbo.rpc.cluster.Cluster; -import org.apache.dubbo.rpc.model.ApplicationModel; -import org.apache.dubbo.rpc.support.MockInvoker; - -import java.util.ArrayList; -import java.util.Arrays; -import java.util.HashMap; -import java.util.HashSet; -import java.util.List; -import java.util.Map; -import java.util.Set; - -import static org.apache.dubbo.common.Constants.APPLICATION_KEY; -import static org.apache.dubbo.common.extension.ExtensionLoader.getExtensionLoader; - -/** - * AbstractDefaultConfig - * - * @export - */ -public abstract class AbstractInterfaceConfig extends AbstractMethodConfig { - - private static final long serialVersionUID = -1559314110797223229L; - - /** - * Local impl class name for the service interface - */ - protected String local; - - /** - * Local stub class name for the service interface - */ - protected String stub; - - /** - * Service monitor - */ - protected MonitorConfig monitor; - - /** - * Strategies for generating dynamic agents,there are two strategies can be choosed: jdk and javassist - */ - protected String proxy; - - /** - * Cluster type - */ - protected String cluster; - - /** - * The {@link Filter} when the provider side exposed a service or the customer side references a remote service used, - * if there are more than one, you can use commas to separate them - */ - protected String filter; - - /** - * The Listener when the provider side exposes a service or the customer side references a remote service used - * if there are more than one, you can use commas to separate them - */ - protected String listener; - - /** - * The owner of the service providers - */ - protected String owner; - - /** - * Connection limits, 0 means shared connection, otherwise it defines the connections delegated to the current service - */ - protected Integer connections; - - /** - * The layer of service providers - */ - protected String layer; - - /** - * The application info - */ - protected ApplicationConfig application; - - /** - * The module info - */ - protected ModuleConfig module; - - /** - * Registry centers - */ - protected List registries; - - protected String registryIds; - - // connection events - protected String onconnect; - - /** - * Disconnection events - */ - protected String ondisconnect; - protected MetadataReportConfig metadataReportConfig; - protected RegistryDataConfig registryDataConfig; - // callback limits - private Integer callbacks; - // the scope for referring/exporting a service, if it's local, it means searching in current JVM only. - private String scope; - - /** - * Check whether the registry config is exists, and then conversion it to {@link RegistryConfig} - */ - protected void checkRegistry() { - loadRegistriesFromBackwardConfig(); - - convertRegistryIdsToRegistries(); - - for (RegistryConfig registryConfig : registries) { - registryConfig.refresh(); - if (StringUtils.isNotEmpty(registryConfig.getId())) { - registryConfig.setPrefix(Constants.REGISTRIES_SUFFIX); - registryConfig.refresh(); - } - } - - for (RegistryConfig registryConfig : registries) { - if (!registryConfig.isValid()) { - throw new IllegalStateException("No registry config found or it's not a valid config! " + - "The registry config is: " + registryConfig); - } - } - - useRegistryForConfigIfNecessary(); - } - - @SuppressWarnings("deprecation") - protected void checkApplication() { - // for backward compatibility - if (application == null) { - application = new ApplicationConfig(); - } - - application.refresh(); - - if (!application.isValid()) { - throw new IllegalStateException("No application config found or it's not a valid config! " + - "Please add to your spring config."); - } - - ApplicationModel.setApplication(application.getName()); - - // backward compatibility - String wait = ConfigUtils.getProperty(Constants.SHUTDOWN_WAIT_KEY); - if (wait != null && wait.trim().length() > 0) { - System.setProperty(Constants.SHUTDOWN_WAIT_KEY, wait.trim()); - } else { - wait = ConfigUtils.getProperty(Constants.SHUTDOWN_WAIT_SECONDS_KEY); - if (wait != null && wait.trim().length() > 0) { - System.setProperty(Constants.SHUTDOWN_WAIT_SECONDS_KEY, wait.trim()); - } - } - } - - protected void checkMonitor() { - if (monitor == null) { - monitor = new MonitorConfig(); - } - - monitor.refresh(); - - if (!monitor.isValid()) { - logger.info("There's no valid monitor config found, if you want to open monitor statistics for Dubbo, " + - "please make sure your monitor is configured properly."); - } - } - - protected void checkMetadataReport() { - if (metadataReportConfig == null) { - metadataReportConfig = new MetadataReportConfig(); - } - metadataReportConfig.refresh(); - if (!metadataReportConfig.isValid()) { - logger.warn("There's no valid metadata config found, if you are using the simplified mode of registry url, " + - "please make sure you have a metadata address configured properly."); - } - } - - protected void checkRegistryDataConfig() { - if (registryDataConfig == null) { - registryDataConfig = new RegistryDataConfig(); - } - registryDataConfig.refresh(); - if (!registryDataConfig.isValid()) { - logger.info("There's no valid registryData config found. So the registry will store full url parameter " + - "to registry server."); - } - } - - /** - * - * Load the registry and conversion it to {@link URL}, the priority order is: system property > dubbo registry config - * - * @param provider whether it is the provider side - * @return - */ - protected List loadRegistries(boolean provider) { - // check && override if necessary - checkRegistry(); - checkRegistryDataConfig(); - List registryList = new ArrayList(); - if (CollectionUtils.isNotEmpty(registries)) { - Map registryDataConfigurationMap = new HashMap<>(4); - appendParameters(registryDataConfigurationMap, registryDataConfig); - for (RegistryConfig config : registries) { - String address = config.getAddress(); - if (StringUtils.isEmpty(address)) { - address = Constants.ANYHOST_VALUE; - } - if (!RegistryConfig.NO_AVAILABLE.equalsIgnoreCase(address)) { - Map map = new HashMap(); - appendParameters(map, application); - appendParameters(map, config); - map.put("path", RegistryService.class.getName()); - appendRuntimeParameters(map); - if (!map.containsKey("protocol")) { - map.put("protocol", "dubbo"); - } - List urls = UrlUtils.parseURLs(address, map); - - for (URL url : urls) { - url = url.addParameter(Constants.REGISTRY_KEY, url.getProtocol()); - url = url.setProtocol(Constants.REGISTRY_PROTOCOL); - // add parameter - url = url.addParametersIfAbsent(registryDataConfigurationMap); - if ((provider && url.getParameter(Constants.REGISTER_KEY, true)) - || (!provider && url.getParameter(Constants.SUBSCRIBE_KEY, true))) { - registryList.add(url); - } - } - } - } - } - return registryList; - } - - /** - * - * Load the monitor config from the system properties and conversation it to {@link URL} - * - * @param registryURL - * @return - */ - protected URL loadMonitor(URL registryURL) { - checkMonitor(); - Map map = new HashMap(); - map.put(Constants.INTERFACE_KEY, MonitorService.class.getName()); - appendRuntimeParameters(map); - //set ip - String hostToRegistry = ConfigUtils.getSystemProperty(Constants.DUBBO_IP_TO_REGISTRY); - if (StringUtils.isEmpty(hostToRegistry)) { - hostToRegistry = NetUtils.getLocalHost(); - } else if (NetUtils.isInvalidLocalHost(hostToRegistry)) { - throw new IllegalArgumentException("Specified invalid registry ip from property:" + - Constants.DUBBO_IP_TO_REGISTRY + ", value:" + hostToRegistry); - } - map.put(Constants.REGISTER_IP_KEY, hostToRegistry); - appendParameters(map, monitor); - appendParameters(map, application); - String address = monitor.getAddress(); - String sysaddress = System.getProperty("dubbo.monitor.address"); - if (sysaddress != null && sysaddress.length() > 0) { - address = sysaddress; - } - if (ConfigUtils.isNotEmpty(address)) { - if (!map.containsKey(Constants.PROTOCOL_KEY)) { - if (getExtensionLoader(MonitorFactory.class).hasExtension("logstat")) { - map.put(Constants.PROTOCOL_KEY, "logstat"); - } else { - map.put(Constants.PROTOCOL_KEY, Constants.DOBBO_PROTOCOL); - } - } - return UrlUtils.parseURL(address, map); - } else if (Constants.REGISTRY_PROTOCOL.equals(monitor.getProtocol()) && registryURL != null) { - return registryURL.setProtocol(Constants.DOBBO_PROTOCOL).addParameter(Constants.PROTOCOL_KEY, Constants.REGISTRY_PROTOCOL).addParameterAndEncoded(Constants.REFER_KEY, StringUtils.toQueryString(map)); - } - return null; - } - - static void appendRuntimeParameters(Map map) { - map.put(Constants.DUBBO_VERSION_KEY, Version.getProtocolVersion()); - map.put(Constants.SPECIFICATION_VERSION_KEY, Version.getVersion()); - map.put(Constants.TIMESTAMP_KEY, String.valueOf(System.currentTimeMillis())); - if (ConfigUtils.getPid() > 0) { - map.put(Constants.PID_KEY, String.valueOf(ConfigUtils.getPid())); - } - } - - private URL loadMetadataReporterURL(boolean provider) { - this.checkApplication(); - String address = metadataReportConfig.getAddress(); - if (StringUtils.isEmpty(address)) { - return null; - } - Map map = new HashMap(); - map.put(APPLICATION_KEY, application.getName()); - appendParameters(map, metadataReportConfig); - return UrlUtils.parseURL(address, map); - } - - protected MetadataReportService getMetadataReportService() { - - if (metadataReportConfig == null || !metadataReportConfig.isValid()) { - return null; - } - return MetadataReportService.instance(() -> { - return loadMetadataReporterURL(true); - }); - } - - /** - * Check whether the remote service interface and the methods meet with Dubbo's requirements.it mainly check, if the - * methods configured in the configuration file are included in the interface of remote service - * - * @param interfaceClass the interface of remote service - * @param methods the methods configured - */ - protected void checkInterfaceAndMethods(Class interfaceClass, List methods) { - // interface cannot be null - Assert.notNull(interfaceClass, new IllegalStateException("interface not allow null!")); - - // to verify interfaceClass is an interface - if (!interfaceClass.isInterface()) { - throw new IllegalStateException("The interface class " + interfaceClass + " is not a interface!"); - } - // check if methods exist in the remote service interface - if (CollectionUtils.isNotEmpty(methods)) { - for (MethodConfig methodBean : methods) { - methodBean.setService(interfaceClass.getName()); - methodBean.setServiceId(this.getId()); - methodBean.refresh(); - String methodName = methodBean.getName(); - if (StringUtils.isEmpty(methodName)) { - throw new IllegalStateException(" name attribute is required! Please check: " + - "" + - ""); - } - - boolean hasMethod = Arrays.stream(interfaceClass.getMethods()).anyMatch(method -> method.getName().equals(methodName)); - if (!hasMethod) { - throw new IllegalStateException("The interface " + interfaceClass.getName() - + " not found method " + methodName); - } - } - } - } - - /** - * Legitimacy check and setup of local simulated operations. The operations can be a string with Simple operation or - * a classname whose {@link Class} implements a particular function - * - * @param interfaceClass for provider side, it is the {@link Class} of the service that will be exported; for consumer - * side, it is the {@link Class} of the remote service interface that will be referenced - */ - void checkMock(Class interfaceClass) { - if (ConfigUtils.isEmpty(mock)) { - return; - } - - String normalizedMock = MockInvoker.normalizeMock(mock); - if (normalizedMock.startsWith(Constants.RETURN_PREFIX)) { - normalizedMock = normalizedMock.substring(Constants.RETURN_PREFIX.length()).trim(); - try { - //Check whether the mock value is legal, if it is illegal, throw exception - MockInvoker.parseMockValue(normalizedMock); - } catch (Exception e) { - throw new IllegalStateException("Illegal mock return in "); - } - } else if (normalizedMock.startsWith(Constants.THROW_PREFIX)) { - normalizedMock = normalizedMock.substring(Constants.THROW_PREFIX.length()).trim(); - if (ConfigUtils.isNotEmpty(normalizedMock)) { - try { - //Check whether the mock value is legal - MockInvoker.getThrowable(normalizedMock); - } catch (Exception e) { - throw new IllegalStateException("Illegal mock throw in "); - } - } - } else { - //Check whether the mock class is a implementation of the interfaceClass, and if it has a default constructor - MockInvoker.getMockObject(normalizedMock, interfaceClass); - } - } - - /** - * Legitimacy check of stub, note that: the local will deprecated, and replace with stub - * - * @param interfaceClass for provider side, it is the {@link Class} of the service that will be exported; for consumer - * side, it is the {@link Class} of the remote service interface - */ - void checkStubAndLocal(Class interfaceClass) { - if (ConfigUtils.isNotEmpty(local)) { - Class localClass = ConfigUtils.isDefault(local) ? - ReflectUtils.forName(interfaceClass.getName() + "Local") : ReflectUtils.forName(local); - verify(interfaceClass, localClass); - } - if (ConfigUtils.isNotEmpty(stub)) { - Class localClass = ConfigUtils.isDefault(stub) ? - ReflectUtils.forName(interfaceClass.getName() + "Stub") : ReflectUtils.forName(stub); - verify(interfaceClass, localClass); - } - } - - private void verify(Class interfaceClass, Class localClass) { - if (!interfaceClass.isAssignableFrom(localClass)) { - throw new IllegalStateException("The local implementation class " + localClass.getName() + - " not implement interface " + interfaceClass.getName()); - } - - try { - //Check if the localClass a constructor with parameter who's type is interfaceClass - ReflectUtils.findConstructor(localClass, interfaceClass); - } catch (NoSuchMethodException e) { - throw new IllegalStateException("No such constructor \"public " + localClass.getSimpleName() + - "(" + interfaceClass.getName() + ")\" in local implementation class " + localClass.getName()); - } - } - - private void overrideParameters(Map map) { - map.put(Constants.PATH_KEY, RegistryService.class.getName()); - map.put(Constants.DOBBO_PROTOCOL, Version.getProtocolVersion()); - map.put(Constants.TIMESTAMP_KEY, String.valueOf(System.currentTimeMillis())); - if (ConfigUtils.getPid() > 0) { - map.put(Constants.PID_KEY, String.valueOf(ConfigUtils.getPid())); - } - map.putIfAbsent(Constants.PROTOCOL_KEY, Constants.DOBBO_PROTOCOL); - } - - private void convertRegistryIdsToRegistries() { - if (StringUtils.isEmpty(registryIds) && CollectionUtils.isEmpty(registries)) { - Set configedRegistries = new HashSet<>(); - configedRegistries.addAll(getSubProperties(Environment.getInstance().getExternalConfigurationMap(), - Constants.REGISTRIES_SUFFIX)); - configedRegistries.addAll(getSubProperties(Environment.getInstance().getAppExternalConfigurationMap(), - Constants.REGISTRIES_SUFFIX)); - - registryIds = String.join(",", configedRegistries); - } - - if (StringUtils.isEmpty(registryIds)) { - if (CollectionUtils.isEmpty(registries)) { - registries = new ArrayList<>(); - registries.add(new RegistryConfig()); - } - } else { - String[] arr = Constants.COMMA_SPLIT_PATTERN.split(registryIds); - if (CollectionUtils.isEmpty(registries)) { - registries = new ArrayList<>(); - } - Arrays.stream(arr).forEach(id -> { - if (registries.stream().noneMatch(reg -> reg.getId().equals(id))) { - RegistryConfig registryConfig = new RegistryConfig(); - registryConfig.setId(id); - registries.add(registryConfig); - } - }); - if (registries.size() > arr.length) { - throw new IllegalStateException("Too many registries found, the registries assigned to this service " + - "are :" + registryIds + ", but got " + registries.size() + " registries!"); - } - } - - } - - private void loadRegistriesFromBackwardConfig() { - // for backward compatibility - // -Ddubbo.registry.address is now deprecated. - if (registries == null || registries.isEmpty()) { - String address = ConfigUtils.getProperty("dubbo.registry.address"); - if (address != null && address.length() > 0) { - registries = new ArrayList(); - String[] as = address.split("\\s*[|]+\\s*"); - for (String a : as) { - RegistryConfig registryConfig = new RegistryConfig(); - registryConfig.setAddress(a); - registries.add(registryConfig); - } - } - } - } - - /** - * For compatibility purpose, use registry as the default config center if the registry protocol is zookeeper and - * there's no config center specified explicitly. - */ - private void useRegistryForConfigIfNecessary() { - registries.stream().filter(RegistryConfig::isZookeeperProtocol).findFirst().ifPresent(rc -> { - // we use the loading status of DynamicConfiguration to decide whether ConfigCenter has been initiated. - Environment.getInstance().getDynamicConfiguration().orElseGet(() -> { - ConfigCenterConfig configCenterConfig = new ConfigCenterConfig(); - configCenterConfig.setProtocol(rc.getProtocol()); - configCenterConfig.setAddress(rc.getAddress()); - configCenterConfig.setHighestPriority(false); - configCenterConfig.init(); - return null; - }); - }); - } - - /** - * @return local - * @deprecated Replace to getStub() - */ - @Deprecated - public String getLocal() { - return local; - } - - /** - * @param local - * @deprecated Replace to setStub(Boolean) - */ - @Deprecated - public void setLocal(Boolean local) { - if (local == null) { - setLocal((String) null); - } else { - setLocal(String.valueOf(local)); - } - } - - /** - * @param local - * @deprecated Replace to setStub(String) - */ - @Deprecated - public void setLocal(String local) { - checkName("local", local); - this.local = local; - } - - public String getStub() { - return stub; - } - - public void setStub(Boolean stub) { - if (stub == null) { - setStub((String) null); - } else { - setStub(String.valueOf(stub)); - } - } - - public void setStub(String stub) { - checkName("stub", stub); - this.stub = stub; - } - - public String getCluster() { - return cluster; - } - - public void setCluster(String cluster) { - checkExtension(Cluster.class, "cluster", cluster); - this.cluster = cluster; - } - - public String getProxy() { - return proxy; - } - - public void setProxy(String proxy) { - checkExtension(ProxyFactory.class, "proxy", proxy); - this.proxy = proxy; - } - - public Integer getConnections() { - return connections; - } - - public void setConnections(Integer connections) { - this.connections = connections; - } - - @Parameter(key = Constants.REFERENCE_FILTER_KEY, append = true) - public String getFilter() { - return filter; - } - - public void setFilter(String filter) { - checkMultiExtension(Filter.class, "filter", filter); - this.filter = filter; - } - - @Parameter(key = Constants.INVOKER_LISTENER_KEY, append = true) - public String getListener() { - return listener; - } - - public void setListener(String listener) { - checkMultiExtension(InvokerListener.class, "listener", listener); - this.listener = listener; - } - - public String getLayer() { - return layer; - } - - public void setLayer(String layer) { - checkNameHasSymbol("layer", layer); - this.layer = layer; - } - - public ApplicationConfig getApplication() { - return application; - } - - public void setApplication(ApplicationConfig application) { - this.application = application; - } - - public ModuleConfig getModule() { - return module; - } - - public void setModule(ModuleConfig module) { - this.module = module; - } - - public RegistryConfig getRegistry() { - return CollectionUtils.isEmpty(registries) ? null : registries.get(0); - } - - public void setRegistry(RegistryConfig registry) { - List registries = new ArrayList(1); - registries.add(registry); - this.registries = registries; - } - - public List getRegistries() { - return registries; - } - - @SuppressWarnings({"unchecked"}) - public void setRegistries(List registries) { - this.registries = (List) registries; - } - - @Parameter(excluded = true) - public String getRegistryIds() { - return registryIds; - } - - public void setRegistryIds(String registryIds) { - this.registryIds = registryIds; - } - - public MonitorConfig getMonitor() { - return monitor; - } - - public void setMonitor(String monitor) { - this.monitor = new MonitorConfig(monitor); - } - - public void setMonitor(MonitorConfig monitor) { - this.monitor = monitor; - } - - public String getOwner() { - return owner; - } - - public void setOwner(String owner) { - checkMultiName("owner", owner); - this.owner = owner; - } - - public RegistryDataConfig getRegistryDataConfig() { - return registryDataConfig; - } - - public void setRegistryDataConfig(RegistryDataConfig registryDataConfig) { - this.registryDataConfig = registryDataConfig; - } - - public Integer getCallbacks() { - return callbacks; - } - - public void setCallbacks(Integer callbacks) { - this.callbacks = callbacks; - } - - public String getOnconnect() { - return onconnect; - } - - public void setOnconnect(String onconnect) { - this.onconnect = onconnect; - } - - public String getOndisconnect() { - return ondisconnect; - } - - public void setOndisconnect(String ondisconnect) { - this.ondisconnect = ondisconnect; - } - - public String getScope() { - return scope; - } - - public void setScope(String scope) { - this.scope = scope; - } - - public MetadataReportConfig getMetadataReportConfig() { - return metadataReportConfig; - } - - public void setMetadataReportConfig(MetadataReportConfig metadataReportConfig) { - this.metadataReportConfig = metadataReportConfig; - } - -} +/* + * 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.Constants; +import org.apache.dubbo.common.URL; +import org.apache.dubbo.common.Version; +import org.apache.dubbo.common.config.Environment; +import org.apache.dubbo.common.extension.ExtensionLoader; +import org.apache.dubbo.common.utils.Assert; +import org.apache.dubbo.common.utils.CollectionUtils; +import org.apache.dubbo.common.utils.ConfigUtils; +import org.apache.dubbo.common.utils.NetUtils; +import org.apache.dubbo.common.utils.ReflectUtils; +import org.apache.dubbo.common.utils.StringUtils; +import org.apache.dubbo.common.utils.UrlUtils; +import org.apache.dubbo.config.context.ConfigManager; +import org.apache.dubbo.common.utils.CollectionUtils; +import org.apache.dubbo.config.support.Parameter; +import org.apache.dubbo.configcenter.DynamicConfiguration; +import org.apache.dubbo.configcenter.DynamicConfigurationFactory; +import org.apache.dubbo.metadata.integration.MetadataReportService; +import org.apache.dubbo.monitor.MonitorFactory; +import org.apache.dubbo.monitor.MonitorService; +import org.apache.dubbo.registry.RegistryService; +import org.apache.dubbo.rpc.Filter; +import org.apache.dubbo.rpc.InvokerListener; +import org.apache.dubbo.rpc.ProxyFactory; +import org.apache.dubbo.rpc.cluster.Cluster; +import org.apache.dubbo.rpc.model.ApplicationModel; +import org.apache.dubbo.rpc.support.MockInvoker; + +import java.io.IOException; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.HashMap; +import java.util.HashSet; +import java.util.List; +import java.util.Map; +import java.util.Set; + +import static org.apache.dubbo.common.config.ConfigurationUtils.parseProperties; +import static org.apache.dubbo.common.extension.ExtensionLoader.getExtensionLoader; + +/** + * AbstractDefaultConfig + * + * @export + */ +public abstract class AbstractInterfaceConfig extends AbstractMethodConfig { + + private static final long serialVersionUID = -1559314110797223229L; + + /** + * Local impl class name for the service interface + */ + protected String local; + + /** + * Local stub class name for the service interface + */ + protected String stub; + + /** + * Service monitor + */ + protected MonitorConfig monitor; + + /** + * Strategies for generating dynamic agents,there are two strategies can be choosed: jdk and javassist + */ + protected String proxy; + + /** + * Cluster type + */ + protected String cluster; + + /** + * The {@link Filter} when the provider side exposed a service or the customer side references a remote service used, + * if there are more than one, you can use commas to separate them + */ + protected String filter; + + /** + * The Listener when the provider side exposes a service or the customer side references a remote service used + * if there are more than one, you can use commas to separate them + */ + protected String listener; + + /** + * The owner of the service providers + */ + protected String owner; + + /** + * Connection limits, 0 means shared connection, otherwise it defines the connections delegated to the current service + */ + protected Integer connections; + + /** + * The layer of service providers + */ + protected String layer; + + /** + * The application info + */ + protected ApplicationConfig application; + + /** + * The module info + */ + protected ModuleConfig module; + + /** + * Registry centers + */ + protected List registries; + + protected String registryIds; + + // connection events + protected String onconnect; + + /** + * Disconnection events + */ + protected String ondisconnect; + protected MetadataReportConfig metadataReportConfig; + + protected ConfigCenterConfig configCenter; + + // callback limits + private Integer callbacks; + // the scope for referring/exporting a service, if it's local, it means searching in current JVM only. + private String scope; + + /** + * Check whether the registry config is exists, and then conversion it to {@link RegistryConfig} + */ + protected void checkRegistry() { + loadRegistriesFromBackwardConfig(); + + convertRegistryIdsToRegistries(); + + for (RegistryConfig registryConfig : registries) { + if (!registryConfig.isValid()) { + throw new IllegalStateException("No registry config found or it's not a valid config! " + + "The registry config is: " + registryConfig); + } + } + + useRegistryForConfigIfNecessary(); + } + + @SuppressWarnings("deprecation") + protected void checkApplication() { + // for backward compatibility + createApplicationIfAbsent(); + + if (!application.isValid()) { + throw new IllegalStateException("No application config found or it's not a valid config! " + + "Please add to your spring config."); + } + + ApplicationModel.setApplication(application.getName()); + + // backward compatibility + String wait = ConfigUtils.getProperty(Constants.SHUTDOWN_WAIT_KEY); + if (wait != null && wait.trim().length() > 0) { + System.setProperty(Constants.SHUTDOWN_WAIT_KEY, wait.trim()); + } else { + wait = ConfigUtils.getProperty(Constants.SHUTDOWN_WAIT_SECONDS_KEY); + if (wait != null && wait.trim().length() > 0) { + System.setProperty(Constants.SHUTDOWN_WAIT_SECONDS_KEY, wait.trim()); + } + } + } + + protected void checkMonitor() { + createMonitorIfAbsent(); + if (!monitor.isValid()) { + logger.info("There's no valid monitor config found, if you want to open monitor statistics for Dubbo, " + + "please make sure your monitor is configured properly."); + } + } + + private void createMonitorIfAbsent() { + if (this.monitor != null) { + return; + } + ConfigManager configManager = ConfigManager.getInstance(); + setMonitor( + configManager + .getMonitor() + .orElseGet(() -> { + MonitorConfig monitorConfig = new MonitorConfig(); + monitorConfig.refresh(); + return monitorConfig; + }) + ); + } + + protected void checkMetadataReport() { + // TODO get from ConfigManager first, only create if absent. + if (metadataReportConfig == null) { + setMetadataReportConfig(new MetadataReportConfig()); + } + metadataReportConfig.refresh(); + if (!metadataReportConfig.isValid()) { + logger.warn("There's no valid metadata config found, if you are using the simplified mode of registry url, " + + "please make sure you have a metadata address configured properly."); + } + } + + + void startConfigCenter() { + if (configCenter == null) { + ConfigManager.getInstance().getConfigCenter().ifPresent(cc -> this.configCenter = cc); + } + + if (this.configCenter != null) { + // TODO there may have duplicate refresh + this.configCenter.refresh(); + prepareEnvironment(); + } + ConfigManager.getInstance().refreshAll(); + } + + private void prepareEnvironment() { + if (configCenter.isValid()) { + if (!configCenter.checkOrUpdateInited()) { + return; + } + DynamicConfiguration dynamicConfiguration = getDynamicConfiguration(configCenter.toUrl()); + String configContent = dynamicConfiguration.getConfig(configCenter.getConfigFile(), configCenter.getGroup()); + + String appGroup = application != null ? application.getName() : null; + String appConfigContent = null; + if (StringUtils.isNotEmpty(appGroup)) { + appConfigContent = dynamicConfiguration.getConfig + (StringUtils.isNotEmpty(configCenter.getAppConfigFile()) ? configCenter.getAppConfigFile() : configCenter.getConfigFile(), + appGroup + ); + } + try { + Environment.getInstance().setConfigCenterFirst(configCenter.isHighestPriority()); + Environment.getInstance().updateExternalConfigurationMap(parseProperties(configContent)); + Environment.getInstance().updateAppExternalConfigurationMap(parseProperties(appConfigContent)); + } catch (IOException e) { + throw new IllegalStateException("Failed to parse configurations from Config Center.", e); + } + } + } + + private DynamicConfiguration getDynamicConfiguration(URL url) { + DynamicConfigurationFactory factories = ExtensionLoader + .getExtensionLoader(DynamicConfigurationFactory.class) + .getExtension(url.getProtocol()); + DynamicConfiguration configuration = factories.getDynamicConfiguration(url); + Environment.getInstance().setDynamicConfiguration(configuration); + return configuration; + } + + /** + * + * Load the registry and conversion it to {@link URL}, the priority order is: system property > dubbo registry config + * + * @param provider whether it is the provider side + * @return + */ + protected List loadRegistries(boolean provider) { + // check && override if necessary + List registryList = new ArrayList(); + if (CollectionUtils.isNotEmpty(registries)) { + for (RegistryConfig config : registries) { + String address = config.getAddress(); + if (StringUtils.isEmpty(address)) { + address = Constants.ANYHOST_VALUE; + } + if (!RegistryConfig.NO_AVAILABLE.equalsIgnoreCase(address)) { + Map map = new HashMap(); + appendParameters(map, application); + appendParameters(map, config); + map.put("path", RegistryService.class.getName()); + appendRuntimeParameters(map); + if (!map.containsKey("protocol")) { + map.put("protocol", "dubbo"); + } + List urls = UrlUtils.parseURLs(address, map); + + for (URL url : urls) { + url = url.addParameter(Constants.REGISTRY_KEY, url.getProtocol()); + url = url.setProtocol(Constants.REGISTRY_PROTOCOL); + if ((provider && url.getParameter(Constants.REGISTER_KEY, true)) + || (!provider && url.getParameter(Constants.SUBSCRIBE_KEY, true))) { + registryList.add(url); + } + } + } + } + } + return registryList; + } + + /** + * + * Load the monitor config from the system properties and conversation it to {@link URL} + * + * @param registryURL + * @return + */ + protected URL loadMonitor(URL registryURL) { + checkMonitor(); + Map map = new HashMap(); + map.put(Constants.INTERFACE_KEY, MonitorService.class.getName()); + appendRuntimeParameters(map); + //set ip + String hostToRegistry = ConfigUtils.getSystemProperty(Constants.DUBBO_IP_TO_REGISTRY); + if (StringUtils.isEmpty(hostToRegistry)) { + hostToRegistry = NetUtils.getLocalHost(); + } else if (NetUtils.isInvalidLocalHost(hostToRegistry)) { + throw new IllegalArgumentException("Specified invalid registry ip from property:" + + Constants.DUBBO_IP_TO_REGISTRY + ", value:" + hostToRegistry); + } + map.put(Constants.REGISTER_IP_KEY, hostToRegistry); + appendParameters(map, monitor); + appendParameters(map, application); + String address = monitor.getAddress(); + String sysaddress = System.getProperty("dubbo.monitor.address"); + if (sysaddress != null && sysaddress.length() > 0) { + address = sysaddress; + } + if (ConfigUtils.isNotEmpty(address)) { + if (!map.containsKey(Constants.PROTOCOL_KEY)) { + if (getExtensionLoader(MonitorFactory.class).hasExtension("logstat")) { + map.put(Constants.PROTOCOL_KEY, "logstat"); + } else { + map.put(Constants.PROTOCOL_KEY, Constants.DOBBO_PROTOCOL); + } + } + return UrlUtils.parseURL(address, map); + } else if (Constants.REGISTRY_PROTOCOL.equals(monitor.getProtocol()) && registryURL != null) { + return registryURL.setProtocol(Constants.DOBBO_PROTOCOL).addParameter(Constants.PROTOCOL_KEY, Constants.REGISTRY_PROTOCOL).addParameterAndEncoded(Constants.REFER_KEY, StringUtils.toQueryString(map)); + } + return null; + } + + static void appendRuntimeParameters(Map map) { + map.put(Constants.DUBBO_VERSION_KEY, Version.getProtocolVersion()); + map.put(Constants.RELEASE_KEY, Version.getVersion()); + map.put(Constants.TIMESTAMP_KEY, String.valueOf(System.currentTimeMillis())); + if (ConfigUtils.getPid() > 0) { + map.put(Constants.PID_KEY, String.valueOf(ConfigUtils.getPid())); + } + } + + private URL loadMetadataReporterURL() { + String address = metadataReportConfig.getAddress(); + if (StringUtils.isEmpty(address)) { + return null; + } + Map map = new HashMap(); + appendParameters(map, metadataReportConfig); + return UrlUtils.parseURL(address, map); + } + + protected MetadataReportService getMetadataReportService() { + + if (metadataReportConfig == null || !metadataReportConfig.isValid()) { + return null; + } + return MetadataReportService.instance(this::loadMetadataReporterURL); + } + + /** + * Check whether the remote service interface and the methods meet with Dubbo's requirements.it mainly check, if the + * methods configured in the configuration file are included in the interface of remote service + * + * @param interfaceClass the interface of remote service + * @param methods the methods configured + */ + protected void checkInterfaceAndMethods(Class interfaceClass, List methods) { + // interface cannot be null + Assert.notNull(interfaceClass, new IllegalStateException("interface not allow null!")); + + // to verify interfaceClass is an interface + if (!interfaceClass.isInterface()) { + throw new IllegalStateException("The interface class " + interfaceClass + " is not a interface!"); + } + // check if methods exist in the remote service interface + if (CollectionUtils.isNotEmpty(methods)) { + for (MethodConfig methodBean : methods) { + methodBean.setService(interfaceClass.getName()); + methodBean.setServiceId(this.getId()); + methodBean.refresh(); + String methodName = methodBean.getName(); + if (StringUtils.isEmpty(methodName)) { + throw new IllegalStateException(" name attribute is required! Please check: " + + "" + + ""); + } + + boolean hasMethod = Arrays.stream(interfaceClass.getMethods()).anyMatch(method -> method.getName().equals(methodName)); + if (!hasMethod) { + throw new IllegalStateException("The interface " + interfaceClass.getName() + + " not found method " + methodName); + } + } + } + } + + /** + * Legitimacy check and setup of local simulated operations. The operations can be a string with Simple operation or + * a classname whose {@link Class} implements a particular function + * + * @param interfaceClass for provider side, it is the {@link Class} of the service that will be exported; for consumer + * side, it is the {@link Class} of the remote service interface that will be referenced + */ + void checkMock(Class interfaceClass) { + if (ConfigUtils.isEmpty(mock)) { + return; + } + + String normalizedMock = MockInvoker.normalizeMock(mock); + if (normalizedMock.startsWith(Constants.RETURN_PREFIX)) { + normalizedMock = normalizedMock.substring(Constants.RETURN_PREFIX.length()).trim(); + try { + //Check whether the mock value is legal, if it is illegal, throw exception + MockInvoker.parseMockValue(normalizedMock); + } catch (Exception e) { + throw new IllegalStateException("Illegal mock return in "); + } + } else if (normalizedMock.startsWith(Constants.THROW_PREFIX)) { + normalizedMock = normalizedMock.substring(Constants.THROW_PREFIX.length()).trim(); + if (ConfigUtils.isNotEmpty(normalizedMock)) { + try { + //Check whether the mock value is legal + MockInvoker.getThrowable(normalizedMock); + } catch (Exception e) { + throw new IllegalStateException("Illegal mock throw in "); + } + } + } else { + //Check whether the mock class is a implementation of the interfaceClass, and if it has a default constructor + MockInvoker.getMockObject(normalizedMock, interfaceClass); + } + } + + /** + * Legitimacy check of stub, note that: the local will deprecated, and replace with stub + * + * @param interfaceClass for provider side, it is the {@link Class} of the service that will be exported; for consumer + * side, it is the {@link Class} of the remote service interface + */ + void checkStubAndLocal(Class interfaceClass) { + if (ConfigUtils.isNotEmpty(local)) { + Class localClass = ConfigUtils.isDefault(local) ? + ReflectUtils.forName(interfaceClass.getName() + "Local") : ReflectUtils.forName(local); + verify(interfaceClass, localClass); + } + if (ConfigUtils.isNotEmpty(stub)) { + Class localClass = ConfigUtils.isDefault(stub) ? + ReflectUtils.forName(interfaceClass.getName() + "Stub") : ReflectUtils.forName(stub); + verify(interfaceClass, localClass); + } + } + + private void verify(Class interfaceClass, Class localClass) { + if (!interfaceClass.isAssignableFrom(localClass)) { + throw new IllegalStateException("The local implementation class " + localClass.getName() + + " not implement interface " + interfaceClass.getName()); + } + + try { + //Check if the localClass a constructor with parameter who's type is interfaceClass + ReflectUtils.findConstructor(localClass, interfaceClass); + } catch (NoSuchMethodException e) { + throw new IllegalStateException("No such constructor \"public " + localClass.getSimpleName() + + "(" + interfaceClass.getName() + ")\" in local implementation class " + localClass.getName()); + } + } + + private void convertRegistryIdsToRegistries() { + if (StringUtils.isEmpty(registryIds) && CollectionUtils.isEmpty(registries)) { + Set configedRegistries = new HashSet<>(); + configedRegistries.addAll(getSubProperties(Environment.getInstance().getExternalConfigurationMap(), + Constants.REGISTRIES_SUFFIX)); + configedRegistries.addAll(getSubProperties(Environment.getInstance().getAppExternalConfigurationMap(), + Constants.REGISTRIES_SUFFIX)); + + registryIds = String.join(",", configedRegistries); + } + + if (StringUtils.isEmpty(registryIds)) { + if (CollectionUtils.isEmpty(registries)) { + setRegistries( + ConfigManager.getInstance().getDefaultRegistries() + .filter(CollectionUtils::isNotEmpty) + .orElseGet(() -> { + RegistryConfig registryConfig = new RegistryConfig(); + registryConfig.refresh(); + return Arrays.asList(registryConfig); + }) + ); + } + } else { + String[] ids = Constants.COMMA_SPLIT_PATTERN.split(registryIds); + List tmpRegistries = CollectionUtils.isNotEmpty(registries) ? registries : new ArrayList<>(); + Arrays.stream(ids).forEach(id -> { + if (tmpRegistries.stream().noneMatch(reg -> reg.getId().equals(id))) { + tmpRegistries.add(ConfigManager.getInstance().getRegistry(id).orElseGet(() -> { + RegistryConfig registryConfig = new RegistryConfig(); + registryConfig.setId(id); + registryConfig.refresh(); + return registryConfig; + })); + } + }); + + if (tmpRegistries.size() > ids.length) { + throw new IllegalStateException("Too much registries found, the registries assigned to this service " + + "are :" + registryIds + ", but got " + tmpRegistries.size() + " registries!"); + } + + setRegistries(tmpRegistries); + } + + } + + private void loadRegistriesFromBackwardConfig() { + // for backward compatibility + // -Ddubbo.registry.address is now deprecated. + if (registries == null || registries.isEmpty()) { + String address = ConfigUtils.getProperty("dubbo.registry.address"); + if (address != null && address.length() > 0) { + List tmpRegistries = new ArrayList(); + String[] as = address.split("\\s*[|]+\\s*"); + for (String a : as) { + RegistryConfig registryConfig = new RegistryConfig(); + registryConfig.setAddress(a); + registryConfig.refresh(); + tmpRegistries.add(registryConfig); + } + setRegistries(tmpRegistries); + } + } + } + + /** + * For compatibility purpose, use registry as the default config center if the registry protocol is zookeeper and + * there's no config center specified explicitly. + */ + private void useRegistryForConfigIfNecessary() { + registries.stream().filter(RegistryConfig::isZookeeperProtocol).findFirst().ifPresent(rc -> { + // we use the loading status of DynamicConfiguration to decide whether ConfigCenter has been initiated. + Environment.getInstance().getDynamicConfiguration().orElseGet(() -> { + ConfigManager configManager = ConfigManager.getInstance(); + ConfigCenterConfig cc = configManager.getConfigCenter().orElse(new ConfigCenterConfig()); + cc.setProtocol(rc.getProtocol()); + cc.setAddress(rc.getAddress()); + cc.setHighestPriority(false); + setConfigCenter(cc); + startConfigCenter(); + return null; + }); + }); + } + + /** + * @return local + * @deprecated Replace to getStub() + */ + @Deprecated + public String getLocal() { + return local; + } + + /** + * @param local + * @deprecated Replace to setStub(Boolean) + */ + @Deprecated + public void setLocal(Boolean local) { + if (local == null) { + setLocal((String) null); + } else { + setLocal(String.valueOf(local)); + } + } + + /** + * @param local + * @deprecated Replace to setStub(String) + */ + @Deprecated + public void setLocal(String local) { + checkName("local", local); + this.local = local; + } + + public String getStub() { + return stub; + } + + public void setStub(Boolean stub) { + if (stub == null) { + setStub((String) null); + } else { + setStub(String.valueOf(stub)); + } + } + + public void setStub(String stub) { + checkName("stub", stub); + this.stub = stub; + } + + public String getCluster() { + return cluster; + } + + public void setCluster(String cluster) { + checkExtension(Cluster.class, "cluster", cluster); + this.cluster = cluster; + } + + public String getProxy() { + return proxy; + } + + public void setProxy(String proxy) { + checkExtension(ProxyFactory.class, "proxy", proxy); + this.proxy = proxy; + } + + public Integer getConnections() { + return connections; + } + + public void setConnections(Integer connections) { + this.connections = connections; + } + + @Parameter(key = Constants.REFERENCE_FILTER_KEY, append = true) + public String getFilter() { + return filter; + } + + public void setFilter(String filter) { + checkMultiExtension(Filter.class, "filter", filter); + this.filter = filter; + } + + @Parameter(key = Constants.INVOKER_LISTENER_KEY, append = true) + public String getListener() { + return listener; + } + + public void setListener(String listener) { + checkMultiExtension(InvokerListener.class, "listener", listener); + this.listener = listener; + } + + public String getLayer() { + return layer; + } + + public void setLayer(String layer) { + checkNameHasSymbol("layer", layer); + this.layer = layer; + } + + public ApplicationConfig getApplication() { + return application; + } + + public void setApplication(ApplicationConfig application) { + ConfigManager.getInstance().setApplication(application); + this.application = application; + } + + private void createApplicationIfAbsent() { + if (this.application != null) { + return; + } + ConfigManager configManager = ConfigManager.getInstance(); + setApplication( + configManager + .getApplication() + .orElseGet(() -> { + ApplicationConfig applicationConfig = new ApplicationConfig(); + applicationConfig.refresh(); + return applicationConfig; + }) + ); + } + + public ModuleConfig getModule() { + return module; + } + + public void setModule(ModuleConfig module) { + ConfigManager.getInstance().setModule(module); + this.module = module; + } + + public RegistryConfig getRegistry() { + return CollectionUtils.isEmpty(registries) ? null : registries.get(0); + } + + public void setRegistry(RegistryConfig registry) { + List registries = new ArrayList(1); + registries.add(registry); + setRegistries(registries); + } + + public List getRegistries() { + return registries; + } + + @SuppressWarnings({"unchecked"}) + public void setRegistries(List registries) { + ConfigManager.getInstance().addRegistries((List) registries); + this.registries = (List) registries; + } + + @Parameter(excluded = true) + public String getRegistryIds() { + return registryIds; + } + + public void setRegistryIds(String registryIds) { + this.registryIds = registryIds; + } + + public MonitorConfig getMonitor() { + return monitor; + } + + public void setMonitor(String monitor) { + setMonitor(new MonitorConfig(monitor)); + } + + public void setMonitor(MonitorConfig monitor) { + ConfigManager.getInstance().setMonitor(monitor); + this.monitor = monitor; + } + + public String getOwner() { + return owner; + } + + public void setOwner(String owner) { + checkMultiName("owner", owner); + this.owner = owner; + } + + public ConfigCenterConfig getConfigCenter() { + return configCenter; + } + + public void setConfigCenter(ConfigCenterConfig configCenter) { + ConfigManager.getInstance().setConfigCenter(configCenter); + this.configCenter = configCenter; + } + + public Integer getCallbacks() { + return callbacks; + } + + public void setCallbacks(Integer callbacks) { + this.callbacks = callbacks; + } + + public String getOnconnect() { + return onconnect; + } + + public void setOnconnect(String onconnect) { + this.onconnect = onconnect; + } + + public String getOndisconnect() { + return ondisconnect; + } + + public void setOndisconnect(String ondisconnect) { + this.ondisconnect = ondisconnect; + } + + public String getScope() { + return scope; + } + + public void setScope(String scope) { + this.scope = scope; + } + + public MetadataReportConfig getMetadataReportConfig() { + return metadataReportConfig; + } + + public void setMetadataReportConfig(MetadataReportConfig metadataReportConfig) { + this.metadataReportConfig = metadataReportConfig; + } + +} diff --git a/dubbo-config/dubbo-config-api/src/main/java/org/apache/dubbo/config/AbstractServiceConfig.java b/dubbo-config/dubbo-config-api/src/main/java/org/apache/dubbo/config/AbstractServiceConfig.java index 74560a143e0..4fffd755229 100644 --- a/dubbo-config/dubbo-config-api/src/main/java/org/apache/dubbo/config/AbstractServiceConfig.java +++ b/dubbo-config/dubbo-config-api/src/main/java/org/apache/dubbo/config/AbstractServiceConfig.java @@ -17,6 +17,7 @@ package org.apache.dubbo.config; import org.apache.dubbo.common.Constants; +import org.apache.dubbo.config.context.ConfigManager; import org.apache.dubbo.common.utils.CollectionUtils; import org.apache.dubbo.config.support.Parameter; import org.apache.dubbo.rpc.ExporterListener; @@ -200,6 +201,7 @@ public List getProtocols() { @SuppressWarnings({"unchecked"}) public void setProtocols(List protocols) { + ConfigManager.getInstance().addProtocols((List) protocols); this.protocols = (List) protocols; } @@ -208,7 +210,7 @@ public ProtocolConfig getProtocol() { } public void setProtocol(ProtocolConfig protocol) { - this.protocols = Arrays.asList(protocol); + setProtocols(Arrays.asList(protocol)); } @Parameter(excluded = true) @@ -286,7 +288,7 @@ public void setSerialization(String serialization) { this.serialization = serialization; } - @Parameter(key = "dubbo.tag", useKeyAsProperty = false) + @Parameter(key = Constants.TAG_KEY, useKeyAsProperty = false) public String getTag() { return tag; } diff --git a/dubbo-config/dubbo-config-api/src/main/java/org/apache/dubbo/config/ConfigCenterConfig.java b/dubbo-config/dubbo-config-api/src/main/java/org/apache/dubbo/config/ConfigCenterConfig.java index 84e7fddd302..58c613834ae 100644 --- a/dubbo-config/dubbo-config-api/src/main/java/org/apache/dubbo/config/ConfigCenterConfig.java +++ b/dubbo-config/dubbo-config-api/src/main/java/org/apache/dubbo/config/ConfigCenterConfig.java @@ -19,18 +19,11 @@ import org.apache.dubbo.common.Constants; import org.apache.dubbo.common.URL; import org.apache.dubbo.common.config.Environment; -import org.apache.dubbo.common.extension.ExtensionLoader; import org.apache.dubbo.common.utils.StringUtils; import org.apache.dubbo.common.utils.UrlUtils; import org.apache.dubbo.config.support.Parameter; -import org.apache.dubbo.configcenter.DynamicConfiguration; -import org.apache.dubbo.configcenter.DynamicConfigurationFactory; -import java.io.IOException; -import java.io.StringReader; -import java.util.HashMap; import java.util.Map; -import java.util.Properties; import java.util.concurrent.atomic.AtomicBoolean; /** @@ -54,60 +47,13 @@ public class ConfigCenterConfig extends AbstractConfig { private String configFile = "dubbo.properties"; private String appConfigFile; - private ApplicationConfig application; - private RegistryConfig registry; - // customized parameters private Map parameters; public ConfigCenterConfig() { } - public void init() { - if (!inited.compareAndSet(false, true)) { - return; - } - - // give jvm properties the chance to override local configs, e.g., -Ddubbo.configcenter.highestPriority - refresh(); - - // try to use registryConfig as the default configcenter, only applies to zookeeper. - if (!isValid() && registry != null && registry.isZookeeperProtocol()) { - setAddress(registry.getAddress()); - setProtocol(registry.getProtocol()); - } -// checkConfigCenter(); - - if (isValid()) { - DynamicConfiguration dynamicConfiguration = startDynamicConfiguration(toConfigUrl()); - String configContent = dynamicConfiguration.getConfig(configFile, group); - - String appGroup = getApplicationName(); - String appConfigContent = null; - if (StringUtils.isNotEmpty(appGroup)) { - appConfigContent = dynamicConfiguration.getConfig - (StringUtils.isNotEmpty(appConfigFile) ? appConfigFile : configFile, - appGroup - ); - } - try { - Environment.getInstance().setConfigCenterFirst(highestPriority); - Environment.getInstance().updateExternalConfigurationMap(parseProperties(configContent)); - Environment.getInstance().updateAppExternalConfigurationMap(parseProperties(appConfigContent)); - } catch (IOException e) { - throw new IllegalStateException("Failed to parse configurations from Config Center.", e); - } - } - } - - private DynamicConfiguration startDynamicConfiguration(URL url) { - DynamicConfigurationFactory dynamicConfigurationFactory = ExtensionLoader.getExtensionLoader(DynamicConfigurationFactory.class).getExtension(url.getProtocol()); - DynamicConfiguration configuration = dynamicConfigurationFactory.getDynamicConfiguration(url); - Environment.getInstance().setDynamicConfiguration(configuration); - return configuration; - } - - private URL toConfigUrl() { + public URL toUrl() { Map map = this.getMetaData(); if (StringUtils.isEmpty(address)) { address = Constants.ANYHOST_VALUE; @@ -120,39 +66,16 @@ private URL toConfigUrl() { return UrlUtils.parseURL(address, map); } - private String getApplicationName() { - if (application != null) { - if (!application.isValid()) { - throw new IllegalStateException( - "No application config found or it's not a valid config! Please add to your spring config."); - } - return application.getName(); - } - return appName; - } - - protected Map parseProperties(String content) throws IOException { - Map map = new HashMap<>(); - if (StringUtils.isEmpty(content)) { - logger.warn("You specified the config centre, but there's not even one single config item in it."); - } else { - Properties properties = new Properties(); - properties.load(new StringReader(content)); - properties.stringPropertyNames().forEach( - k -> map.put(k, properties.getProperty(k)) - ); - } - return map; + public boolean checkOrUpdateInited() { + return inited.compareAndSet(false, true); } public void setExternalConfig(Map externalConfiguration) { Environment.getInstance().setExternalConfigMap(externalConfiguration); - inited.set(true); } public void setAppExternalConfig(Map appExternalConfiguration) { Environment.getInstance().setAppExternalConfigMap(appExternalConfiguration); - inited.set(true); } public String getProtocol() { @@ -209,7 +132,7 @@ public void setCheck(Boolean check) { } @Parameter(key = Constants.CONFIG_ENABLE_KEY, useKeyAsProperty = false) - public Boolean getHighestPriority() { + public Boolean isHighestPriority() { return highestPriority; } @@ -278,29 +201,6 @@ public void setParameters(Map parameters) { this.parameters = parameters; } - public ApplicationConfig getApplication() { - return application; - } - - public void setApplication(ApplicationConfig application) { - this.application = application; - } - - public RegistryConfig getRegistry() { - return registry; - } - - public void setRegistry(RegistryConfig registry) { - this.registry = registry; - } - - private void checkConfigCenter() { - if (StringUtils.isEmpty(address) - || (StringUtils.isEmpty(protocol) && (StringUtils.isEmpty(address) || !address.contains("://")))) { - throw new IllegalStateException("You must specify the right parameter for configcenter."); - } - } - @Override @Parameter(excluded = true) public boolean isValid() { diff --git a/dubbo-config/dubbo-config-api/src/main/java/org/apache/dubbo/config/MetadataReportConfig.java b/dubbo-config/dubbo-config-api/src/main/java/org/apache/dubbo/config/MetadataReportConfig.java index a134eef9085..a4ace7a266d 100644 --- a/dubbo-config/dubbo-config-api/src/main/java/org/apache/dubbo/config/MetadataReportConfig.java +++ b/dubbo-config/dubbo-config-api/src/main/java/org/apache/dubbo/config/MetadataReportConfig.java @@ -16,11 +16,14 @@ */ package org.apache.dubbo.config; +import org.apache.dubbo.common.Constants; import org.apache.dubbo.common.utils.StringUtils; import org.apache.dubbo.config.support.Parameter; import java.util.Map; +import static org.apache.dubbo.common.Constants.PROPERTIES_CHAR_SEPERATOR; + /** * RegistryConfig * @@ -29,6 +32,12 @@ public class MetadataReportConfig extends AbstractConfig { private static final long serialVersionUID = 55233L; + /** + * the value is : metadata-report + */ + private static final String PREFIX_TAG = StringUtils.camelToSplitName( + MetadataReportConfig.class.getSimpleName().substring(0, MetadataReportConfig.class.getSimpleName().length() - 6), PROPERTIES_CHAR_SEPERATOR); + // Register center address private String address; @@ -41,6 +50,11 @@ public class MetadataReportConfig extends AbstractConfig { // Request timeout in milliseconds for register center private Integer timeout; + /** + * The group the metadata in . It is the same as registry + */ + private String group; + // Customized parameters private Map parameters; @@ -64,6 +78,7 @@ public MetadataReportConfig(String address) { setAddress(address); } + @Parameter(excluded = true) public String getAddress() { return address; } @@ -104,6 +119,7 @@ public void setParameters(Map parameters) { this.parameters = parameters; } + @Parameter(key = "retry-times") public Integer getRetryTimes() { return retryTimes; } @@ -112,6 +128,7 @@ public void setRetryTimes(Integer retryTimes) { this.retryTimes = retryTimes; } + @Parameter(key = "retry-period") public Integer getRetryPeriod() { return retryPeriod; } @@ -120,6 +137,7 @@ public void setRetryPeriod(Integer retryPeriod) { this.retryPeriod = retryPeriod; } + @Parameter(key = "cycle-report") public Boolean getCycleReport() { return cycleReport; } @@ -128,17 +146,32 @@ public void setCycleReport(Boolean cycleReport) { this.cycleReport = cycleReport; } + @Parameter(key = "sync-report") + public Boolean getSyncReport() { + return syncReport; + } + + public void setSyncReport(Boolean syncReport) { + this.syncReport = syncReport; + } + + @Override + @Parameter(excluded = true) + public String getPrefix() { + return StringUtils.isNotEmpty(prefix) ? prefix : (Constants.DUBBO + "." + PREFIX_TAG); + } + @Override @Parameter(excluded = true) public boolean isValid() { return StringUtils.isNotEmpty(address); } - public Boolean getSyncReport() { - return syncReport; + public String getGroup() { + return group; } - public void setSyncReport(Boolean syncReport) { - this.syncReport = syncReport; + public void setGroup(String group) { + this.group = group; } } diff --git a/dubbo-config/dubbo-config-api/src/main/java/org/apache/dubbo/config/ProtocolConfig.java b/dubbo-config/dubbo-config-api/src/main/java/org/apache/dubbo/config/ProtocolConfig.java index f419244ec43..5f60b4f736e 100644 --- a/dubbo-config/dubbo-config-api/src/main/java/org/apache/dubbo/config/ProtocolConfig.java +++ b/dubbo-config/dubbo-config-api/src/main/java/org/apache/dubbo/config/ProtocolConfig.java @@ -533,6 +533,18 @@ public void destroy() { } } + @Override + public void refresh() { + if (StringUtils.isEmpty(this.getName())) { + this.setName(Constants.DUBBO_VERSION_KEY); + } + super.refresh(); + if (StringUtils.isNotEmpty(this.getId())) { + this.setPrefix(Constants.PROTOCOLS_SUFFIX); + super.refresh(); + } + } + @Override @Parameter(excluded = true) public boolean isValid() { diff --git a/dubbo-config/dubbo-config-api/src/main/java/org/apache/dubbo/config/ReferenceConfig.java b/dubbo-config/dubbo-config-api/src/main/java/org/apache/dubbo/config/ReferenceConfig.java index 55020268f2b..71d05739a1d 100644 --- a/dubbo-config/dubbo-config-api/src/main/java/org/apache/dubbo/config/ReferenceConfig.java +++ b/dubbo-config/dubbo-config-api/src/main/java/org/apache/dubbo/config/ReferenceConfig.java @@ -27,6 +27,7 @@ import org.apache.dubbo.common.utils.StringUtils; import org.apache.dubbo.common.utils.CollectionUtils; import org.apache.dubbo.config.annotation.Reference; +import org.apache.dubbo.config.context.ConfigManager; import org.apache.dubbo.config.support.Parameter; import org.apache.dubbo.metadata.integration.MetadataReportService; import org.apache.dubbo.rpc.Invoker; @@ -195,6 +196,8 @@ public void checkAndUpdateSubConfigs() { if (StringUtils.isEmpty(interfaceName)) { throw new IllegalStateException(" interface not allow null!"); } + completeCompoundConfigs(); + startConfigCenter(); // get consumer's global configuration checkDefault(); this.refresh(); @@ -213,18 +216,8 @@ public void checkAndUpdateSubConfigs() { checkInterfaceAndMethods(interfaceClass, methods); } resolveFile(); - if (consumer != null) { - inheritIfAbsentFromConsumer(); - } - if (module != null) { - inheritIfAbsentFromModule(); - } - if (application != null) { - inheritIfAbsentFromApplication(); - } checkApplication(); checkMetadataReport(); - checkRegistryDataConfig(); } public synchronized T get() { @@ -354,6 +347,7 @@ private T createProxy(Map map) { } } } else { // assemble URL from register center's configuration + checkRegistry(); List us = loadRegistries(false); if (CollectionUtils.isNotEmpty(us)) { for (URL u : us) { @@ -420,46 +414,57 @@ private T createProxy(Map map) { } private void checkDefault() { - if (consumer == null) { - consumer = new ConsumerConfig(); - } - consumer.refresh(); + createConsumerIfAbsent(); } - private void inheritIfAbsentFromConsumer() { - if (application == null) { - application = consumer.getApplication(); - } - if (module == null) { - module = consumer.getModule(); - } - if (registries == null) { - registries = consumer.getRegistries(); - } - if (monitor == null) { - monitor = consumer.getMonitor(); + private void createConsumerIfAbsent() { + if (consumer != null) { + return; } + setConsumer( + ConfigManager.getInstance() + .getDefaultConsumer() + .orElseGet(() -> { + ConsumerConfig consumerConfig = new ConsumerConfig(); + consumerConfig.refresh(); + return consumerConfig; + }) + ); } - private void inheritIfAbsentFromModule() { - if (registries == null) { - registries = module.getRegistries(); - } - if (monitor == null) { - monitor = module.getMonitor(); + private void completeCompoundConfigs() { + if (consumer != null) { + if (application == null) { + setApplication(consumer.getApplication()); + } + if (module == null) { + setModule(consumer.getModule()); + } + if (registries == null) { + setRegistries(consumer.getRegistries()); + } + if (monitor == null) { + setMonitor(consumer.getMonitor()); + } } - } - - private void inheritIfAbsentFromApplication() { - if (registries == null) { - registries = application.getRegistries(); + if (module != null) { + if (registries == null) { + setRegistries(module.getRegistries()); + } + if (monitor == null) { + setMonitor(module.getMonitor()); + } } - if (monitor == null) { - monitor = application.getMonitor(); + if (application != null) { + if (registries == null) { + setRegistries(application.getRegistries()); + } + if (monitor == null) { + setMonitor(application.getMonitor()); + } } } - public Class getInterfaceClass() { if (interfaceClass != null) { return interfaceClass; @@ -539,6 +544,7 @@ public ConsumerConfig getConsumer() { } public void setConsumer(ConsumerConfig consumer) { + ConfigManager.getInstance().addConsumer(consumer); this.consumer = consumer; } @@ -587,21 +593,12 @@ private void resolveFile() { } if (resolveFile != null && resolveFile.length() > 0) { Properties properties = new Properties(); - FileInputStream fis = null; - try { - fis = new FileInputStream(new File(resolveFile)); + try (FileInputStream fis = new FileInputStream(new File(resolveFile))) { properties.load(fis); } catch (IOException e) { throw new IllegalStateException("Failed to load " + resolveFile + ", cause: " + e.getMessage(), e); - } finally { - try { - if (null != fis) { - fis.close(); - } - } catch (IOException e) { - logger.warn(e.getMessage(), e); - } } + resolve = properties.getProperty(interfaceName); } } diff --git a/dubbo-config/dubbo-config-api/src/main/java/org/apache/dubbo/config/RegistryConfig.java b/dubbo-config/dubbo-config-api/src/main/java/org/apache/dubbo/config/RegistryConfig.java index 0006b0e3595..43d683c7f7c 100644 --- a/dubbo-config/dubbo-config-api/src/main/java/org/apache/dubbo/config/RegistryConfig.java +++ b/dubbo-config/dubbo-config-api/src/main/java/org/apache/dubbo/config/RegistryConfig.java @@ -126,18 +126,19 @@ public class RegistryConfig extends AbstractConfig { private Boolean isDefault; /** - * Simple the registry. + * Simple the registry. both useful for provider and consumer * * @since 2.7.0 */ - private Boolean simple; + private Boolean simplified; /** - * After simplify the registry, should add some parameter individually. - * additionalParameterKeys = addParamKeys + * After simplify the registry, should add some paramter individually. just for provider. + *

+ * such as: extra-keys = A,b,c,d * * @since 2.7.0 */ - private String addParamKeys; + private String extraKeys; public RegistryConfig() { } @@ -380,6 +381,23 @@ public void setDefault(Boolean isDefault) { this.isDefault = isDefault; } + public Boolean getSimplified() { + return simplified; + } + + public void setSimplified(Boolean simplified) { + this.simplified = simplified; + } + + @Parameter(key = Constants.EXTRA_KEYS_KEY) + public String getExtraKeys() { + return extraKeys; + } + + public void setExtraKeys(String extraKeys) { + this.extraKeys = extraKeys; + } + @Parameter(excluded = true) public boolean isZookeeperProtocol() { if (!isValid()) { @@ -389,6 +407,15 @@ public boolean isZookeeperProtocol() { || getAddress().startsWith(Constants.ZOOKEEPER_PROTOCOL); } + @Override + public void refresh() { + super.refresh(); + if (StringUtils.isNotEmpty(this.getId())) { + this.setPrefix(Constants.REGISTRIES_SUFFIX); + super.refresh(); + } + } + @Override @Parameter(excluded = true) public boolean isValid() { diff --git a/dubbo-config/dubbo-config-api/src/main/java/org/apache/dubbo/config/RegistryDataConfig.java b/dubbo-config/dubbo-config-api/src/main/java/org/apache/dubbo/config/RegistryDataConfig.java deleted file mode 100644 index f96044dd991..00000000000 --- a/dubbo-config/dubbo-config-api/src/main/java/org/apache/dubbo/config/RegistryDataConfig.java +++ /dev/null @@ -1,62 +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.config; - -/** - * 2018/10/31 - */ -public class RegistryDataConfig extends AbstractConfig { - - private Boolean simpleProviderConfig; - private String extraProviderKeys; - - private Boolean simpleConsumerConfig; - private String extraConsumerKeys; - - public Boolean getSimpleProviderConfig() { - return simpleProviderConfig; - } - - public void setSimpleProviderConfig(Boolean simpleProviderConfig) { - this.simpleProviderConfig = simpleProviderConfig; - } - - public Boolean getSimpleConsumerConfig() { - return simpleConsumerConfig; - } - - public void setSimpleConsumerConfig(Boolean simpleConsumerConfig) { - this.simpleConsumerConfig = simpleConsumerConfig; - } - - public String getExtraProviderKeys() { - return extraProviderKeys; - } - - public void setExtraProviderKeys(String extraProviderKeys) { - this.extraProviderKeys = extraProviderKeys; - } - - - public String getExtraConsumerKeys() { - return extraConsumerKeys; - } - - public void setExtraConsumerKeys(String extraConsumerKeys) { - this.extraConsumerKeys = extraConsumerKeys; - } -} diff --git a/dubbo-config/dubbo-config-api/src/main/java/org/apache/dubbo/config/ServiceConfig.java b/dubbo-config/dubbo-config-api/src/main/java/org/apache/dubbo/config/ServiceConfig.java index 8e6bccc4218..3a85ac8b274 100644 --- a/dubbo-config/dubbo-config-api/src/main/java/org/apache/dubbo/config/ServiceConfig.java +++ b/dubbo-config/dubbo-config-api/src/main/java/org/apache/dubbo/config/ServiceConfig.java @@ -23,11 +23,13 @@ import org.apache.dubbo.common.config.Environment; import org.apache.dubbo.common.extension.ExtensionLoader; import org.apache.dubbo.common.utils.ClassHelper; +import org.apache.dubbo.common.utils.CollectionUtils; import org.apache.dubbo.common.utils.ConfigUtils; import org.apache.dubbo.common.utils.NamedThreadFactory; import org.apache.dubbo.common.utils.StringUtils; import org.apache.dubbo.common.utils.CollectionUtils; import org.apache.dubbo.config.annotation.Service; +import org.apache.dubbo.config.context.ConfigManager; import org.apache.dubbo.config.invoker.DelegateProviderMetaDataInvoker; import org.apache.dubbo.config.support.Parameter; import org.apache.dubbo.metadata.integration.MetadataReportService; @@ -260,23 +262,16 @@ public boolean isUnexported() { } public void checkAndUpdateSubConfigs() { + // Use default configs defined explicitly on global configs + completeCompoundConfigs(); + // Config Center should always being started first. + startConfigCenter(); checkDefault(); - if (provider != null) { - inheritIfAbsentFromProvider(); - } - if (module != null) { - inheritIfAbsentFromModule(); - } - if (application != null) { - inheritIfAbsentFromApplication(); - } - checkApplication(); checkRegistry(); checkProtocol(); this.refresh(); checkMetadataReport(); - checkRegistryDataConfig(); if (StringUtils.isEmpty(interfaceName)) { throw new IllegalStateException(" interface not allow null!"); @@ -503,10 +498,6 @@ private void doExportUrlsFor1Protocol(ProtocolConfig protocolConfig, List r map.put(Constants.TOKEN_KEY, token); } } - if (Constants.LOCAL_PROTOCOL.equals(protocolConfig.getName())) { - protocolConfig.setRegister(false); - map.put("notify", "false"); - } // export service String contextPath = protocolConfig.getContextpath(); if (StringUtils.isEmpty(contextPath) && provider != null) { @@ -593,42 +584,6 @@ private void exportLocal(URL url) { } } - private void inheritIfAbsentFromProvider() { - if (application == null) { - application = provider.getApplication(); - } - if (module == null) { - module = provider.getModule(); - } - if (registries == null) { - registries = provider.getRegistries(); - } - if (monitor == null) { - monitor = provider.getMonitor(); - } - if (protocols == null) { - protocols = provider.getProtocols(); - } - } - - private void inheritIfAbsentFromModule() { - if (registries == null) { - registries = module.getRegistries(); - } - if (monitor == null) { - monitor = module.getMonitor(); - } - } - - private void inheritIfAbsentFromApplication() { - if (registries == null) { - registries = application.getRegistries(); - } - if (monitor == null) { - monitor = application.getMonitor(); - } - } - protected Class getServiceClass(T ref) { return ref.getClass(); } @@ -671,19 +626,11 @@ private String findConfigedHosts(ProtocolConfig protocolConfig, List regist // skip multicast registry since we cannot connect to it via Socket continue; } - try { - Socket socket = new Socket(); - try { - SocketAddress addr = new InetSocketAddress(registryURL.getHost(), registryURL.getPort()); - socket.connect(addr, 1000); - hostToBind = socket.getLocalAddress().getHostAddress(); - break; - } finally { - try { - socket.close(); - } catch (Throwable e) { - } - } + try (Socket socket = new Socket()) { + SocketAddress addr = new InetSocketAddress(registryURL.getHost(), registryURL.getPort()); + socket.connect(addr, 1000); + hostToBind = socket.getLocalAddress().getHostAddress(); + break; } catch (Exception e) { logger.warn(e.getMessage(), e); } @@ -785,30 +732,69 @@ private String getValueFromConfig(ProtocolConfig protocolConfig, String key) { return port; } + private void completeCompoundConfigs() { + if (provider != null) { + if (application == null) { + setApplication(provider.getApplication()); + } + if (module == null) { + setModule(provider.getModule()); + } + if (registries == null) { + setRegistries(provider.getRegistries()); + } + if (monitor == null) { + setMonitor(provider.getMonitor()); + } + if (protocols == null) { + setProtocols(provider.getProtocols()); + } + if (configCenter == null) { + setConfigCenter(provider.getConfigCenter()); + } + } + if (module != null) { + if (registries == null) { + setRegistries(module.getRegistries()); + } + if (monitor == null) { + setMonitor(module.getMonitor()); + } + } + if (application != null) { + if (registries == null) { + setRegistries(application.getRegistries()); + } + if (monitor == null) { + setMonitor(application.getMonitor()); + } + } + } + private void checkDefault() { - if (provider == null) { - provider = new ProviderConfig(); + createProviderIfAbsent(); + } + + private void createProviderIfAbsent() { + if (provider != null) { + return; } - provider.refresh(); + setProvider ( + ConfigManager.getInstance() + .getDefaultProvider() + .orElseGet(() -> { + ProviderConfig providerConfig = new ProviderConfig(); + providerConfig.refresh(); + return providerConfig; + }) + ); } private void checkProtocol() { if (CollectionUtils.isEmpty(protocols) && provider != null) { setProtocols(provider.getProtocols()); } - convertProtocolIdsToProtocols(); - - for (ProtocolConfig protocolConfig : protocols) { - if (StringUtils.isEmpty(protocolConfig.getName())) { - protocolConfig.setName(Constants.DUBBO_VERSION_KEY); - } - protocolConfig.refresh(); - if (StringUtils.isNotEmpty(protocolConfig.getId())) { - protocolConfig.setPrefix("dubbo.protocols."); - protocolConfig.refresh(); - } - } } private void convertProtocolIdsToProtocols() { @@ -824,25 +810,34 @@ private void convertProtocolIdsToProtocols() { if (StringUtils.isEmpty(protocolIds)) { if (CollectionUtils.isEmpty(protocols)) { - protocols = new ArrayList<>(); - protocols.add(new ProtocolConfig()); + setProtocols( + ConfigManager.getInstance().getDefaultProtocols() + .filter(CollectionUtils::isNotEmpty) + .orElseGet(() -> { + ProtocolConfig protocolConfig = new ProtocolConfig(); + protocolConfig.refresh(); + return Arrays.asList(protocolConfig); + }) + ); } } else { String[] arr = Constants.COMMA_SPLIT_PATTERN.split(protocolIds); - if (CollectionUtils.isEmpty(protocols)) { - protocols = new ArrayList<>(); - } + List tmpProtocols = CollectionUtils.isNotEmpty(protocols) ? protocols : new ArrayList<>(); Arrays.stream(arr).forEach(id -> { - if (protocols.stream().noneMatch(prot -> prot.getId().equals(id))) { - ProtocolConfig protocolConfig = new ProtocolConfig(); - protocolConfig.setId(id); - protocols.add(protocolConfig); + if (tmpProtocols.stream().noneMatch(prot -> prot.getId().equals(id))) { + tmpProtocols.add(ConfigManager.getInstance().getProtocol(id).orElseGet(() -> { + ProtocolConfig protocolConfig = new ProtocolConfig(); + protocolConfig.setId(id); + protocolConfig.refresh(); + return protocolConfig; + })); } }); - if (protocols.size() > arr.length) { + if (tmpProtocols.size() > arr.length) { throw new IllegalStateException("Too much protocols found, the protocols comply to this service are :" + protocolIds + " but got " + protocols .size() + " registries!"); } + setProtocols(tmpProtocols); } } @@ -926,6 +921,7 @@ public ProviderConfig getProvider() { } public void setProvider(ProviderConfig provider) { + ConfigManager.getInstance().addProvider(provider); this.provider = provider; } diff --git a/dubbo-config/dubbo-config-api/src/main/java/org/apache/dubbo/config/context/ConfigManager.java b/dubbo-config/dubbo-config-api/src/main/java/org/apache/dubbo/config/context/ConfigManager.java new file mode 100644 index 00000000000..ae16ef961a2 --- /dev/null +++ b/dubbo-config/dubbo-config-api/src/main/java/org/apache/dubbo/config/context/ConfigManager.java @@ -0,0 +1,331 @@ +/* + * 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.context; + +import org.apache.dubbo.common.logger.Logger; +import org.apache.dubbo.common.logger.LoggerFactory; +import org.apache.dubbo.common.utils.StringUtils; +import org.apache.dubbo.config.AbstractConfig; +import org.apache.dubbo.config.ApplicationConfig; +import org.apache.dubbo.config.ConfigCenterConfig; +import org.apache.dubbo.config.ConsumerConfig; +import org.apache.dubbo.config.ModuleConfig; +import org.apache.dubbo.config.MonitorConfig; +import org.apache.dubbo.config.ProtocolConfig; +import org.apache.dubbo.config.ProviderConfig; +import org.apache.dubbo.config.RegistryConfig; + +import java.util.ArrayList; +import java.util.List; +import java.util.Map; +import java.util.Optional; +import java.util.concurrent.ConcurrentHashMap; + +import static org.apache.dubbo.common.Constants.DEFAULT_KEY; + +/** + * TODO + * Experimental API, should only being used internally at present. + *

+ * Maybe we can consider open to end user in the following version by providing a fluent style builder. + * + *

{@code
+ *  public void class DubboBuilder() {
+ *
+ *      public static DubboBuilder create() {
+ *          return new DubboBuilder();
+ *      }
+ *
+ *      public DubboBuilder application(ApplicationConfig application) {
+ *          ConfigManager.getInstance().addApplication(application);
+ *          return this;
+ *      }
+ *
+ *      ...
+ *
+ *      public void build() {
+ *          // export all ServiceConfigs
+ *          // refer all ReferenceConfigs
+ *      }
+ *  }
+ *  }
+ * 
+ *

+ * TODO + * The properties defined here are duplicate with that in ReferenceConfig/ServiceConfig, + * the properties here are currently only used for duplication check but are still not being used in the export/refer process yet. + * Maybe we can remove the property definition in ReferenceConfig/ServiceConfig and only keep the setXxxConfig() as an entrance. + * All workflow internally can rely on ConfigManager. + */ +public class ConfigManager { + private static final Logger logger = LoggerFactory.getLogger(ConfigManager.class); + private static final ConfigManager configManager = new ConfigManager(); + + private ApplicationConfig application; + private MonitorConfig monitor; + private ModuleConfig module; + private ConfigCenterConfig configCenter; + + private Map protocols = new ConcurrentHashMap<>(); + private Map registries = new ConcurrentHashMap<>(); + private Map providers = new ConcurrentHashMap<>(); + private Map consumers = new ConcurrentHashMap<>(); + + public static ConfigManager getInstance() { + return configManager; + } + + private ConfigManager() { + + } + + public Optional getApplication() { + return Optional.ofNullable(application); + } + + public void setApplication(ApplicationConfig application) { + if (application != null) { + checkDuplicate(this.application, application); + this.application = application; + } + } + + public Optional getMonitor() { + return Optional.ofNullable(monitor); + } + + public void setMonitor(MonitorConfig monitor) { + if (monitor != null) { + checkDuplicate(this.monitor, monitor); + this.monitor = monitor; + } + } + + public Optional getModule() { + return Optional.ofNullable(module); + } + + public void setModule(ModuleConfig module) { + if (module != null) { + checkDuplicate(this.module, module); + this.module = module; + } + } + + public Optional getConfigCenter() { + return Optional.ofNullable(configCenter); + } + + public void setConfigCenter(ConfigCenterConfig configCenter) { + if (configCenter != null) { + checkDuplicate(this.configCenter, configCenter); + this.configCenter = configCenter; + } + } + + public Optional getProvider(String id) { + return Optional.ofNullable(providers.get(id)); + } + + public Optional getDefaultProvider() { + return Optional.ofNullable(providers.get(DEFAULT_KEY)); + } + + public void addProvider(ProviderConfig providerConfig) { + if (providerConfig == null) { + return; + } + + String key = StringUtils.isNotEmpty(providerConfig.getId()) + ? providerConfig.getId() + : (providerConfig.isDefault() == null || providerConfig.isDefault()) ? DEFAULT_KEY : null; + + if (StringUtils.isEmpty(key)) { + throw new IllegalStateException("A ProviderConfig should either has an id or it's the default one, " + providerConfig); + } + + if (providers.containsKey(key) && !providerConfig.equals(providers.get(key))) { + logger.warn("Duplicate ProviderConfig found, there already has one default ProviderConfig or more than two ProviderConfigs have the same id, " + + "you can try to give each ProviderConfig a different id. " + providerConfig); + } else { + providers.put(key, providerConfig); + } + } + + public Optional getConsumer(String id) { + return Optional.ofNullable(consumers.get(id)); + } + + public Optional getDefaultConsumer() { + return Optional.ofNullable(consumers.get(DEFAULT_KEY)); + } + + public void addConsumer(ConsumerConfig consumerConfig) { + if (consumerConfig == null) { + return; + } + + String key = StringUtils.isNotEmpty(consumerConfig.getId()) + ? consumerConfig.getId() + : (consumerConfig.isDefault() == null || consumerConfig.isDefault()) ? DEFAULT_KEY : null; + + if (StringUtils.isEmpty(key)) { + throw new IllegalStateException("A ConsumerConfig should either has an id or it's the default one, " + consumerConfig); + } + + if (consumers.containsKey(key) && !consumerConfig.equals(consumers.get(key))) { + logger.warn("Duplicate ConsumerConfig found, there already has one default ConsumerConfig or more than two ConsumerConfigs have the same id, " + + "you can try to give each ConsumerConfig a different id. " + consumerConfig); + } else { + consumers.put(key, consumerConfig); + } + } + + public Optional getProtocol(String id) { + return Optional.ofNullable(protocols.get(id)); + } + + public Optional> getDefaultProtocols() { + List defaults = new ArrayList<>(); + protocols.forEach((k, v) -> { + if (DEFAULT_KEY.equalsIgnoreCase(k)) { + defaults.add(v); + } else if (v.isDefault() == null || v.isDefault()) { + defaults.add(v); + } + }); + return Optional.of(defaults); + } + + public void addProtocols(List protocolConfigs) { + if (protocolConfigs != null) { + protocolConfigs.forEach(this::addProtocol); + } + } + + public void addProtocol(ProtocolConfig protocolConfig) { + if (protocolConfig == null) { + return; + } + + String key = StringUtils.isNotEmpty(protocolConfig.getId()) + ? protocolConfig.getId() + : (protocolConfig.isDefault() == null || protocolConfig.isDefault()) ? DEFAULT_KEY : null; + + if (StringUtils.isEmpty(key)) { + throw new IllegalStateException("A ProtocolConfig should either has an id or it's the default one, " + protocolConfig); + } + + if (protocols.containsKey(key) && !protocolConfig.equals(protocols.get(key))) { + logger.warn("Duplicate ProtocolConfig found, there already has one default ProtocolConfig or more than two ProtocolConfigs have the same id, " + + "you can try to give each ProtocolConfig a different id. " + protocolConfig); + } else { + protocols.put(key, protocolConfig); + } + } + + public Optional getRegistry(String id) { + return Optional.ofNullable(registries.get(id)); + } + + public Optional> getDefaultRegistries() { + List defaults = new ArrayList<>(); + registries.forEach((k, v) -> { + if (DEFAULT_KEY.equalsIgnoreCase(k)) { + defaults.add(v); + } else if (v.isDefault() == null || v.isDefault()) { + defaults.add(v); + } + }); + return Optional.of(defaults); + } + + public void addRegistries(List registryConfigs) { + if (registryConfigs != null) { + registryConfigs.forEach(this::addRegistry); + } + } + + public void addRegistry(RegistryConfig registryConfig) { + if (registryConfig == null) { + return; + } + + String key = StringUtils.isNotEmpty(registryConfig.getId()) + ? registryConfig.getId() + : (registryConfig.isDefault() == null || registryConfig.isDefault()) ? DEFAULT_KEY : null; + + if (StringUtils.isEmpty(key)) { + throw new IllegalStateException("A RegistryConfig should either has an id or it's the default one, " + registryConfig); + } + + if (registries.containsKey(key) && !registryConfig.equals(registries.get(key))) { + logger.warn("Duplicate RegistryConfig found, there already has one default RegistryConfig or more than two RegistryConfigs have the same id, " + + "you can try to give each RegistryConfig a different id. " + registryConfig); + } else { + registries.put(key, registryConfig); + } + } + + public Map getProtocols() { + return protocols; + } + + public Map getRegistries() { + return registries; + } + + public Map getProviders() { + return providers; + } + + public Map getConsumers() { + return consumers; + } + + public void refreshAll() { + // refresh all configs here, + getApplication().ifPresent(ApplicationConfig::refresh); + getMonitor().ifPresent(MonitorConfig::refresh); + getModule().ifPresent(ModuleConfig::refresh); + + getProtocols().values().forEach(ProtocolConfig::refresh); + getRegistries().values().forEach(RegistryConfig::refresh); + getProviders().values().forEach(ProviderConfig::refresh); + getConsumers().values().forEach(ConsumerConfig::refresh); + } + + private void checkDuplicate(AbstractConfig oldOne, AbstractConfig newOne) { + if (oldOne != null && !oldOne.equals(newOne)) { + String configName = oldOne.getClass().getSimpleName(); + throw new IllegalStateException("Duplicate Config found for " + configName + ", you should use only one unique " + configName + " for one application."); + } + } + + // For test purpose + public void clear() { + this.application = null; + this.configCenter = null; + this.monitor = null; + this.module = null; + this.registries.clear(); + this.protocols.clear(); + this.providers.clear(); + this.consumers.clear(); + } + +} diff --git a/dubbo-config/dubbo-config-api/src/test/java/org/apache/dubbo/config/AbstractConfigTest.java b/dubbo-config/dubbo-config-api/src/test/java/org/apache/dubbo/config/AbstractConfigTest.java index b8a3dc930a1..d95b2de84a9 100644 --- a/dubbo-config/dubbo-config-api/src/test/java/org/apache/dubbo/config/AbstractConfigTest.java +++ b/dubbo-config/dubbo-config-api/src/test/java/org/apache/dubbo/config/AbstractConfigTest.java @@ -17,6 +17,7 @@ package org.apache.dubbo.config; import org.apache.dubbo.common.config.Environment; +import org.apache.dubbo.common.utils.ConfigUtils; import org.apache.dubbo.config.api.Greeting; import org.apache.dubbo.config.support.Parameter; @@ -31,6 +32,7 @@ import java.util.Collections; import java.util.HashMap; import java.util.Map; +import java.util.Properties; import static org.hamcrest.MatcherAssert.assertThat; import static org.junit.jupiter.api.Assertions.assertTrue; @@ -353,7 +355,7 @@ public void testRefreshSystem() { } @Test - public void testRefreshProperties() { + public void testRefreshProperties() throws Exception{ try { Environment.getInstance().setExternalConfigMap(new HashMap<>()); OverrideConfig overrideConfig = new OverrideConfig(); @@ -361,6 +363,10 @@ public void testRefreshProperties() { overrideConfig.setProtocol("override-config"); overrideConfig.setEscape("override-config://"); + Properties properties = new Properties(); + properties.load(this.getClass().getResourceAsStream("/dubbo.properties")); + ConfigUtils.setProperties(properties); + overrideConfig.refresh(); Assertions.assertEquals("override-config://127.0.0.1:2181", overrideConfig.getAddress()); @@ -369,6 +375,7 @@ public void testRefreshProperties() { //Assertions.assertEquals("properties", overrideConfig.getUseKeyAsProperty()); } finally { Environment.getInstance().clearExternalConfigs(); + ConfigUtils.setProperties(null); } } @@ -407,7 +414,7 @@ public void testRefreshExternal() { } @Test - public void testRefreshId() { + public void testRefreshById() { try { OverrideConfig overrideConfig = new OverrideConfig(); overrideConfig.setId("override-id"); @@ -428,8 +435,7 @@ public void testRefreshId() { Environment.getInstance().setExternalConfigMap(external); ConfigCenterConfig configCenter = new ConfigCenterConfig(); - configCenter.init(); - + overrideConfig.setConfigCenter(configCenter); // Load configuration from system properties -> externalConfiguration -> RegistryConfig -> dubbo.properties overrideConfig.refresh(); @@ -475,7 +481,7 @@ public void tetMetaData() { String[] parameters() default {}; } - private static class OverrideConfig extends AbstractConfig { + private static class OverrideConfig extends AbstractInterfaceConfig { public String address; public String protocol; public String exclude; diff --git a/dubbo-config/dubbo-config-api/src/test/java/org/apache/dubbo/config/AbstractInterfaceConfigTest.java b/dubbo-config/dubbo-config-api/src/test/java/org/apache/dubbo/config/AbstractInterfaceConfigTest.java index 1c534eaadc2..f0d1a80a262 100644 --- a/dubbo-config/dubbo-config-api/src/test/java/org/apache/dubbo/config/AbstractInterfaceConfigTest.java +++ b/dubbo-config/dubbo-config-api/src/test/java/org/apache/dubbo/config/AbstractInterfaceConfigTest.java @@ -20,6 +20,7 @@ import org.apache.dubbo.common.URL; import org.apache.dubbo.common.utils.ConfigUtils; import org.apache.dubbo.config.api.Greeting; +import org.apache.dubbo.config.context.ConfigManager; import org.apache.dubbo.config.mock.GreetingLocal1; import org.apache.dubbo.config.mock.GreetingLocal2; import org.apache.dubbo.config.mock.GreetingLocal3; @@ -29,6 +30,7 @@ import org.apache.dubbo.registry.RegistryService; import org.junit.jupiter.api.AfterAll; +import org.junit.jupiter.api.AfterEach; import org.junit.jupiter.api.Assertions; import org.junit.jupiter.api.BeforeAll; import org.junit.jupiter.api.Test; @@ -61,6 +63,11 @@ public static void tearDown() { System.clearProperty(Constants.DUBBO_PROPERTIES_KEY); } + @AfterEach + public void tearMethodAfterEachUT() { + ConfigManager.getInstance().clear(); + } + @Test public void testCheckRegistry1() { System.setProperty("dubbo.registry.address", "addr1|addr2"); @@ -123,6 +130,8 @@ public void checkApplication2() { public void testLoadRegistries() { System.setProperty("dubbo.registry.address", "addr1"); InterfaceConfig interfaceConfig = new InterfaceConfig(); + // FIXME: now we need to check first, then load + interfaceConfig.checkRegistry(); List urls = interfaceConfig.loadRegistries(true); Assertions.assertEquals(1, urls.size()); URL url = urls.get(0); diff --git a/dubbo-config/dubbo-config-api/src/test/java/org/apache/dubbo/config/ConfigCenterConfigTest.java b/dubbo-config/dubbo-config-api/src/test/java/org/apache/dubbo/config/ConfigCenterConfigTest.java new file mode 100644 index 00000000000..96e55825d74 --- /dev/null +++ b/dubbo-config/dubbo-config-api/src/test/java/org/apache/dubbo/config/ConfigCenterConfigTest.java @@ -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.config; + + +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.Test; + +public class ConfigCenterConfigTest { + @Test + public void testPrefix() { + ConfigCenterConfig config = new ConfigCenterConfig(); + Assertions.assertEquals("dubbo.config-center", config.getPrefix()); + } +} diff --git a/dubbo-config/dubbo-config-api/src/test/java/org/apache/dubbo/config/ReferenceConfigTest.java b/dubbo-config/dubbo-config-api/src/test/java/org/apache/dubbo/config/ReferenceConfigTest.java index eb6b827854f..7c0c7597776 100644 --- a/dubbo-config/dubbo-config-api/src/test/java/org/apache/dubbo/config/ReferenceConfigTest.java +++ b/dubbo-config/dubbo-config-api/src/test/java/org/apache/dubbo/config/ReferenceConfigTest.java @@ -18,13 +18,26 @@ import org.apache.dubbo.common.Constants; import org.apache.dubbo.config.api.DemoService; +import org.apache.dubbo.config.context.ConfigManager; import org.apache.dubbo.config.provider.impl.DemoServiceImpl; +import org.junit.jupiter.api.AfterEach; import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; public class ReferenceConfigTest { + @BeforeEach + public void setUp() { + ConfigManager.getInstance().clear(); + } + + @AfterEach + public void tearDown() { + ConfigManager.getInstance().clear(); + } + @Test public void testInjvm() throws Exception { ApplicationConfig application = new ApplicationConfig(); diff --git a/dubbo-config/dubbo-config-api/src/test/java/org/apache/dubbo/config/ServiceConfigTest.java b/dubbo-config/dubbo-config-api/src/test/java/org/apache/dubbo/config/ServiceConfigTest.java index e7e3072e7df..1030bf35406 100644 --- a/dubbo-config/dubbo-config-api/src/test/java/org/apache/dubbo/config/ServiceConfigTest.java +++ b/dubbo-config/dubbo-config-api/src/test/java/org/apache/dubbo/config/ServiceConfigTest.java @@ -21,6 +21,7 @@ import org.apache.dubbo.common.URL; import org.apache.dubbo.config.api.DemoService; import org.apache.dubbo.config.api.Greeting; +import org.apache.dubbo.config.context.ConfigManager; import org.apache.dubbo.config.mock.MockProtocol2; import org.apache.dubbo.config.mock.MockRegistryFactory2; import org.apache.dubbo.config.mock.TestProxyFactory; @@ -31,6 +32,7 @@ import org.apache.dubbo.rpc.Protocol; import org.apache.dubbo.rpc.service.GenericService; +import org.junit.jupiter.api.AfterEach; import org.junit.jupiter.api.Assertions; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Disabled; @@ -101,6 +103,13 @@ public void setUp() throws Exception { service2.setRef(new DemoServiceImpl()); service2.setMethods(Collections.singletonList(method)); service2.setProxy("testproxyfactory"); + + ConfigManager.getInstance().clear(); + } + + @AfterEach + public void tearDown() { + ConfigManager.getInstance().clear(); } @Test diff --git a/dubbo-config/dubbo-config-api/src/test/java/org/apache/dubbo/config/cache/CacheTest.java b/dubbo-config/dubbo-config-api/src/test/java/org/apache/dubbo/config/cache/CacheTest.java index 78aba22c77e..b9b5c45d435 100644 --- a/dubbo-config/dubbo-config-api/src/test/java/org/apache/dubbo/config/cache/CacheTest.java +++ b/dubbo-config/dubbo-config-api/src/test/java/org/apache/dubbo/config/cache/CacheTest.java @@ -27,9 +27,12 @@ import org.apache.dubbo.config.ReferenceConfig; import org.apache.dubbo.config.RegistryConfig; import org.apache.dubbo.config.ServiceConfig; +import org.apache.dubbo.config.context.ConfigManager; import org.apache.dubbo.rpc.Invocation; import org.apache.dubbo.rpc.RpcInvocation; +import org.junit.jupiter.api.AfterEach; +import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; import java.util.Arrays; @@ -44,17 +47,30 @@ */ public class CacheTest { + @BeforeEach + public void setUp() { + ConfigManager.getInstance().clear(); + } + + @AfterEach + public void tearDown() { + ConfigManager.getInstance().clear(); + } + private void testCache(String type) throws Exception { + ApplicationConfig applicationConfig = new ApplicationConfig("cache-test"); + RegistryConfig registryConfig = new RegistryConfig("N/A"); + ProtocolConfig protocolConfig = new ProtocolConfig("injvm"); ServiceConfig service = new ServiceConfig(); - service.setApplication(new ApplicationConfig("cache-provider")); - service.setRegistry(new RegistryConfig("N/A")); - service.setProtocol(new ProtocolConfig("injvm")); + service.setApplication(applicationConfig); + service.setRegistry(registryConfig); + service.setProtocol(protocolConfig); service.setInterface(CacheService.class.getName()); service.setRef(new CacheServiceImpl()); service.export(); try { ReferenceConfig reference = new ReferenceConfig(); - reference.setApplication(new ApplicationConfig("cache-consumer")); + reference.setApplication(applicationConfig); reference.setInterface(CacheService.class); reference.setUrl("injvm://127.0.0.1?scope=remote&cache=true"); @@ -99,8 +115,12 @@ private void testCache(String type) throws Exception { } @Test - public void testCache() throws Exception { + public void testCacheLru() throws Exception { testCache("lru"); + } + + @Test + public void testCacheThreadlocal() throws Exception { testCache("threadlocal"); } diff --git a/dubbo-config/dubbo-config-api/src/test/java/org/apache/dubbo/config/url/ExporterSideConfigUrlTest.java b/dubbo-config/dubbo-config-api/src/test/java/org/apache/dubbo/config/url/ExporterSideConfigUrlTest.java index 38d423bbb14..16122908c85 100644 --- a/dubbo-config/dubbo-config-api/src/test/java/org/apache/dubbo/config/url/ExporterSideConfigUrlTest.java +++ b/dubbo-config/dubbo-config-api/src/test/java/org/apache/dubbo/config/url/ExporterSideConfigUrlTest.java @@ -19,6 +19,7 @@ import org.apache.dubbo.common.logger.Logger; import org.apache.dubbo.common.logger.LoggerFactory; +import org.apache.dubbo.config.context.ConfigManager; import org.junit.jupiter.api.AfterEach; import org.junit.jupiter.api.BeforeEach; @@ -43,10 +44,12 @@ public static void start() { @BeforeEach public void setUp() { initServConf(); + ConfigManager.getInstance().clear(); } @AfterEach() public void teardown() { + ConfigManager.getInstance().clear(); } @Test diff --git a/dubbo-config/dubbo-config-api/src/test/java/org/apache/dubbo/config/url/InvokerSideConfigUrlTest.java b/dubbo-config/dubbo-config-api/src/test/java/org/apache/dubbo/config/url/InvokerSideConfigUrlTest.java index 2977aa2e50d..da0f6071776 100644 --- a/dubbo-config/dubbo-config-api/src/test/java/org/apache/dubbo/config/url/InvokerSideConfigUrlTest.java +++ b/dubbo-config/dubbo-config-api/src/test/java/org/apache/dubbo/config/url/InvokerSideConfigUrlTest.java @@ -19,12 +19,12 @@ import org.apache.dubbo.common.Constants; import org.apache.dubbo.common.logger.Logger; import org.apache.dubbo.common.logger.LoggerFactory; -import org.apache.dubbo.config.ApplicationConfig; import org.apache.dubbo.config.ConsumerConfig; import org.apache.dubbo.config.MethodConfig; import org.apache.dubbo.config.ReferenceConfig; import org.apache.dubbo.config.RegistryConfig; import org.apache.dubbo.config.api.DemoService; +import org.apache.dubbo.config.context.ConfigManager; import org.apache.dubbo.config.mock.MockRegistry; import org.junit.jupiter.api.AfterEach; @@ -42,8 +42,6 @@ public class InvokerSideConfigUrlTest extends UrlTestBase { // ====================================================== // invoker related data preparing // ====================================================== - private ApplicationConfig appConfForConsumer; - private ApplicationConfig appConfForReference; private RegistryConfig regConfForConsumer; private RegistryConfig regConfForReference; private MethodConfig methodConfForReference; @@ -145,11 +143,13 @@ public static void start() { public void setUp() { initServConf(); initRefConf(); + ConfigManager.getInstance().clear(); } @AfterEach() public void teardown() { //RegistryServer.reloadCache(); + ConfigManager.getInstance().clear(); } @@ -173,9 +173,6 @@ public void regConfForConsumerUrlTest() { // private helper // ====================================================== private void initRefConf() { - - appConfForConsumer = new ApplicationConfig(); - appConfForReference = new ApplicationConfig(); regConfForConsumer = new RegistryConfig(); regConfForReference = new RegistryConfig(); methodConfForReference = new MethodConfig(); @@ -186,11 +183,10 @@ private void initRefConf() { methodConfForReference.setName("sayName"); regConfForReference.setAddress("127.0.0.1:9090"); regConfForReference.setProtocol("mockregistry"); - appConfForReference.setName("ConfigTests"); refConf.setInterface("org.apache.dubbo.config.api.DemoService"); - refConf.setApplication(appConfForReference); - consumerConf.setApplication(appConfForConsumer); + refConf.setApplication(application); +// consumerConf.setApplication(appConfForConsumer); refConf.setRegistry(regConfForReference); consumerConf.setRegistry(regConfForConsumer); diff --git a/dubbo-config/dubbo-config-api/src/test/java/org/apache/dubbo/config/url/UrlTestBase.java b/dubbo-config/dubbo-config-api/src/test/java/org/apache/dubbo/config/url/UrlTestBase.java index affbb4f3aad..f5a1a73ed22 100644 --- a/dubbo-config/dubbo-config-api/src/test/java/org/apache/dubbo/config/url/UrlTestBase.java +++ b/dubbo-config/dubbo-config-api/src/test/java/org/apache/dubbo/config/url/UrlTestBase.java @@ -50,8 +50,7 @@ public class UrlTestBase { private static final int TESTVALUE5 = 8; private static final int TESTVALUE6 = 9; private static final int TESTVALUE7 = 10; - protected ApplicationConfig appConfForProvider; - protected ApplicationConfig appConfForService; + protected ApplicationConfig application = new ApplicationConfig(); protected RegistryConfig regConfForProvider; protected RegistryConfig regConfForService; protected ProviderConfig provConf; @@ -141,9 +140,6 @@ protected void fillConfig(T conf, Object[] row, int column) { @SuppressWarnings("deprecation") protected void initServConf() { - - appConfForProvider = new ApplicationConfig(); - appConfForService = new ApplicationConfig(); regConfForProvider = new RegistryConfig(); regConfForService = new RegistryConfig(); provConf = new ProviderConfig(); @@ -152,8 +148,8 @@ protected void initServConf() { methodConfForService = new MethodConfig(); servConf = new ServiceConfig(); - provConf.setApplication(appConfForProvider); - servConf.setApplication(appConfForService); +// provConf.setApplication(appConfForProvider); + servConf.setApplication(application); provConf.setRegistry(regConfForProvider); servConf.setRegistry(regConfForService); @@ -170,7 +166,7 @@ protected void initServConf() { methodConfForService.setName("sayName"); regConfForService.setAddress("127.0.0.1:9090"); regConfForService.setProtocol("mockregistry"); - appConfForService.setName("ConfigTests"); + application.setName("ConfigTests"); } protected String getProviderParamString() { diff --git a/dubbo-config/dubbo-config-spring/pom.xml b/dubbo-config/dubbo-config-spring/pom.xml index 55ee8cd2278..08cc297f02f 100644 --- a/dubbo-config/dubbo-config-spring/pom.xml +++ b/dubbo-config/dubbo-config-spring/pom.xml @@ -19,7 +19,7 @@ org.apache.dubbo dubbo-config - 2.7.0-SNAPSHOT + 2.7.1-SNAPSHOT dubbo-config-spring jar @@ -118,14 +118,14 @@ test
- org.apache.tomcat.embed - tomcat-embed-core + junit + junit + 4.12 test - org.springframework - spring-test - 5.1.3.RELEASE + org.apache.tomcat.embed + tomcat-embed-core test
diff --git a/dubbo-config/dubbo-config-spring/src/main/java/org/apache/dubbo/config/spring/AnnotationBean.java b/dubbo-config/dubbo-config-spring/src/main/java/org/apache/dubbo/config/spring/AnnotationBean.java deleted file mode 100644 index 85930677252..00000000000 --- a/dubbo-config/dubbo-config-spring/src/main/java/org/apache/dubbo/config/spring/AnnotationBean.java +++ /dev/null @@ -1,323 +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.config.spring; - -import org.apache.dubbo.common.Constants; -import org.apache.dubbo.common.logger.Logger; -import org.apache.dubbo.common.logger.LoggerFactory; -import org.apache.dubbo.common.utils.ArrayUtils; -import org.apache.dubbo.common.utils.ConcurrentHashSet; -import org.apache.dubbo.common.utils.ReflectUtils; -import org.apache.dubbo.common.utils.StringUtils; -import org.apache.dubbo.config.AbstractConfig; -import org.apache.dubbo.config.ApplicationConfig; -import org.apache.dubbo.config.ConsumerConfig; -import org.apache.dubbo.config.ModuleConfig; -import org.apache.dubbo.config.MonitorConfig; -import org.apache.dubbo.config.ProtocolConfig; -import org.apache.dubbo.config.ProviderConfig; -import org.apache.dubbo.config.RegistryConfig; -import org.apache.dubbo.config.ServiceConfig; -import org.apache.dubbo.config.annotation.Reference; -import org.apache.dubbo.config.annotation.Service; - -import org.springframework.beans.BeansException; -import org.springframework.beans.factory.DisposableBean; -import org.springframework.beans.factory.config.BeanFactoryPostProcessor; -import org.springframework.beans.factory.config.BeanPostProcessor; -import org.springframework.beans.factory.config.ConfigurableListableBeanFactory; -import org.springframework.beans.factory.support.BeanDefinitionRegistry; -import org.springframework.context.ApplicationContext; -import org.springframework.context.ApplicationContextAware; - -import java.lang.reflect.Field; -import java.lang.reflect.Method; -import java.lang.reflect.Modifier; -import java.util.ArrayList; -import java.util.List; -import java.util.Set; -import java.util.concurrent.ConcurrentHashMap; -import java.util.concurrent.ConcurrentMap; - -/** - * AnnotationBean - * - * @export - */ -@Deprecated -public class AnnotationBean extends AbstractConfig implements DisposableBean, BeanFactoryPostProcessor, BeanPostProcessor, ApplicationContextAware { - - private static final long serialVersionUID = -7582802454287589552L; - - private static final Logger logger = LoggerFactory.getLogger(Logger.class); - private final Set> serviceConfigs = new ConcurrentHashSet>(); - private final ConcurrentMap> referenceConfigs = new ConcurrentHashMap>(); - private String annotationPackage; - private String[] annotationPackages; - private ApplicationContext applicationContext; - - public String getPackage() { - return annotationPackage; - } - - public void setPackage(String annotationPackage) { - this.annotationPackage = annotationPackage; - this.annotationPackages = (StringUtils.isEmpty(annotationPackage)) ? null - : Constants.COMMA_SPLIT_PATTERN.split(annotationPackage); - } - - @Override - public void setApplicationContext(ApplicationContext applicationContext) throws BeansException { - this.applicationContext = applicationContext; - } - - @Override - public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) - throws BeansException { - if (StringUtils.isEmpty(annotationPackage)) { - return; - } - if (beanFactory instanceof BeanDefinitionRegistry) { - try { - // init scanner - Class scannerClass = ReflectUtils.forName("org.springframework.context.annotation.ClassPathBeanDefinitionScanner"); - Object scanner = scannerClass.getConstructor(new Class[]{BeanDefinitionRegistry.class, boolean.class}).newInstance((BeanDefinitionRegistry) beanFactory, true); - // add filter - Class filterClass = ReflectUtils.forName("org.springframework.core.type.filter.AnnotationTypeFilter"); - Object filter = filterClass.getConstructor(Class.class).newInstance(Service.class); - Method addIncludeFilter = scannerClass.getMethod("addIncludeFilter", ReflectUtils.forName("org.springframework.core.type.filter.TypeFilter")); - addIncludeFilter.invoke(scanner, filter); - // scan packages - String[] packages = Constants.COMMA_SPLIT_PATTERN.split(annotationPackage); - Method scan = scannerClass.getMethod("scan", String[].class); - scan.invoke(scanner, new Object[]{packages}); - } catch (Throwable e) { - // spring 2.0 - } - } - } - - @Override - public void destroy() { - // no need to destroy here - // see org.apache.dubbo.config.spring.extension.SpringExtensionFactory.ShutdownHookListener - /* - for (ServiceConfig serviceConfig : serviceConfigs) { - try { - serviceConfig.unexport(); - } catch (Throwable e) { - logger.error(e.getMessage(), e); - } - } - - for (ReferenceConfig referenceConfig : referenceConfigs.values()) { - try { - referenceConfig.destroy(); - } catch (Throwable e) { - logger.error(e.getMessage(), e); - } - } - */ - } - - @Override - public Object postProcessAfterInitialization(Object bean, String beanName) - throws BeansException { - if (!isMatchPackage(bean)) { - return bean; - } - Service service = bean.getClass().getAnnotation(Service.class); - if (service != null) { - ServiceBean serviceConfig = new ServiceBean(service); - serviceConfig.setRef(bean); - if (void.class.equals(service.interfaceClass()) - && "".equals(service.interfaceName())) { - if (bean.getClass().getInterfaces().length > 0) { - serviceConfig.setInterface(bean.getClass().getInterfaces()[0]); - } else { - throw new IllegalStateException("Failed to export remote service class " + bean.getClass().getName() + ", cause: The @Service undefined interfaceClass or interfaceName, and the service class unimplemented any interfaces."); - } - } - if (applicationContext != null) { - serviceConfig.setApplicationContext(applicationContext); - if (service.registry().length > 0) { - List registryConfigs = new ArrayList(); - for (String registryId : service.registry()) { - if (registryId != null && registryId.length() > 0) { - registryConfigs.add(applicationContext.getBean(registryId, RegistryConfig.class)); - } - } - serviceConfig.setRegistries(registryConfigs); - } - if (service.provider().length() > 0) { - serviceConfig.setProvider(applicationContext.getBean(service.provider(), ProviderConfig.class)); - } - if (service.monitor().length() > 0) { - serviceConfig.setMonitor(applicationContext.getBean(service.monitor(), MonitorConfig.class)); - } - if (service.application().length() > 0) { - serviceConfig.setApplication(applicationContext.getBean(service.application(), ApplicationConfig.class)); - } - if (service.module().length() > 0) { - serviceConfig.setModule(applicationContext.getBean(service.module(), ModuleConfig.class)); - } - if (service.protocol().length > 0) { - List protocolConfigs = new ArrayList(); - for (String protocolId : service.protocol()) { - if (protocolId != null && protocolId.length() > 0) { - protocolConfigs.add(applicationContext.getBean(protocolId, ProtocolConfig.class)); - } - } - serviceConfig.setProtocols(protocolConfigs); - } - if (service.tag().length() > 0) { - serviceConfig.setTag(service.tag()); - } - try { - serviceConfig.afterPropertiesSet(); - } catch (RuntimeException e) { - throw e; - } catch (Exception e) { - throw new IllegalStateException(e.getMessage(), e); - } - } - serviceConfigs.add(serviceConfig); - serviceConfig.export(); - } - return bean; - } - - @Override - public Object postProcessBeforeInitialization(Object bean, String beanName) - throws BeansException { - if (!isMatchPackage(bean)) { - return bean; - } - Method[] methods = bean.getClass().getMethods(); - for (Method method : methods) { - String name = method.getName(); - if (name.length() > 3 && name.startsWith("set") - && method.getParameterTypes().length == 1 - && Modifier.isPublic(method.getModifiers()) - && !Modifier.isStatic(method.getModifiers())) { - try { - Reference reference = method.getAnnotation(Reference.class); - if (reference != null) { - Object value = refer(reference, method.getParameterTypes()[0]); - if (value != null) { - method.invoke(bean, value); - } - } - } catch (Throwable e) { - logger.error("Failed to init remote service reference at method " + name + " in class " + bean.getClass().getName() + ", cause: " + e.getMessage(), e); - } - } - } - Field[] fields = bean.getClass().getDeclaredFields(); - for (Field field : fields) { - try { - if (!field.isAccessible()) { - field.setAccessible(true); - } - Reference reference = field.getAnnotation(Reference.class); - if (reference != null) { - Object value = refer(reference, field.getType()); - if (value != null) { - field.set(bean, value); - } - } - } catch (Throwable e) { - logger.error("Failed to init remote service reference at field " + field.getName() + " in class " + bean.getClass().getName() + ", cause: " + e.getMessage(), e); - } - } - return bean; - } - - private Object refer(Reference reference, Class referenceClass) { //method.getParameterTypes()[0] - String interfaceName; - if (!"".equals(reference.interfaceName())) { - interfaceName = reference.interfaceName(); - } else if (!void.class.equals(reference.interfaceClass())) { - interfaceName = reference.interfaceClass().getName(); - } else if (referenceClass.isInterface()) { - interfaceName = referenceClass.getName(); - } else { - throw new IllegalStateException("The @Reference undefined interfaceClass or interfaceName, and the property type " + referenceClass.getName() + " is not a interface."); - } - String key = reference.group() + "/" + interfaceName + ":" + reference.version(); - ReferenceBean referenceConfig = referenceConfigs.get(key); - if (referenceConfig == null) { - referenceConfig = new ReferenceBean(reference); - if (void.class.equals(reference.interfaceClass()) - && "".equals(reference.interfaceName()) - && referenceClass.isInterface()) { - referenceConfig.setInterface(referenceClass); - } - if (applicationContext != null) { - referenceConfig.setApplicationContext(applicationContext); - if (reference.registry().length > 0) { - List registryConfigs = new ArrayList(); - for (String registryId : reference.registry()) { - if (registryId != null && registryId.length() > 0) { - registryConfigs.add(applicationContext.getBean(registryId, RegistryConfig.class)); - } - } - referenceConfig.setRegistries(registryConfigs); - } - if (reference.consumer().length() > 0) { - referenceConfig.setConsumer(applicationContext.getBean(reference.consumer(), ConsumerConfig.class)); - } - if (reference.monitor().length() > 0) { - referenceConfig.setMonitor(applicationContext.getBean(reference.monitor(), MonitorConfig.class)); - } - if (reference.application().length() > 0) { - referenceConfig.setApplication(applicationContext.getBean(reference.application(), ApplicationConfig.class)); - } - if (reference.module().length() > 0) { - referenceConfig.setModule(applicationContext.getBean(reference.module(), ModuleConfig.class)); - } - if (reference.consumer().length() > 0) { - referenceConfig.setConsumer(applicationContext.getBean(reference.consumer(), ConsumerConfig.class)); - } - try { - referenceConfig.afterPropertiesSet(); - } catch (RuntimeException e) { - throw e; - } catch (Exception e) { - throw new IllegalStateException(e.getMessage(), e); - } - } - referenceConfigs.putIfAbsent(key, referenceConfig); - referenceConfig = referenceConfigs.get(key); - } - return referenceConfig.get(); - } - - private boolean isMatchPackage(Object bean) { - if (ArrayUtils.isEmpty(annotationPackages)) { - return true; - } - String beanClassName = bean.getClass().getName(); - for (String pkg : annotationPackages) { - if (beanClassName.startsWith(pkg)) { - return true; - } - } - return false; - } - -} diff --git a/dubbo-config/dubbo-config-spring/src/main/java/org/apache/dubbo/config/spring/ConfigCenterBean.java b/dubbo-config/dubbo-config-spring/src/main/java/org/apache/dubbo/config/spring/ConfigCenterBean.java index e497d4ba155..1ea2485c0d2 100644 --- a/dubbo-config/dubbo-config-spring/src/main/java/org/apache/dubbo/config/spring/ConfigCenterBean.java +++ b/dubbo-config/dubbo-config-spring/src/main/java/org/apache/dubbo/config/spring/ConfigCenterBean.java @@ -16,13 +16,11 @@ */ package org.apache.dubbo.config.spring; -import org.apache.dubbo.common.utils.CollectionUtils; +import org.apache.dubbo.common.config.ConfigurationUtils; import org.apache.dubbo.common.utils.StringUtils; import org.apache.dubbo.config.ApplicationConfig; import org.apache.dubbo.config.ConfigCenterConfig; -import org.apache.dubbo.config.RegistryConfig; import org.apache.dubbo.config.spring.extension.SpringExtensionFactory; -import org.apache.dubbo.config.support.Parameter; import org.springframework.beans.factory.BeanFactoryUtils; import org.springframework.beans.factory.DisposableBean; @@ -34,9 +32,7 @@ import org.springframework.core.env.Environment; import org.springframework.core.env.PropertySource; -import java.util.ArrayList; import java.util.HashMap; -import java.util.List; import java.util.Map; /** @@ -49,7 +45,8 @@ public class ConfigCenterBean extends ConfigCenterConfig implements Initializing private transient ApplicationContext applicationContext; - private Boolean fromSpring = false; + private Boolean includeSpringEnv = false; + private ApplicationConfig application; @Override public void setApplicationContext(ApplicationContext applicationContext) { @@ -76,28 +73,6 @@ public void afterPropertiesSet() throws Exception { } } } - - if ((getRegistry() == null)) { - List registryConfigs = new ArrayList<>(); - if (getApplication() != null && CollectionUtils.isNotEmpty(getApplication().getRegistries())) { - registryConfigs = getApplication().getRegistries(); - } else { - Map registryConfigMap = applicationContext == null ? null : BeanFactoryUtils.beansOfTypeIncludingAncestors(applicationContext, RegistryConfig.class, false, false); - if (registryConfigMap != null && registryConfigMap.size() > 0) { - registryConfigs.addAll(registryConfigMap.values()); - } - } - for (RegistryConfig config : registryConfigs) { - if (config.isDefault() == null || config.isDefault() && config.isZookeeperProtocol()) { - setRegistry(config); - break; - } - } - } - - if (!fromSpring) { - this.init(); - } } @Override @@ -107,12 +82,11 @@ public void destroy() throws Exception { @Override public void setEnvironment(Environment environment) { - if (fromSpring) { + if (includeSpringEnv) { Map externalProperties = getConfigurations(getConfigFile(), environment); Map appExternalProperties = getConfigurations(StringUtils.isNotEmpty(getAppConfigFile()) ? getAppConfigFile() : (StringUtils.isEmpty(getAppName()) ? ("application." + getConfigFile()) : (getAppName() + "." + getConfigFile())), environment); org.apache.dubbo.common.config.Environment.getInstance().setExternalConfigMap(externalProperties); org.apache.dubbo.common.config.Environment.getInstance().setAppExternalConfigMap(appExternalProperties); - this.init(); } } @@ -123,7 +97,7 @@ private Map getConfigurations(String key, Environment environmen if (rawProperties instanceof Map) { externalProperties.putAll((Map) rawProperties); } else if (rawProperties instanceof String) { - externalProperties.putAll(parseProperties((String) rawProperties)); + externalProperties.putAll(ConfigurationUtils.parseProperties((String) rawProperties)); } if (environment instanceof ConfigurableEnvironment && externalProperties.isEmpty()) { @@ -144,12 +118,23 @@ private Map getConfigurations(String key, Environment environmen return externalProperties; } - @Parameter(excluded = true) - public Boolean getFromSpring() { - return fromSpring; + public ApplicationContext getApplicationContext() { + return applicationContext; + } + + public Boolean getIncludeSpringEnv() { + return includeSpringEnv; + } + + public void setIncludeSpringEnv(Boolean includeSpringEnv) { + this.includeSpringEnv = includeSpringEnv; + } + + public ApplicationConfig getApplication() { + return application; } - public void setFromSpring(Boolean fromSpring) { - this.fromSpring = fromSpring; + public void setApplication(ApplicationConfig application) { + this.application = application; } } diff --git a/dubbo-config/dubbo-config-spring/src/main/java/org/apache/dubbo/config/spring/ReferenceBean.java b/dubbo-config/dubbo-config-spring/src/main/java/org/apache/dubbo/config/spring/ReferenceBean.java index 3a3e419beba..5e8cab22eae 100644 --- a/dubbo-config/dubbo-config-spring/src/main/java/org/apache/dubbo/config/spring/ReferenceBean.java +++ b/dubbo-config/dubbo-config-spring/src/main/java/org/apache/dubbo/config/spring/ReferenceBean.java @@ -20,13 +20,13 @@ import org.apache.dubbo.common.utils.CollectionUtils; import org.apache.dubbo.common.utils.StringUtils; import org.apache.dubbo.config.ApplicationConfig; +import org.apache.dubbo.config.ConfigCenterConfig; import org.apache.dubbo.config.ConsumerConfig; import org.apache.dubbo.config.MetadataReportConfig; import org.apache.dubbo.config.ModuleConfig; import org.apache.dubbo.config.MonitorConfig; import org.apache.dubbo.config.ReferenceConfig; import org.apache.dubbo.config.RegistryConfig; -import org.apache.dubbo.config.RegistryDataConfig; import org.apache.dubbo.config.annotation.Reference; import org.apache.dubbo.config.spring.extension.SpringExtensionFactory; import org.apache.dubbo.config.support.Parameter; @@ -112,12 +112,10 @@ public void afterPropertiesSet() throws Exception { if (applicationConfigMap != null && applicationConfigMap.size() > 0) { ApplicationConfig applicationConfig = null; for (ApplicationConfig config : applicationConfigMap.values()) { - if (config.isDefault() == null || config.isDefault()) { - if (applicationConfig != null) { - throw new IllegalStateException("Duplicate application configs: " + applicationConfig + " and " + config); - } - applicationConfig = config; + if (applicationConfig != null) { + throw new IllegalStateException("Duplicate application configs: " + applicationConfig + " and " + config); } + applicationConfig = config; } if (applicationConfig != null) { setApplication(applicationConfig); @@ -189,13 +187,12 @@ public void afterPropertiesSet() throws Exception { } } - - if (getRegistryDataConfig() == null) { - Map registryDataConfigMap = applicationContext == null ? null : BeanFactoryUtils.beansOfTypeIncludingAncestors(applicationContext, RegistryDataConfig.class, false, false); - if (registryDataConfigMap != null && registryDataConfigMap.size() == 1) { - super.setRegistryDataConfig(registryDataConfigMap.values().iterator().next()); - } else if (registryDataConfigMap != null && registryDataConfigMap.size() > 1) { - throw new IllegalStateException("Multiple RegistryData configs: " + registryDataConfigMap); + if (getConfigCenter() == null) { + Map configenterMap = applicationContext == null ? null : BeanFactoryUtils.beansOfTypeIncludingAncestors(applicationContext, ConfigCenterConfig.class, false, false); + if (configenterMap != null && configenterMap.size() == 1) { + super.setConfigCenter(configenterMap.values().iterator().next()); + } else if (configenterMap != null && configenterMap.size() > 1) { + throw new IllegalStateException("Multiple ConfigCenter found:" + configenterMap); } } diff --git a/dubbo-config/dubbo-config-spring/src/main/java/org/apache/dubbo/config/spring/ServiceBean.java b/dubbo-config/dubbo-config-spring/src/main/java/org/apache/dubbo/config/spring/ServiceBean.java index c72abf94461..7c216a64a97 100644 --- a/dubbo-config/dubbo-config-spring/src/main/java/org/apache/dubbo/config/spring/ServiceBean.java +++ b/dubbo-config/dubbo-config-spring/src/main/java/org/apache/dubbo/config/spring/ServiceBean.java @@ -1,312 +1,355 @@ -/* - * 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.spring; - -import org.apache.dubbo.common.Constants; -import org.apache.dubbo.common.utils.CollectionUtils; -import org.apache.dubbo.common.utils.StringUtils; -import org.apache.dubbo.config.ApplicationConfig; -import org.apache.dubbo.config.MetadataReportConfig; -import org.apache.dubbo.config.ModuleConfig; -import org.apache.dubbo.config.MonitorConfig; -import org.apache.dubbo.config.ProtocolConfig; -import org.apache.dubbo.config.ProviderConfig; -import org.apache.dubbo.config.RegistryConfig; -import org.apache.dubbo.config.RegistryDataConfig; -import org.apache.dubbo.config.ServiceConfig; -import org.apache.dubbo.config.annotation.Service; -import org.apache.dubbo.config.spring.extension.SpringExtensionFactory; - -import org.springframework.aop.support.AopUtils; -import org.springframework.beans.factory.BeanFactoryUtils; -import org.springframework.beans.factory.BeanNameAware; -import org.springframework.beans.factory.DisposableBean; -import org.springframework.beans.factory.InitializingBean; -import org.springframework.context.ApplicationContext; -import org.springframework.context.ApplicationContextAware; -import org.springframework.context.ApplicationListener; -import org.springframework.context.event.ContextRefreshedEvent; - -import java.util.ArrayList; -import java.util.Arrays; -import java.util.List; -import java.util.Map; - -import static org.apache.dubbo.config.spring.util.BeanFactoryUtils.addApplicationListener; - -/** - * ServiceFactoryBean - * - * @export - */ -public class ServiceBean extends ServiceConfig implements InitializingBean, DisposableBean, ApplicationContextAware, ApplicationListener, BeanNameAware { - - private static final long serialVersionUID = 213195494150089726L; - - private final transient Service service; - - private transient ApplicationContext applicationContext; - - private transient String beanName; - - private transient boolean supportedApplicationListener; - - public ServiceBean() { - super(); - this.service = null; - } - - public ServiceBean(Service service) { - super(service); - this.service = service; - } - - @Override - public void setApplicationContext(ApplicationContext applicationContext) { - this.applicationContext = applicationContext; - SpringExtensionFactory.addApplicationContext(applicationContext); - supportedApplicationListener = addApplicationListener(applicationContext, this); - } - - @Override - public void setBeanName(String name) { - this.beanName = name; - } - - /** - * Gets associated {@link Service} - * - * @return associated {@link Service} - */ - public Service getService() { - return service; - } - - @Override - public void onApplicationEvent(ContextRefreshedEvent event) { - if (!isExported() && !isUnexported()) { - if (logger.isInfoEnabled()) { - logger.info("The service ready on spring started. service: " + getInterface()); - } - export(); - } - } - - @Override - @SuppressWarnings({"unchecked", "deprecation"}) - public void afterPropertiesSet() throws Exception { - if (getProvider() == null) { - Map providerConfigMap = applicationContext == null ? null : BeanFactoryUtils.beansOfTypeIncludingAncestors(applicationContext, ProviderConfig.class, false, false); - if (providerConfigMap != null && providerConfigMap.size() > 0) { - Map protocolConfigMap = applicationContext == null ? null : BeanFactoryUtils.beansOfTypeIncludingAncestors(applicationContext, ProtocolConfig.class, false, false); - if (CollectionUtils.isEmptyMap(protocolConfigMap) - && providerConfigMap.size() > 1) { // backward compatibility - List providerConfigs = new ArrayList(); - for (ProviderConfig config : providerConfigMap.values()) { - if (config.isDefault() != null && config.isDefault()) { - providerConfigs.add(config); - } - } - if (!providerConfigs.isEmpty()) { - setProviders(providerConfigs); - } - } else { - ProviderConfig providerConfig = null; - for (ProviderConfig config : providerConfigMap.values()) { - if (config.isDefault() == null || config.isDefault()) { - if (providerConfig != null) { - throw new IllegalStateException("Duplicate provider configs: " + providerConfig + " and " + config); - } - providerConfig = config; - } - } - if (providerConfig != null) { - setProvider(providerConfig); - } - } - } - } - if (getApplication() == null - && (getProvider() == null || getProvider().getApplication() == null)) { - Map applicationConfigMap = applicationContext == null ? null : BeanFactoryUtils.beansOfTypeIncludingAncestors(applicationContext, ApplicationConfig.class, false, false); - if (applicationConfigMap != null && applicationConfigMap.size() > 0) { - ApplicationConfig applicationConfig = null; - for (ApplicationConfig config : applicationConfigMap.values()) { - if (config.isDefault() == null || config.isDefault()) { - if (applicationConfig != null) { - throw new IllegalStateException("Duplicate application configs: " + applicationConfig + " and " + config); - } - applicationConfig = config; - } - } - if (applicationConfig != null) { - setApplication(applicationConfig); - } - } - } - if (getModule() == null - && (getProvider() == null || getProvider().getModule() == null)) { - Map moduleConfigMap = applicationContext == null ? null : BeanFactoryUtils.beansOfTypeIncludingAncestors(applicationContext, ModuleConfig.class, false, false); - if (moduleConfigMap != null && moduleConfigMap.size() > 0) { - ModuleConfig moduleConfig = null; - for (ModuleConfig config : moduleConfigMap.values()) { - if (config.isDefault() == null || config.isDefault()) { - if (moduleConfig != null) { - throw new IllegalStateException("Duplicate module configs: " + moduleConfig + " and " + config); - } - moduleConfig = config; - } - } - if (moduleConfig != null) { - setModule(moduleConfig); - } - } - } - - if (StringUtils.isEmpty(getRegistryIds())) { - if (getApplication() != null && StringUtils.isNotEmpty(getApplication().getRegistryIds())) { - setRegistryIds(getApplication().getRegistryIds()); - } - if (getProvider() != null && StringUtils.isNotEmpty(getProvider().getRegistryIds())) { - setRegistryIds(getProvider().getRegistryIds()); - } - } - - if ((CollectionUtils.isEmpty(getRegistries())) - && (getProvider() == null || CollectionUtils.isEmpty(getProvider().getRegistries())) - && (getApplication() == null || CollectionUtils.isEmpty(getApplication().getRegistries()))) { - Map registryConfigMap = applicationContext == null ? null : BeanFactoryUtils.beansOfTypeIncludingAncestors(applicationContext, RegistryConfig.class, false, false); - if (CollectionUtils.isNotEmptyMap(registryConfigMap)) { - List registryConfigs = new ArrayList<>(); - if (StringUtils.isNotEmpty(registryIds)) { - Arrays.stream(Constants.COMMA_SPLIT_PATTERN.split(registryIds)).forEach(id -> { - if (registryConfigMap.containsKey(id)) { - registryConfigs.add(registryConfigMap.get(id)); - } - }); - } - - if (registryConfigs.isEmpty()) { - for (RegistryConfig config : registryConfigMap.values()) { - if (StringUtils.isEmpty(registryIds)) { - registryConfigs.add(config); - } - } - } - if (!registryConfigs.isEmpty()) { - super.setRegistries(registryConfigs); - } - } - } - if (getMetadataReportConfig() == null) { - Map metadataReportConfigMap = applicationContext == null ? null : BeanFactoryUtils.beansOfTypeIncludingAncestors(applicationContext, MetadataReportConfig.class, false, false); - if (metadataReportConfigMap != null && metadataReportConfigMap.size() == 1) { - super.setMetadataReportConfig(metadataReportConfigMap.values().iterator().next()); - } else if (metadataReportConfigMap != null && metadataReportConfigMap.size() > 1) { - throw new IllegalStateException("Multiple MetadataReport configs: " + metadataReportConfigMap); - } - } - - if (getRegistryDataConfig() == null) { - Map registryDataConfigMap = applicationContext == null ? null : BeanFactoryUtils.beansOfTypeIncludingAncestors(applicationContext, RegistryDataConfig.class, false, false); - if (registryDataConfigMap != null && registryDataConfigMap.size() == 1) { - super.setRegistryDataConfig(registryDataConfigMap.values().iterator().next()); - } else if (registryDataConfigMap != null && registryDataConfigMap.size() > 1) { - throw new IllegalStateException("Multiple RegistryData configs: " + registryDataConfigMap); - } - } - - if (getMonitor() == null - && (getProvider() == null || getProvider().getMonitor() == null) - && (getApplication() == null || getApplication().getMonitor() == null)) { - Map monitorConfigMap = applicationContext == null ? null : BeanFactoryUtils.beansOfTypeIncludingAncestors(applicationContext, MonitorConfig.class, false, false); - if (monitorConfigMap != null && monitorConfigMap.size() > 0) { - MonitorConfig monitorConfig = null; - for (MonitorConfig config : monitorConfigMap.values()) { - if (config.isDefault() == null || config.isDefault()) { - if (monitorConfig != null) { - throw new IllegalStateException("Duplicate monitor configs: " + monitorConfig + " and " + config); - } - monitorConfig = config; - } - } - if (monitorConfig != null) { - setMonitor(monitorConfig); - } - } - } - - if (StringUtils.isEmpty(getProtocolIds())) { - if (getProvider() != null && StringUtils.isNotEmpty(getProvider().getProtocolIds())) { - setProtocolIds(getProvider().getProtocolIds()); - } - } - - if (CollectionUtils.isEmpty(getProtocols()) - && (getProvider() == null || CollectionUtils.isEmpty(getProvider().getProtocols()))) { - Map protocolConfigMap = applicationContext == null ? null : BeanFactoryUtils.beansOfTypeIncludingAncestors(applicationContext, ProtocolConfig.class, false, false); - if (protocolConfigMap != null && protocolConfigMap.size() > 0) { - List protocolConfigs = new ArrayList(); - if (StringUtils.isNotEmpty(getProtocolIds())) { - Arrays.stream(Constants.COMMA_SPLIT_PATTERN.split(getProtocolIds())) - .forEach(id -> { - if (protocolConfigMap.containsKey(id)) { - protocolConfigs.add(protocolConfigMap.get(id)); - } - }); - } - - if (protocolConfigs.isEmpty()) { - for (ProtocolConfig config : protocolConfigMap.values()) { - if (StringUtils.isEmpty(protocolIds)) { - protocolConfigs.add(config); - } - } - } - - if (!protocolConfigs.isEmpty()) { - super.setProtocols(protocolConfigs); - } - } - } - if (StringUtils.isEmpty(getPath())) { - if (StringUtils.isNotEmpty(beanName) - && StringUtils.isNotEmpty(getInterface()) - && beanName.startsWith(getInterface())) { - setPath(beanName); - } - } - if (!supportedApplicationListener) { - export(); - } - } - - @Override - public void destroy() throws Exception { - // no need to call unexport() here, see - // org.apache.dubbo.config.spring.extension.SpringExtensionFactory.ShutdownHookListener - } - - // merged from dubbox - @Override - protected Class getServiceClass(T ref) { - if (AopUtils.isAopProxy(ref)) { - return AopUtils.getTargetClass(ref); - } - return super.getServiceClass(ref); - } -} +/* + * 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.spring; + +import org.apache.dubbo.common.Constants; +import org.apache.dubbo.common.utils.CollectionUtils; +import org.apache.dubbo.common.utils.StringUtils; +import org.apache.dubbo.config.ApplicationConfig; +import org.apache.dubbo.config.ConfigCenterConfig; +import org.apache.dubbo.config.MetadataReportConfig; +import org.apache.dubbo.config.ModuleConfig; +import org.apache.dubbo.config.MonitorConfig; +import org.apache.dubbo.config.ProtocolConfig; +import org.apache.dubbo.config.ProviderConfig; +import org.apache.dubbo.config.RegistryConfig; +import org.apache.dubbo.config.ServiceConfig; +import org.apache.dubbo.config.annotation.Service; +import org.apache.dubbo.config.spring.context.event.ServiceBeanExportedEvent; +import org.apache.dubbo.config.spring.extension.SpringExtensionFactory; + +import org.springframework.aop.support.AopUtils; +import org.springframework.beans.factory.BeanFactoryUtils; +import org.springframework.beans.factory.BeanNameAware; +import org.springframework.beans.factory.DisposableBean; +import org.springframework.beans.factory.InitializingBean; +import org.springframework.context.ApplicationContext; +import org.springframework.context.ApplicationContextAware; +import org.springframework.context.ApplicationEventPublisher; +import org.springframework.context.ApplicationEventPublisherAware; +import org.springframework.context.ApplicationListener; +import org.springframework.context.event.ContextRefreshedEvent; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; +import java.util.Map; + +import static org.apache.dubbo.config.spring.util.BeanFactoryUtils.addApplicationListener; + +/** + * ServiceFactoryBean + * + * @export + */ +public class ServiceBean extends ServiceConfig implements InitializingBean, DisposableBean, + ApplicationContextAware, ApplicationListener, BeanNameAware, + ApplicationEventPublisherAware { + + + private static final long serialVersionUID = 213195494150089726L; + + private final transient Service service; + + private transient ApplicationContext applicationContext; + + private transient String beanName; + + private transient boolean supportedApplicationListener; + + private ApplicationEventPublisher applicationEventPublisher; + + public ServiceBean() { + super(); + this.service = null; + } + + public ServiceBean(Service service) { + super(service); + this.service = service; + } + + @Override + public void setApplicationContext(ApplicationContext applicationContext) { + this.applicationContext = applicationContext; + SpringExtensionFactory.addApplicationContext(applicationContext); + supportedApplicationListener = addApplicationListener(applicationContext, this); + } + + @Override + public void setBeanName(String name) { + this.beanName = name; + } + + /** + * Gets associated {@link Service} + * + * @return associated {@link Service} + */ + public Service getService() { + return service; + } + + @Override + public void onApplicationEvent(ContextRefreshedEvent event) { + if (!isExported() && !isUnexported()) { + if (logger.isInfoEnabled()) { + logger.info("The service ready on spring started. service: " + getInterface()); + } + export(); + } + } + + @Override + @SuppressWarnings({"unchecked", "deprecation"}) + public void afterPropertiesSet() throws Exception { + if (getProvider() == null) { + Map providerConfigMap = applicationContext == null ? null : BeanFactoryUtils.beansOfTypeIncludingAncestors(applicationContext, ProviderConfig.class, false, false); + if (providerConfigMap != null && providerConfigMap.size() > 0) { + Map protocolConfigMap = applicationContext == null ? null : BeanFactoryUtils.beansOfTypeIncludingAncestors(applicationContext, ProtocolConfig.class, false, false); + if (CollectionUtils.isEmptyMap(protocolConfigMap) + && providerConfigMap.size() > 1) { // backward compatibility + List providerConfigs = new ArrayList(); + for (ProviderConfig config : providerConfigMap.values()) { + if (config.isDefault() != null && config.isDefault()) { + providerConfigs.add(config); + } + } + if (!providerConfigs.isEmpty()) { + setProviders(providerConfigs); + } + } else { + ProviderConfig providerConfig = null; + for (ProviderConfig config : providerConfigMap.values()) { + if (config.isDefault() == null || config.isDefault()) { + if (providerConfig != null) { + throw new IllegalStateException("Duplicate provider configs: " + providerConfig + " and " + config); + } + providerConfig = config; + } + } + if (providerConfig != null) { + setProvider(providerConfig); + } + } + } + } + if (getApplication() == null + && (getProvider() == null || getProvider().getApplication() == null)) { + Map applicationConfigMap = applicationContext == null ? null : BeanFactoryUtils.beansOfTypeIncludingAncestors(applicationContext, ApplicationConfig.class, false, false); + if (applicationConfigMap != null && applicationConfigMap.size() > 0) { + ApplicationConfig applicationConfig = null; + for (ApplicationConfig config : applicationConfigMap.values()) { + if (applicationConfig != null) { + throw new IllegalStateException("Duplicate application configs: " + applicationConfig + " and " + config); + } + applicationConfig = config; + } + if (applicationConfig != null) { + setApplication(applicationConfig); + } + } + } + if (getModule() == null + && (getProvider() == null || getProvider().getModule() == null)) { + Map moduleConfigMap = applicationContext == null ? null : BeanFactoryUtils.beansOfTypeIncludingAncestors(applicationContext, ModuleConfig.class, false, false); + if (moduleConfigMap != null && moduleConfigMap.size() > 0) { + ModuleConfig moduleConfig = null; + for (ModuleConfig config : moduleConfigMap.values()) { + if (config.isDefault() == null || config.isDefault()) { + if (moduleConfig != null) { + throw new IllegalStateException("Duplicate module configs: " + moduleConfig + " and " + config); + } + moduleConfig = config; + } + } + if (moduleConfig != null) { + setModule(moduleConfig); + } + } + } + + if (StringUtils.isEmpty(getRegistryIds())) { + if (getApplication() != null && StringUtils.isNotEmpty(getApplication().getRegistryIds())) { + setRegistryIds(getApplication().getRegistryIds()); + } + if (getProvider() != null && StringUtils.isNotEmpty(getProvider().getRegistryIds())) { + setRegistryIds(getProvider().getRegistryIds()); + } + } + + if ((CollectionUtils.isEmpty(getRegistries())) + && (getProvider() == null || CollectionUtils.isEmpty(getProvider().getRegistries())) + && (getApplication() == null || CollectionUtils.isEmpty(getApplication().getRegistries()))) { + Map registryConfigMap = applicationContext == null ? null : BeanFactoryUtils.beansOfTypeIncludingAncestors(applicationContext, RegistryConfig.class, false, false); + if (CollectionUtils.isNotEmptyMap(registryConfigMap)) { + List registryConfigs = new ArrayList<>(); + if (StringUtils.isNotEmpty(registryIds)) { + Arrays.stream(Constants.COMMA_SPLIT_PATTERN.split(registryIds)).forEach(id -> { + if (registryConfigMap.containsKey(id)) { + registryConfigs.add(registryConfigMap.get(id)); + } + }); + } + + if (registryConfigs.isEmpty()) { + for (RegistryConfig config : registryConfigMap.values()) { + if (StringUtils.isEmpty(registryIds)) { + registryConfigs.add(config); + } + } + } + if (!registryConfigs.isEmpty()) { + super.setRegistries(registryConfigs); + } + } + } + if (getMetadataReportConfig() == null) { + Map metadataReportConfigMap = applicationContext == null ? null : BeanFactoryUtils.beansOfTypeIncludingAncestors(applicationContext, MetadataReportConfig.class, false, false); + if (metadataReportConfigMap != null && metadataReportConfigMap.size() == 1) { + super.setMetadataReportConfig(metadataReportConfigMap.values().iterator().next()); + } else if (metadataReportConfigMap != null && metadataReportConfigMap.size() > 1) { + throw new IllegalStateException("Multiple MetadataReport configs: " + metadataReportConfigMap); + } + } + + if (getConfigCenter() == null) { + Map configenterMap = applicationContext == null ? null : BeanFactoryUtils.beansOfTypeIncludingAncestors(applicationContext, ConfigCenterConfig.class, false, false); + if (configenterMap != null && configenterMap.size() == 1) { + super.setConfigCenter(configenterMap.values().iterator().next()); + } else if (configenterMap != null && configenterMap.size() > 1) { + throw new IllegalStateException("Multiple ConfigCenter found:" + configenterMap); + } + } + + if (getMonitor() == null + && (getProvider() == null || getProvider().getMonitor() == null) + && (getApplication() == null || getApplication().getMonitor() == null)) { + Map monitorConfigMap = applicationContext == null ? null : BeanFactoryUtils.beansOfTypeIncludingAncestors(applicationContext, MonitorConfig.class, false, false); + if (monitorConfigMap != null && monitorConfigMap.size() > 0) { + MonitorConfig monitorConfig = null; + for (MonitorConfig config : monitorConfigMap.values()) { + if (config.isDefault() == null || config.isDefault()) { + if (monitorConfig != null) { + throw new IllegalStateException("Duplicate monitor configs: " + monitorConfig + " and " + config); + } + monitorConfig = config; + } + } + if (monitorConfig != null) { + setMonitor(monitorConfig); + } + } + } + + if (StringUtils.isEmpty(getProtocolIds())) { + if (getProvider() != null && StringUtils.isNotEmpty(getProvider().getProtocolIds())) { + setProtocolIds(getProvider().getProtocolIds()); + } + } + + if (CollectionUtils.isEmpty(getProtocols()) + && (getProvider() == null || CollectionUtils.isEmpty(getProvider().getProtocols()))) { + Map protocolConfigMap = applicationContext == null ? null : BeanFactoryUtils.beansOfTypeIncludingAncestors(applicationContext, ProtocolConfig.class, false, false); + if (protocolConfigMap != null && protocolConfigMap.size() > 0) { + List protocolConfigs = new ArrayList(); + if (StringUtils.isNotEmpty(getProtocolIds())) { + Arrays.stream(Constants.COMMA_SPLIT_PATTERN.split(getProtocolIds())) + .forEach(id -> { + if (protocolConfigMap.containsKey(id)) { + protocolConfigs.add(protocolConfigMap.get(id)); + } + }); + } + + if (protocolConfigs.isEmpty()) { + for (ProtocolConfig config : protocolConfigMap.values()) { + if (StringUtils.isEmpty(protocolIds)) { + protocolConfigs.add(config); + } + } + } + + if (!protocolConfigs.isEmpty()) { + super.setProtocols(protocolConfigs); + } + } + } + if (StringUtils.isEmpty(getPath())) { + if (StringUtils.isNotEmpty(beanName) + && StringUtils.isNotEmpty(getInterface()) + && beanName.startsWith(getInterface())) { + setPath(beanName); + } + } + if (!supportedApplicationListener) { + export(); + } + } + + /** + * Get the name of {@link ServiceBean} + * + * @return {@link ServiceBean}'s name + * @since 2.6.5 + */ + public String getBeanName() { + return this.beanName; + } + + /** + * @since 2.6.5 + */ + @Override + public void export() { + super.export(); + // Publish ServiceBeanExportedEvent + publishExportEvent(); + } + + /** + * @since 2.6.5 + */ + private void publishExportEvent() { + ServiceBeanExportedEvent exportEvent = new ServiceBeanExportedEvent(this); + applicationEventPublisher.publishEvent(exportEvent); + } + + @Override + public void destroy() throws Exception { + // no need to call unexport() here, see + // org.apache.dubbo.config.spring.extension.SpringExtensionFactory.ShutdownHookListener + } + + // merged from dubbox + @Override + protected Class getServiceClass(T ref) { + if (AopUtils.isAopProxy(ref)) { + return AopUtils.getTargetClass(ref); + } + return super.getServiceClass(ref); + } + + /** + * @param applicationEventPublisher + * @since 2.6.5 + */ + @Override + public void setApplicationEventPublisher(ApplicationEventPublisher applicationEventPublisher) { + this.applicationEventPublisher = applicationEventPublisher; + } +} \ No newline at end of file diff --git a/dubbo-config/dubbo-config-spring/src/main/java/org/apache/dubbo/config/spring/beans/factory/annotation/AbstractAnnotationConfigBeanBuilder.java b/dubbo-config/dubbo-config-spring/src/main/java/org/apache/dubbo/config/spring/beans/factory/annotation/AbstractAnnotationConfigBeanBuilder.java index eb99855e72b..7f7afd98d66 100644 --- a/dubbo-config/dubbo-config-spring/src/main/java/org/apache/dubbo/config/spring/beans/factory/annotation/AbstractAnnotationConfigBeanBuilder.java +++ b/dubbo-config/dubbo-config-spring/src/main/java/org/apache/dubbo/config/spring/beans/factory/annotation/AbstractAnnotationConfigBeanBuilder.java @@ -77,7 +77,7 @@ public final B build() throws Exception { configureBean(bean); if (logger.isInfoEnabled()) { - logger.info(bean + " has been built."); + logger.info("The bean[type:" + bean.getClass().getSimpleName() + "] has been built."); } return bean; @@ -175,7 +175,7 @@ private void configureModuleConfig(B bean) { /** - * Resolves the bean ids of {@link org.apache.dubbo.config.RegistryConfig} + * Resolves the bean ids of {@link RegistryConfig} * * @param annotation {@link A} * @return non-empty array diff --git a/dubbo-config/dubbo-config-spring/src/main/java/org/apache/dubbo/config/spring/beans/factory/annotation/AnnotationInjectedBeanPostProcessor.java b/dubbo-config/dubbo-config-spring/src/main/java/org/apache/dubbo/config/spring/beans/factory/annotation/AnnotationInjectedBeanPostProcessor.java new file mode 100644 index 00000000000..30592a1a7cb --- /dev/null +++ b/dubbo-config/dubbo-config-spring/src/main/java/org/apache/dubbo/config/spring/beans/factory/annotation/AnnotationInjectedBeanPostProcessor.java @@ -0,0 +1,531 @@ +/* + * 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.spring.beans.factory.annotation; + +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; +import org.springframework.beans.BeanUtils; +import org.springframework.beans.BeansException; +import org.springframework.beans.PropertyValues; +import org.springframework.beans.factory.BeanClassLoaderAware; +import org.springframework.beans.factory.BeanCreationException; +import org.springframework.beans.factory.BeanFactory; +import org.springframework.beans.factory.BeanFactoryAware; +import org.springframework.beans.factory.DisposableBean; +import org.springframework.beans.factory.annotation.InjectionMetadata; +import org.springframework.beans.factory.config.BeanPostProcessor; +import org.springframework.beans.factory.config.ConfigurableListableBeanFactory; +import org.springframework.beans.factory.config.InstantiationAwareBeanPostProcessorAdapter; +import org.springframework.beans.factory.support.MergedBeanDefinitionPostProcessor; +import org.springframework.beans.factory.support.RootBeanDefinition; +import org.springframework.context.EnvironmentAware; +import org.springframework.core.Ordered; +import org.springframework.core.PriorityOrdered; +import org.springframework.core.env.Environment; +import org.springframework.util.Assert; +import org.springframework.util.ClassUtils; +import org.springframework.util.ReflectionUtils; +import org.springframework.util.StringUtils; + +import java.beans.PropertyDescriptor; +import java.lang.annotation.Annotation; +import java.lang.reflect.Field; +import java.lang.reflect.Method; +import java.lang.reflect.Modifier; +import java.util.ArrayList; +import java.util.Collection; +import java.util.Collections; +import java.util.LinkedHashMap; +import java.util.LinkedList; +import java.util.List; +import java.util.Map; +import java.util.concurrent.ConcurrentHashMap; +import java.util.concurrent.ConcurrentMap; + +import static org.apache.dubbo.config.spring.util.ClassUtils.resolveGenericType; +import static org.springframework.core.BridgeMethodResolver.findBridgedMethod; +import static org.springframework.core.BridgeMethodResolver.isVisibilityBridgeMethodPair; +import static org.springframework.core.annotation.AnnotationUtils.findAnnotation; +import static org.springframework.core.annotation.AnnotationUtils.getAnnotation; + +/** + * Abstract generic {@link BeanPostProcessor} implementation for customized annotation that annotated injected-object. + * + * The source code is cloned from https://github.com/alibaba/spring-context-support/blob/1.0.2/src/main/java/com/alibaba/spring/beans/factory/annotation/AnnotationInjectedBeanPostProcessor.java + * + * @since 2.6.6 + */ +public abstract class AnnotationInjectedBeanPostProcessor extends + InstantiationAwareBeanPostProcessorAdapter implements MergedBeanDefinitionPostProcessor, PriorityOrdered, + BeanFactoryAware, BeanClassLoaderAware, EnvironmentAware, DisposableBean { + + private final static int CACHE_SIZE = Integer.getInteger("", 32); + + private final Log logger = LogFactory.getLog(getClass()); + + private final Class annotationType; + + private final ConcurrentMap injectionMetadataCache = + new ConcurrentHashMap(CACHE_SIZE); + + private final ConcurrentMap injectedObjectsCache = new ConcurrentHashMap(CACHE_SIZE); + + private ConfigurableListableBeanFactory beanFactory; + + private Environment environment; + + private ClassLoader classLoader; + + private int order = Ordered.LOWEST_PRECEDENCE; + + public AnnotationInjectedBeanPostProcessor() { + this.annotationType = resolveGenericType(getClass()); + } + + private static Collection combine(Collection... elements) { + List allElements = new ArrayList(); + for (Collection e : elements) { + allElements.addAll(e); + } + return allElements; + } + + /** + * Annotation type + * + * @return non-null + */ + public final Class getAnnotationType() { + return annotationType; + } + + @Override + public void setBeanFactory(BeanFactory beanFactory) throws BeansException { + Assert.isInstanceOf(ConfigurableListableBeanFactory.class, beanFactory, + "AnnotationInjectedBeanPostProcessor requires a ConfigurableListableBeanFactory"); + this.beanFactory = (ConfigurableListableBeanFactory) beanFactory; + } + + @Override + public PropertyValues postProcessPropertyValues( + PropertyValues pvs, PropertyDescriptor[] pds, Object bean, String beanName) throws BeanCreationException { + + InjectionMetadata metadata = findInjectionMetadata(beanName, bean.getClass(), pvs); + try { + metadata.inject(bean, beanName, pvs); + } catch (BeanCreationException ex) { + throw ex; + } catch (Throwable ex) { + throw new BeanCreationException(beanName, "Injection of @" + getAnnotationType().getName() + + " dependencies is failed", ex); + } + return pvs; + } + + + /** + * Finds {@link InjectionMetadata.InjectedElement} Metadata from annotated {@link A} fields + * + * @param beanClass The {@link Class} of Bean + * @return non-null {@link List} + */ + private List findFieldAnnotationMetadata(final Class beanClass) { + + final List elements = new LinkedList(); + + ReflectionUtils.doWithFields(beanClass, new ReflectionUtils.FieldCallback() { + @Override + public void doWith(Field field) throws IllegalArgumentException, IllegalAccessException { + + A annotation = getAnnotation(field, getAnnotationType()); + + if (annotation != null) { + + if (Modifier.isStatic(field.getModifiers())) { + if (logger.isWarnEnabled()) { + logger.warn("@" + getAnnotationType().getName() + " is not supported on static fields: " + field); + } + return; + } + + elements.add(new AnnotationInjectedBeanPostProcessor.AnnotatedFieldElement(field, annotation)); + } + + } + }); + + return elements; + + } + + /** + * Finds {@link InjectionMetadata.InjectedElement} Metadata from annotated {@link A @A} methods + * + * @param beanClass The {@link Class} of Bean + * @return non-null {@link List} + */ + private List findAnnotatedMethodMetadata(final Class beanClass) { + + final List elements = new LinkedList(); + + ReflectionUtils.doWithMethods(beanClass, new ReflectionUtils.MethodCallback() { + @Override + public void doWith(Method method) throws IllegalArgumentException, IllegalAccessException { + + Method bridgedMethod = findBridgedMethod(method); + + if (!isVisibilityBridgeMethodPair(method, bridgedMethod)) { + return; + } + + A annotation = findAnnotation(bridgedMethod, getAnnotationType()); + + if (annotation != null && method.equals(ClassUtils.getMostSpecificMethod(method, beanClass))) { + if (Modifier.isStatic(method.getModifiers())) { + if (logger.isWarnEnabled()) { + logger.warn("@" + getAnnotationType().getSimpleName() + " annotation is not supported on static methods: " + method); + } + return; + } + if (method.getParameterTypes().length == 0) { + if (logger.isWarnEnabled()) { + logger.warn("@" + getAnnotationType().getSimpleName() + " annotation should only be used on methods with parameters: " + + method); + } + } + PropertyDescriptor pd = BeanUtils.findPropertyForMethod(bridgedMethod, beanClass); + elements.add(new AnnotationInjectedBeanPostProcessor.AnnotatedMethodElement(method, pd, annotation)); + } + } + }); + + return elements; + + } + + + private AnnotationInjectedBeanPostProcessor.AnnotatedInjectionMetadata buildAnnotatedMetadata(final Class beanClass) { + Collection fieldElements = findFieldAnnotationMetadata(beanClass); + Collection methodElements = findAnnotatedMethodMetadata(beanClass); + return new AnnotationInjectedBeanPostProcessor.AnnotatedInjectionMetadata(beanClass, fieldElements, methodElements); + + } + + private InjectionMetadata findInjectionMetadata(String beanName, Class clazz, PropertyValues pvs) { + // Fall back to class name as cache key, for backwards compatibility with custom callers. + String cacheKey = (StringUtils.hasLength(beanName) ? beanName : clazz.getName()); + // Quick check on the concurrent map first, with minimal locking. + AnnotationInjectedBeanPostProcessor.AnnotatedInjectionMetadata metadata = this.injectionMetadataCache.get(cacheKey); + if (InjectionMetadata.needsRefresh(metadata, clazz)) { + synchronized (this.injectionMetadataCache) { + metadata = this.injectionMetadataCache.get(cacheKey); + if (InjectionMetadata.needsRefresh(metadata, clazz)) { + if (metadata != null) { + metadata.clear(pvs); + } + try { + metadata = buildAnnotatedMetadata(clazz); + this.injectionMetadataCache.put(cacheKey, metadata); + } catch (NoClassDefFoundError err) { + throw new IllegalStateException("Failed to introspect object class [" + clazz.getName() + + "] for annotation metadata: could not find class that it depends on", err); + } + } + } + } + return metadata; + } + + @Override + public void postProcessMergedBeanDefinition(RootBeanDefinition beanDefinition, Class beanType, String beanName) { + if (beanType != null) { + InjectionMetadata metadata = findInjectionMetadata(beanName, beanType, null); + metadata.checkConfigMembers(beanDefinition); + } + } + + @Override + public int getOrder() { + return order; + } + + public void setOrder(int order) { + this.order = order; + } + + @Override + public void destroy() throws Exception { + + for (Object object : injectedObjectsCache.values()) { + if (logger.isInfoEnabled()) { + logger.info(object + " was destroying!"); + } + + if (object instanceof DisposableBean) { + ((DisposableBean) object).destroy(); + } + } + + injectionMetadataCache.clear(); + injectedObjectsCache.clear(); + + if (logger.isInfoEnabled()) { + logger.info(getClass() + " was destroying!"); + } + + } + + @Override + public void setBeanClassLoader(ClassLoader classLoader) { + this.classLoader = classLoader; + } + + @Override + public void setEnvironment(Environment environment) { + this.environment = environment; + } + + protected Environment getEnvironment() { + return environment; + } + + protected ClassLoader getClassLoader() { + return classLoader; + } + + protected ConfigurableListableBeanFactory getBeanFactory() { + return beanFactory; + } + + /** + * Gets all injected-objects. + * + * @return non-null {@link Collection} + */ + protected Collection getInjectedObjects() { + return this.injectedObjectsCache.values(); + } + + /** + * Get injected-object from specified {@link A annotation} and Bean Class + * + * @param annotation {@link A annotation} + * @param bean Current bean that will be injected + * @param beanName Current bean name that will be injected + * @param injectedType the type of injected-object + * @param injectedElement {@link InjectionMetadata.InjectedElement} + * @return An injected object + * @throws Exception If getting is failed + */ + protected Object getInjectedObject(A annotation, Object bean, String beanName, Class injectedType, + InjectionMetadata.InjectedElement injectedElement) throws Exception { + + String cacheKey = buildInjectedObjectCacheKey(annotation, bean, beanName, injectedType, injectedElement); + + Object injectedObject = injectedObjectsCache.get(cacheKey); + + if (injectedObject == null) { + injectedObject = doGetInjectedBean(annotation, bean, beanName, injectedType, injectedElement); + // Customized inject-object if necessary + injectedObjectsCache.putIfAbsent(cacheKey, injectedObject); + } + + return injectedObject; + + } + + /** + * Subclass must implement this method to get injected-object. The context objects could help this method if + * necessary : + *
    + *
  • {@link #getBeanFactory() BeanFactory}
  • + *
  • {@link #getClassLoader() ClassLoader}
  • + *
  • {@link #getEnvironment() Environment}
  • + *
+ * + * @param annotation {@link A annotation} + * @param bean Current bean that will be injected + * @param beanName Current bean name that will be injected + * @param injectedType the type of injected-object + * @param injectedElement {@link InjectionMetadata.InjectedElement} + * @return The injected object + * @throws Exception If resolving an injected object is failed. + */ + protected abstract Object doGetInjectedBean(A annotation, Object bean, String beanName, Class injectedType, + InjectionMetadata.InjectedElement injectedElement) throws Exception; + + /** + * Build a cache key for injected-object. The context objects could help this method if + * necessary : + *
    + *
  • {@link #getBeanFactory() BeanFactory}
  • + *
  • {@link #getClassLoader() ClassLoader}
  • + *
  • {@link #getEnvironment() Environment}
  • + *
+ * + * @param annotation {@link A annotation} + * @param bean Current bean that will be injected + * @param beanName Current bean name that will be injected + * @param injectedType the type of injected-object + * @param injectedElement {@link InjectionMetadata.InjectedElement} + * @return Bean cache key + */ + protected abstract String buildInjectedObjectCacheKey(A annotation, Object bean, String beanName, + Class injectedType, + InjectionMetadata.InjectedElement injectedElement); + + /** + * Get {@link Map} in injected field. + * + * @return non-null ready-only {@link Map} + */ + protected Map getInjectedFieldObjectsMap() { + + Map injectedElementBeanMap = + new LinkedHashMap(); + + for (AnnotationInjectedBeanPostProcessor.AnnotatedInjectionMetadata metadata : injectionMetadataCache.values()) { + + Collection fieldElements = metadata.getFieldElements(); + + for (AnnotationInjectedBeanPostProcessor.AnnotatedFieldElement fieldElement : fieldElements) { + + injectedElementBeanMap.put(fieldElement, fieldElement.bean); + + } + + } + + return Collections.unmodifiableMap(injectedElementBeanMap); + + } + + /** + * Get {@link Map} in injected method. + * + * @return non-null {@link Map} + */ + protected Map getInjectedMethodObjectsMap() { + + Map injectedElementBeanMap = + new LinkedHashMap(); + + for (AnnotationInjectedBeanPostProcessor.AnnotatedInjectionMetadata metadata : injectionMetadataCache.values()) { + + Collection methodElements = metadata.getMethodElements(); + + for (AnnotationInjectedBeanPostProcessor.AnnotatedMethodElement methodElement : methodElements) { + + injectedElementBeanMap.put(methodElement, methodElement.object); + + } + + } + + return Collections.unmodifiableMap(injectedElementBeanMap); + + } + + /** + * {@link A} {@link InjectionMetadata} implementation + */ + private class AnnotatedInjectionMetadata extends InjectionMetadata { + + private final Collection fieldElements; + + private final Collection methodElements; + + public AnnotatedInjectionMetadata(Class targetClass, Collection fieldElements, + Collection methodElements) { + super(targetClass, combine(fieldElements, methodElements)); + this.fieldElements = fieldElements; + this.methodElements = methodElements; + } + + public Collection getFieldElements() { + return fieldElements; + } + + public Collection getMethodElements() { + return methodElements; + } + } + + /** + * {@link A} {@link Method} {@link InjectionMetadata.InjectedElement} + */ + private class AnnotatedMethodElement extends InjectionMetadata.InjectedElement { + + private final Method method; + + private final A annotation; + + private volatile Object object; + + protected AnnotatedMethodElement(Method method, PropertyDescriptor pd, A annotation) { + super(method, pd); + this.method = method; + this.annotation = annotation; + } + + @Override + protected void inject(Object bean, String beanName, PropertyValues pvs) throws Throwable { + + Class injectedType = pd.getPropertyType(); + + Object injectedObject = getInjectedObject(annotation, bean, beanName, injectedType, this); + + ReflectionUtils.makeAccessible(method); + + method.invoke(bean, injectedObject); + + } + + } + + /** + * {@link A} {@link Field} {@link InjectionMetadata.InjectedElement} + */ + public class AnnotatedFieldElement extends InjectionMetadata.InjectedElement { + + private final Field field; + + private final A annotation; + + private volatile Object bean; + + protected AnnotatedFieldElement(Field field, A annotation) { + super(field, null); + this.field = field; + this.annotation = annotation; + } + + @Override + protected void inject(Object bean, String beanName, PropertyValues pvs) throws Throwable { + + Class injectedType = field.getType(); + + Object injectedObject = getInjectedObject(annotation, bean, beanName, injectedType, this); + + ReflectionUtils.makeAccessible(field); + + field.set(bean, injectedObject); + + } + + } +} diff --git a/dubbo-config/dubbo-config-spring/src/main/java/org/apache/dubbo/config/spring/beans/factory/annotation/DubboConfigBindingBeanPostProcessor.java b/dubbo-config/dubbo-config-spring/src/main/java/org/apache/dubbo/config/spring/beans/factory/annotation/DubboConfigBindingBeanPostProcessor.java index 65aadeff359..96c4d3885b0 100644 --- a/dubbo-config/dubbo-config-spring/src/main/java/org/apache/dubbo/config/spring/beans/factory/annotation/DubboConfigBindingBeanPostProcessor.java +++ b/dubbo-config/dubbo-config-spring/src/main/java/org/apache/dubbo/config/spring/beans/factory/annotation/DubboConfigBindingBeanPostProcessor.java @@ -76,7 +76,7 @@ public DubboConfigBindingBeanPostProcessor(String prefix, String beanName) { @Override public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException { - if (beanName != null && beanName.equals(this.beanName) && bean instanceof AbstractConfig) { + if (beanName.equals(this.beanName) && bean instanceof AbstractConfig) { AbstractConfig dubboConfig = (AbstractConfig) bean; diff --git a/dubbo-config/dubbo-config-spring/src/main/java/org/apache/dubbo/config/spring/beans/factory/annotation/ReferenceAnnotationBeanPostProcessor.java b/dubbo-config/dubbo-config-spring/src/main/java/org/apache/dubbo/config/spring/beans/factory/annotation/ReferenceAnnotationBeanPostProcessor.java index 926c15a0115..82fb9b25eb0 100644 --- a/dubbo-config/dubbo-config-spring/src/main/java/org/apache/dubbo/config/spring/beans/factory/annotation/ReferenceAnnotationBeanPostProcessor.java +++ b/dubbo-config/dubbo-config-spring/src/main/java/org/apache/dubbo/config/spring/beans/factory/annotation/ReferenceAnnotationBeanPostProcessor.java @@ -16,583 +16,237 @@ */ package org.apache.dubbo.config.spring.beans.factory.annotation; -import org.apache.dubbo.common.Constants; -import org.apache.dubbo.common.utils.ArrayUtils; -import org.apache.dubbo.common.utils.StringUtils; import org.apache.dubbo.config.annotation.Reference; import org.apache.dubbo.config.spring.ReferenceBean; +import org.apache.dubbo.config.spring.ServiceBean; +import org.apache.dubbo.config.spring.context.event.ServiceBeanExportedEvent; +import org.apache.dubbo.config.spring.util.AnnotationUtils; -import org.apache.commons.logging.Log; -import org.apache.commons.logging.LogFactory; -import org.springframework.beans.BeanUtils; import org.springframework.beans.BeansException; -import org.springframework.beans.PropertyValues; -import org.springframework.beans.factory.BeanClassLoaderAware; -import org.springframework.beans.factory.BeanCreationException; -import org.springframework.beans.factory.DisposableBean; import org.springframework.beans.factory.annotation.InjectionMetadata; -import org.springframework.beans.factory.config.InstantiationAwareBeanPostProcessorAdapter; -import org.springframework.beans.factory.support.MergedBeanDefinitionPostProcessor; -import org.springframework.beans.factory.support.RootBeanDefinition; import org.springframework.context.ApplicationContext; import org.springframework.context.ApplicationContextAware; -import org.springframework.core.PriorityOrdered; -import org.springframework.core.env.Environment; -import org.springframework.util.ClassUtils; -import org.springframework.util.ConcurrentReferenceHashMap; -import org.springframework.util.ObjectUtils; -import org.springframework.util.ReflectionUtils; - -import java.beans.PropertyDescriptor; -import java.lang.annotation.Annotation; +import org.springframework.context.ApplicationEvent; +import org.springframework.context.ApplicationListener; +import org.springframework.context.event.ContextRefreshedEvent; + import java.lang.reflect.Field; +import java.lang.reflect.InvocationHandler; import java.lang.reflect.Method; -import java.lang.reflect.Modifier; -import java.util.ArrayList; +import java.lang.reflect.Proxy; import java.util.Collection; -import java.util.Iterator; -import java.util.LinkedHashMap; -import java.util.LinkedList; -import java.util.List; +import java.util.Collections; import java.util.Map; import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.ConcurrentMap; -import static org.springframework.core.BridgeMethodResolver.findBridgedMethod; -import static org.springframework.core.BridgeMethodResolver.isVisibilityBridgeMethodPair; -import static org.springframework.core.annotation.AnnotationUtils.findAnnotation; -import static org.springframework.core.annotation.AnnotationUtils.getAnnotation; - /** * {@link org.springframework.beans.factory.config.BeanPostProcessor} implementation * that Consumer service {@link Reference} annotated fields * * @since 2.5.7 */ -public class ReferenceAnnotationBeanPostProcessor extends InstantiationAwareBeanPostProcessorAdapter - implements MergedBeanDefinitionPostProcessor, PriorityOrdered, ApplicationContextAware, BeanClassLoaderAware, - DisposableBean { +public class ReferenceAnnotationBeanPostProcessor extends AnnotationInjectedBeanPostProcessor + implements ApplicationContextAware, ApplicationListener { /** * The bean name of {@link ReferenceAnnotationBeanPostProcessor} */ public static final String BEAN_NAME = "referenceAnnotationBeanPostProcessor"; - private final Log logger = LogFactory.getLog(getClass()); - - private ApplicationContext applicationContext; - - private ClassLoader classLoader; + /** + * Cache size + */ + private static final int CACHE_SIZE = Integer.getInteger(BEAN_NAME + ".cache.size", 32); - private final ConcurrentMap injectionMetadataCache = - new ConcurrentHashMap(256); + private final ConcurrentMap> referenceBeanCache = + new ConcurrentHashMap>(CACHE_SIZE); - private final ConcurrentMap> referenceBeansCache = - new ConcurrentHashMap>(); + private final ConcurrentHashMap localReferenceBeanInvocationHandlerCache = + new ConcurrentHashMap(CACHE_SIZE); - private static final Map, List> annotationMethodsCache = - new ConcurrentReferenceHashMap, List>(256); + private final ConcurrentMap> injectedFieldReferenceBeanCache = + new ConcurrentHashMap>(CACHE_SIZE); - @Override - public PropertyValues postProcessPropertyValues( - PropertyValues pvs, PropertyDescriptor[] pds, Object bean, String beanName) throws BeanCreationException { - - InjectionMetadata metadata = findReferenceMetadata(beanName, bean.getClass(), pvs); - try { - metadata.inject(bean, beanName, pvs); - } catch (BeanCreationException ex) { - throw ex; - } catch (Throwable ex) { - throw new BeanCreationException(beanName, "Injection of @Reference dependencies failed", ex); - } - return pvs; - } + private final ConcurrentMap> injectedMethodReferenceBeanCache = + new ConcurrentHashMap>(CACHE_SIZE); + private ApplicationContext applicationContext; /** - * Finds {@link InjectionMetadata.InjectedElement} Metadata from annotated {@link Reference @Reference} fields + * Gets all beans of {@link ReferenceBean} * - * @param beanClass The {@link Class} of Bean - * @return non-null {@link List} + * @return non-null read-only {@link Collection} + * @since 2.5.9 */ - private List findFieldReferenceMetadata(final Class beanClass) { - - final List elements = new LinkedList(); - - ReflectionUtils.doWithFields(beanClass, new ReflectionUtils.FieldCallback() { - @Override - public void doWith(Field field) throws IllegalArgumentException, IllegalAccessException { - - Reference reference = getAnnotation(field, Reference.class); - - if (reference != null) { - - if (Modifier.isStatic(field.getModifiers())) { - if (logger.isWarnEnabled()) { - logger.warn("@Reference annotation is not supported on static fields: " + field); - } - return; - } - - elements.add(new ReferenceFieldElement(field, reference)); - } - - } - }); - - return elements; - + public Collection> getReferenceBeans() { + return referenceBeanCache.values(); } /** - * Finds {@link InjectionMetadata.InjectedElement} Metadata from annotated {@link Reference @Reference} methods + * Get {@link ReferenceBean} {@link Map} in injected field. * - * @param beanClass The {@link Class} of Bean - * @return non-null {@link List} + * @return non-null {@link Map} + * @since 2.5.11 */ - private List findMethodReferenceMetadata(final Class beanClass) { - - final List elements = new LinkedList(); - - ReflectionUtils.doWithMethods(beanClass, new ReflectionUtils.MethodCallback() { - @Override - public void doWith(Method method) throws IllegalArgumentException, IllegalAccessException { - - Method bridgedMethod = findBridgedMethod(method); - - if (!isVisibilityBridgeMethodPair(method, bridgedMethod)) { - return; - } - - Reference reference = findAnnotation(bridgedMethod, Reference.class); - - if (reference != null && method.equals(ClassUtils.getMostSpecificMethod(method, beanClass))) { - if (Modifier.isStatic(method.getModifiers())) { - if (logger.isWarnEnabled()) { - logger.warn("@Reference annotation is not supported on static methods: " + method); - } - return; - } - if (method.getParameterTypes().length == 0) { - if (logger.isWarnEnabled()) { - logger.warn("@Reference annotation should only be used on methods with parameters: " + - method); - } - } - PropertyDescriptor pd = BeanUtils.findPropertyForMethod(bridgedMethod, beanClass); - elements.add(new ReferenceMethodElement(method, pd, reference)); - } - } - }); - - return elements; - + public Map> getInjectedFieldReferenceBeanMap() { + return Collections.unmodifiableMap(injectedFieldReferenceBeanCache); } - /** - * @param beanClass - * @return + * Get {@link ReferenceBean} {@link Map} in injected method. + * + * @return non-null {@link Map} + * @since 2.5.11 */ - private ReferenceInjectionMetadata buildReferenceMetadata(final Class beanClass) { - Collection fieldElements = findFieldReferenceMetadata(beanClass); - Collection methodElements = findMethodReferenceMetadata(beanClass); - return new ReferenceInjectionMetadata(beanClass, fieldElements, methodElements); - - } - - private InjectionMetadata findReferenceMetadata(String beanName, Class clazz, PropertyValues pvs) { - // Fall back to class name as cache key, for backwards compatibility with custom callers. - String cacheKey = (StringUtils.isNotEmpty(beanName) ? beanName : clazz.getName()); - // Quick check on the concurrent map first, with minimal locking. - ReferenceInjectionMetadata metadata = this.injectionMetadataCache.get(cacheKey); - if (InjectionMetadata.needsRefresh(metadata, clazz)) { - synchronized (this.injectionMetadataCache) { - metadata = this.injectionMetadataCache.get(cacheKey); - if (InjectionMetadata.needsRefresh(metadata, clazz)) { - if (metadata != null) { - metadata.clear(pvs); - } - try { - metadata = buildReferenceMetadata(clazz); - this.injectionMetadataCache.put(cacheKey, metadata); - } catch (NoClassDefFoundError err) { - throw new IllegalStateException("Failed to introspect bean class [" + clazz.getName() + - "] for reference metadata: could not find class that it depends on", err); - } - } - } - } - return metadata; - } - - @Override - public void setApplicationContext(ApplicationContext applicationContext) throws BeansException { - this.applicationContext = applicationContext; - } - - @Override - public void postProcessMergedBeanDefinition(RootBeanDefinition beanDefinition, Class beanType, String beanName) { - if (beanType != null) { - InjectionMetadata metadata = findReferenceMetadata(beanName, beanType, null); - metadata.checkConfigMembers(beanDefinition); - } + public Map> getInjectedMethodReferenceBeanMap() { + return Collections.unmodifiableMap(injectedMethodReferenceBeanCache); } @Override - public int getOrder() { - return LOWEST_PRECEDENCE; - } + protected Object doGetInjectedBean(Reference reference, Object bean, String beanName, Class injectedType, + InjectionMetadata.InjectedElement injectedElement) throws Exception { - @Override - public void destroy() throws Exception { + String referencedBeanName = buildReferencedBeanName(reference, injectedType); - for (ReferenceBean referenceBean : referenceBeansCache.values()) { - if (logger.isInfoEnabled()) { - logger.info(referenceBean + " was destroying!"); - } - referenceBean.destroy(); - } + ReferenceBean referenceBean = buildReferenceBeanIfAbsent(referencedBeanName, reference, injectedType, getClassLoader()); - injectionMetadataCache.clear(); - referenceBeansCache.clear(); + cacheInjectedReferenceBean(referenceBean, injectedElement); - if (logger.isInfoEnabled()) { - logger.info(getClass() + " was destroying!"); - } + Object proxy = buildProxy(referencedBeanName, referenceBean, injectedType); + return proxy; } - @Override - public void setBeanClassLoader(ClassLoader classLoader) { - this.classLoader = classLoader; - } - - - /** - * Gets all beans of {@link ReferenceBean} - * - * @return non-null {@link Collection} - * @since 2.5.9 - */ - public Collection> getReferenceBeans() { - return this.referenceBeansCache.values(); + private Object buildProxy(String referencedBeanName, ReferenceBean referenceBean, Class injectedType) { + InvocationHandler handler = buildInvocationHandler(referencedBeanName, referenceBean); + Object proxy = Proxy.newProxyInstance(getClassLoader(), new Class[]{injectedType}, handler); + return proxy; } + private InvocationHandler buildInvocationHandler(String referencedBeanName, ReferenceBean referenceBean) { - /** - * {@link Reference} {@link InjectionMetadata} implementation - * - * @since 2.5.11 - */ - private static class ReferenceInjectionMetadata extends InjectionMetadata { - - private final Collection fieldElements; - - private final Collection methodElements; - + ReferenceBeanInvocationHandler handler = localReferenceBeanInvocationHandlerCache.get(referencedBeanName); - public ReferenceInjectionMetadata(Class targetClass, Collection fieldElements, - Collection methodElements) { - super(targetClass, combine(fieldElements, methodElements)); - this.fieldElements = fieldElements; - this.methodElements = methodElements; + if (handler == null) { + handler = new ReferenceBeanInvocationHandler(referenceBean); } - private static Collection combine(Collection... elements) { - List allElements = new ArrayList(); - for (Collection e : elements) { - allElements.addAll(e); - } - return allElements; - } - - public Collection getFieldElements() { - return fieldElements; + if (applicationContext.containsBean(referencedBeanName)) { // Is local @Service Bean or not ? + // ReferenceBeanInvocationHandler's initialization has to wait for current local @Service Bean has been exported. + localReferenceBeanInvocationHandlerCache.put(referencedBeanName, handler); + } else { + // Remote Reference Bean should initialize immediately + handler.init(); } - public Collection getMethodElements() { - return methodElements; - } + return handler; } - /** - * {@link Reference} {@link Method} {@link InjectionMetadata.InjectedElement} - */ - private class ReferenceMethodElement extends InjectionMetadata.InjectedElement { + private static class ReferenceBeanInvocationHandler implements InvocationHandler { - private final Method method; + private final ReferenceBean referenceBean; - private final Reference reference; + private Object bean; - private volatile ReferenceBean referenceBean; - - protected ReferenceMethodElement(Method method, PropertyDescriptor pd, Reference reference) { - super(method, pd); - this.method = method; - this.reference = reference; + private ReferenceBeanInvocationHandler(ReferenceBean referenceBean) { + this.referenceBean = referenceBean; } @Override - protected void inject(Object bean, String beanName, PropertyValues pvs) throws Throwable { - - Class referenceClass = pd.getPropertyType(); - - referenceBean = buildReferenceBean(reference, referenceClass); - - ReflectionUtils.makeAccessible(method); - - method.invoke(bean, referenceBean.getObject()); - + public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { + return method.invoke(bean, args); } - } - - /** - * {@link Reference} {@link Field} {@link InjectionMetadata.InjectedElement} - */ - private class ReferenceFieldElement extends InjectionMetadata.InjectedElement { - - private final Field field; - - private final Reference reference; - - private volatile ReferenceBean referenceBean; - - protected ReferenceFieldElement(Field field, Reference reference) { - super(field, null); - this.field = field; - this.reference = reference; + private void init() { + this.bean = referenceBean.get(); } + } - @Override - protected void inject(Object bean, String beanName, PropertyValues pvs) throws Throwable { - - Class referenceClass = field.getType(); + @Override + protected String buildInjectedObjectCacheKey(Reference reference, Object bean, String beanName, + Class injectedType, InjectionMetadata.InjectedElement injectedElement) { - referenceBean = buildReferenceBean(reference, referenceClass); + String key = buildReferencedBeanName(reference, injectedType) + + "#source=" + (injectedElement.getMember()) + + "#attributes=" + AnnotationUtils.getAttributes(reference,getEnvironment(),true); - ReflectionUtils.makeAccessible(field); + return key; + } - field.set(bean, referenceBean.getObject()); + private String buildReferencedBeanName(Reference reference, Class injectedType) { - } + ServiceBeanNameBuilder builder = ServiceBeanNameBuilder.create(reference, injectedType, getEnvironment()); + return getEnvironment().resolvePlaceholders(builder.build()); } - private ReferenceBean buildReferenceBean(Reference reference, Class referenceClass) throws Exception { - - String referenceBeanCacheKey = generateReferenceBeanCacheKey(reference, referenceClass); + private ReferenceBean buildReferenceBeanIfAbsent(String referencedBeanName, Reference reference, + Class referencedType, ClassLoader classLoader) + throws Exception { - ReferenceBean referenceBean = referenceBeansCache.get(referenceBeanCacheKey); + ReferenceBean referenceBean = referenceBeanCache.get(referencedBeanName); if (referenceBean == null) { - ReferenceBeanBuilder beanBuilder = ReferenceBeanBuilder .create(reference, classLoader, applicationContext) - .interfaceClass(referenceClass); - + .interfaceClass(referencedType); referenceBean = beanBuilder.build(); - - referenceBeansCache.putIfAbsent(referenceBeanCacheKey, referenceBean); - + referenceBeanCache.put(referencedBeanName, referenceBean); } return referenceBean; - - } - - - /** - * Generate a cache key of {@link ReferenceBean} - * - * @param reference {@link Reference} - * @param beanClass {@link Class} - * @return - */ - private String generateReferenceBeanCacheKey(Reference reference, Class beanClass) { - - String key = resolveReferenceKey(annotationValues(reference)); - - Environment environment = applicationContext.getEnvironment(); - - key = environment.resolvePlaceholders(key); - - return key; - } - private static String resolveInterfaceName(Reference reference, Class beanClass) - throws IllegalStateException { - - String interfaceName; - if (!"".equals(reference.interfaceName())) { - interfaceName = reference.interfaceName(); - } else if (!void.class.equals(reference.interfaceClass())) { - interfaceName = reference.interfaceClass().getName(); - } else if (beanClass.isInterface()) { - interfaceName = beanClass.getName(); - } else { - throw new IllegalStateException( - "The @Reference undefined interfaceClass or interfaceName, and the property type " - + beanClass.getName() + " is not a interface."); + private void cacheInjectedReferenceBean(ReferenceBean referenceBean, + InjectionMetadata.InjectedElement injectedElement) { + if (injectedElement.getMember() instanceof Field) { + injectedFieldReferenceBeanCache.put(injectedElement, referenceBean); + } else if (injectedElement.getMember() instanceof Method) { + injectedMethodReferenceBeanCache.put(injectedElement, referenceBean); } - - return interfaceName; - } - - /** - * Get {@link ReferenceBean} {@link Map} in injected field. - * - * @return non-null {@link Map} - * @since 2.5.11 - */ - public Map> getInjectedFieldReferenceBeanMap() { - - Map> injectedElementReferenceBeanMap = - new LinkedHashMap>(); - - for (ReferenceInjectionMetadata metadata : injectionMetadataCache.values()) { - - Collection fieldElements = metadata.getFieldElements(); - - for (ReferenceFieldElement fieldElement : fieldElements) { - - injectedElementReferenceBeanMap.put(fieldElement, fieldElement.referenceBean); - - } - - } - - return injectedElementReferenceBeanMap; - + @Override + public void setApplicationContext(ApplicationContext applicationContext) throws BeansException { + this.applicationContext = applicationContext; } - /** - * Get {@link ReferenceBean} {@link Map} in injected method. - * - * @return non-null {@link Map} - * @since 2.5.11 - */ - public Map> getInjectedMethodReferenceBeanMap() { - - Map> injectedElementReferenceBeanMap = - new LinkedHashMap>(); - - for (ReferenceInjectionMetadata metadata : injectionMetadataCache.values()) { - - Collection methodElements = metadata.getMethodElements(); - - for (ReferenceMethodElement methodElement : methodElements) { - - injectedElementReferenceBeanMap.put(methodElement, methodElement.referenceBean); - - } - + @Override + public void onApplicationEvent(ApplicationEvent event) { + if (event instanceof ServiceBeanExportedEvent) { + onServiceBeanExportEvent((ServiceBeanExportedEvent) event); + } else if (event instanceof ContextRefreshedEvent) { + onContextRefreshedEvent((ContextRefreshedEvent) event); } - - return injectedElementReferenceBeanMap; - } - private T getFieldValue(Object object, String fieldName, Class fieldType) { - - Field field = ReflectionUtils.findField(object.getClass(), fieldName, fieldType); - - ReflectionUtils.makeAccessible(field); - - return (T) ReflectionUtils.getField(field, object); - - } - - /** - * Generate a key based on the annotation. - * - * @param annotations annotation value - * @return unique key, never null will be returned. - * @since 2.7.0 - */ - private String resolveReferenceKey(Map annotations) { - Iterator> annotationVisitor = annotations.entrySet().iterator(); - StringBuilder builder = new StringBuilder(); - while (annotationVisitor.hasNext()) { - Map.Entry attribute = annotationVisitor.next(); - String attributeValue = null; - if (attribute.getValue() instanceof String[]) { - attributeValue = toPlainString((String[]) attribute.getValue()); - } else { - attributeValue = attribute.getValue() == null ? "" : attribute.getValue().toString(); - } - - if (StringUtils.isNotEmpty(attributeValue)) { - if (builder.length() > 0) { - builder.append(Constants.PATH_SEPARATOR); - } - builder.append(attributeValue); - } - } - return builder.toString(); + private void onServiceBeanExportEvent(ServiceBeanExportedEvent event) { + ServiceBean serviceBean = event.getServiceBean(); + initReferenceBeanInvocationHandler(serviceBean); } - private Map annotationValues(Annotation annotation) { - Map annotations = new LinkedHashMap<>(); - - for (Method method : getAnnotationMethods(annotation.annotationType())) { - try { - Object attributeValue = method.invoke(annotation); - Object defaultValue = method.getDefaultValue(); - if (nullSafeEquals(attributeValue, defaultValue)) { - continue; - } - annotations.put(method.getName(), attributeValue); - } catch (Throwable e) { - throw new IllegalStateException("Failed to obtain annotation attribute value for " + method, e); - } + private void initReferenceBeanInvocationHandler(ServiceBean serviceBean) { + String serviceBeanName = serviceBean.getBeanName(); + // Remove ServiceBean when it's exported + ReferenceBeanInvocationHandler handler = localReferenceBeanInvocationHandlerCache.remove(serviceBeanName); + // Initialize + if (handler != null) { + handler.init(); } - return annotations; } - private static List getAnnotationMethods(Class annotationType) { - List methods = annotationMethodsCache.get(annotationType); - if (methods != null) { - return methods; - } - - methods = new ArrayList(); - for (Method method : annotationType.getDeclaredMethods()) { - if (isAnnotationMethod(method)) { - ReflectionUtils.makeAccessible(method); - methods.add(method); - } - } + private void onContextRefreshedEvent(ContextRefreshedEvent event) { - annotationMethodsCache.put(annotationType, methods); - return methods; } - private static boolean isAnnotationMethod(Method method) { - return (method != null - && method.getParameterTypes().length == 0 - && method.getReturnType() != void.class); - } - private static boolean nullSafeEquals(Object first, Object another) { - return ObjectUtils.nullSafeEquals(first, another); - } - - private String toPlainString(String[] array) { - if (ArrayUtils.isEmpty(array)) { - return ""; - } - StringBuilder buffer = new StringBuilder(); - for (int i = 0; i < array.length; i++) { - if (i > 0) { - buffer.append(Constants.COMMA_SEPARATOR); - } - buffer.append(array[i]); - } - return buffer.toString(); + @Override + public void destroy() throws Exception { + super.destroy(); + this.referenceBeanCache.clear(); + this.localReferenceBeanInvocationHandlerCache.clear(); + this.injectedFieldReferenceBeanCache.clear(); + this.injectedMethodReferenceBeanCache.clear(); } } diff --git a/dubbo-config/dubbo-config-spring/src/main/java/org/apache/dubbo/config/spring/beans/factory/annotation/ReferenceBeanBuilder.java b/dubbo-config/dubbo-config-spring/src/main/java/org/apache/dubbo/config/spring/beans/factory/annotation/ReferenceBeanBuilder.java index 617b5f15ff9..aff3ed2a5d0 100644 --- a/dubbo-config/dubbo-config-spring/src/main/java/org/apache/dubbo/config/spring/beans/factory/annotation/ReferenceBeanBuilder.java +++ b/dubbo-config/dubbo-config-spring/src/main/java/org/apache/dubbo/config/spring/beans/factory/annotation/ReferenceBeanBuilder.java @@ -16,22 +16,24 @@ */ package org.apache.dubbo.config.spring.beans.factory.annotation; +import org.apache.dubbo.common.utils.CollectionUtils; import org.apache.dubbo.config.ConsumerConfig; import org.apache.dubbo.config.annotation.Reference; import org.apache.dubbo.config.spring.ReferenceBean; -import org.apache.dubbo.config.spring.convert.converter.StringArrayToMapConverter; -import org.apache.dubbo.config.spring.convert.converter.StringArrayToStringConverter; +import org.springframework.beans.propertyeditors.StringTrimmerEditor; import org.springframework.context.ApplicationContext; -import org.springframework.core.convert.ConversionService; -import org.springframework.core.convert.support.DefaultConversionService; import org.springframework.util.Assert; import org.springframework.util.ClassUtils; import org.springframework.util.StringUtils; import org.springframework.validation.DataBinder; +import java.beans.PropertyEditorSupport; +import java.util.Map; + import static org.apache.dubbo.config.spring.util.BeanFactoryUtils.getOptionalBean; import static org.apache.dubbo.config.spring.util.ObjectUtils.of; +import static org.springframework.util.StringUtils.commaDelimitedListToStringArray; /** * {@link ReferenceBean} Builder @@ -40,6 +42,8 @@ */ class ReferenceBeanBuilder extends AbstractAnnotationConfigBeanBuilder { + // Ignore those fields + static final String[] IGNORE_FIELD_NAMES = of("application", "module", "consumer", "monitor", "registry"); private ReferenceBeanBuilder(Reference annotation, ClassLoader classLoader, ApplicationContext applicationContext) { super(annotation, classLoader, applicationContext); @@ -94,20 +98,30 @@ protected ReferenceBean doBuild() { protected void preConfigureBean(Reference reference, ReferenceBean referenceBean) { Assert.notNull(interfaceClass, "The interface class must set first!"); DataBinder dataBinder = new DataBinder(referenceBean); - // Set ConversionService - dataBinder.setConversionService(getConversionService()); - // Ignore those fields - String[] ignoreAttributeNames = of("application", "module", "consumer", "monitor", "registry"); -// dataBinder.setDisallowedFields(ignoreAttributeNames); + // Register CustomEditors for special fields + dataBinder.registerCustomEditor(String.class, "filter", new StringTrimmerEditor(true)); + dataBinder.registerCustomEditor(String.class, "listener", new StringTrimmerEditor(true)); + dataBinder.registerCustomEditor(Map.class, "parameters", new PropertyEditorSupport() { + @Override + public void setAsText(String text) throws java.lang.IllegalArgumentException { + // Trim all whitespace + String content = StringUtils.trimAllWhitespace(text); + if (!StringUtils.hasText(content)) { // No content , ignore directly + return; + } + // replace "=" to "," + content = StringUtils.replace(content, "=", ","); + // replace ":" to "," + content = StringUtils.replace(content, ":", ","); + // String[] to Map + Map parameters = CollectionUtils.toStringMap(commaDelimitedListToStringArray(content)); + setValue(parameters); + } + }); + // Bind annotation attributes - dataBinder.bind(new AnnotationPropertyValuesAdapter(reference, applicationContext.getEnvironment(), ignoreAttributeNames)); - } + dataBinder.bind(new AnnotationPropertyValuesAdapter(reference, applicationContext.getEnvironment(), IGNORE_FIELD_NAMES)); - private ConversionService getConversionService() { - DefaultConversionService conversionService = new DefaultConversionService(); - conversionService.addConverter(new StringArrayToStringConverter()); - conversionService.addConverter(new StringArrayToMapConverter()); - return conversionService; } diff --git a/dubbo-config/dubbo-config-spring/src/main/java/org/apache/dubbo/config/spring/beans/factory/annotation/ServiceAnnotationBeanPostProcessor.java b/dubbo-config/dubbo-config-spring/src/main/java/org/apache/dubbo/config/spring/beans/factory/annotation/ServiceAnnotationBeanPostProcessor.java index 37fed800348..bc5339b55dc 100644 --- a/dubbo-config/dubbo-config-spring/src/main/java/org/apache/dubbo/config/spring/beans/factory/annotation/ServiceAnnotationBeanPostProcessor.java +++ b/dubbo-config/dubbo-config-spring/src/main/java/org/apache/dubbo/config/spring/beans/factory/annotation/ServiceAnnotationBeanPostProcessor.java @@ -72,7 +72,6 @@ public class ServiceAnnotationBeanPostProcessor implements BeanDefinitionRegistryPostProcessor, EnvironmentAware, ResourceLoaderAware, BeanClassLoaderAware { - private static final String SEPARATOR = ":"; private final Logger logger = LoggerFactory.getLogger(getClass()); @@ -208,7 +207,7 @@ private BeanNameGenerator resolveBeanNameGenerator(BeanDefinitionRegistry regist * {@link Service} Annotation. * * @param scanner {@link ClassPathBeanDefinitionScanner} - * @param packageToScan package to scan + * @param packageToScan pachage to scan * @param registry {@link BeanDefinitionRegistry} * @return non-null * @since 2.5.8 @@ -262,8 +261,8 @@ private void registerServiceBean(BeanDefinitionHolder beanDefinitionHolder, Bean if (scanner.checkCandidate(beanName, serviceBeanDefinition)) { // check duplicated candidate bean registry.registerBeanDefinition(beanName, serviceBeanDefinition); - if (logger.isWarnEnabled()) { - logger.warn("The BeanDefinition[" + serviceBeanDefinition + + if (logger.isInfoEnabled()) { + logger.info("The BeanDefinition[" + serviceBeanDefinition + "] of ServiceBean has been registered with name : " + beanName); } @@ -290,27 +289,10 @@ private void registerServiceBean(BeanDefinitionHolder beanDefinitionHolder, Bean */ private String generateServiceBeanName(Service service, Class interfaceClass, String annotatedServiceBeanName) { - StringBuilder beanNameBuilder = new StringBuilder(ServiceBean.class.getSimpleName()); - - beanNameBuilder.append(SEPARATOR).append(annotatedServiceBeanName); - - String interfaceClassName = interfaceClass.getName(); - - beanNameBuilder.append(SEPARATOR).append(interfaceClassName); + ServiceBeanNameBuilder builder = ServiceBeanNameBuilder.create(service, interfaceClass, environment); - String version = service.version(); - - if (StringUtils.hasText(version)) { - beanNameBuilder.append(SEPARATOR).append(version); - } - - String group = service.group(); - - if (StringUtils.hasText(group)) { - beanNameBuilder.append(SEPARATOR).append(group); - } - return beanNameBuilder.toString(); + return builder.build(); } @@ -387,7 +369,8 @@ private AbstractBeanDefinition buildServiceBeanDefinition(Service service, Class MutablePropertyValues propertyValues = beanDefinition.getPropertyValues(); - String[] ignoreAttributeNames = of("provider", "monitor", "application", "module", "registry", "protocol", "interface", "interfaceName"); + String[] ignoreAttributeNames = of("provider", "monitor", "application", "module", "registry", "protocol", + "interface", "interfaceName"); propertyValues.addPropertyValues(new AnnotationPropertyValuesAdapter(service, environment, ignoreAttributeNames)); diff --git a/dubbo-config/dubbo-config-spring/src/main/java/org/apache/dubbo/config/spring/beans/factory/annotation/ServiceBeanNameBuilder.java b/dubbo-config/dubbo-config-spring/src/main/java/org/apache/dubbo/config/spring/beans/factory/annotation/ServiceBeanNameBuilder.java new file mode 100644 index 00000000000..6cd712408be --- /dev/null +++ b/dubbo-config/dubbo-config-spring/src/main/java/org/apache/dubbo/config/spring/beans/factory/annotation/ServiceBeanNameBuilder.java @@ -0,0 +1,113 @@ +/* + * 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.spring.beans.factory.annotation; + +import org.apache.dubbo.config.annotation.Reference; +import org.apache.dubbo.config.annotation.Service; +import org.apache.dubbo.config.spring.ReferenceBean; +import org.apache.dubbo.config.spring.ServiceBean; + +import org.springframework.core.env.Environment; +import org.springframework.util.StringUtils; + +import static org.apache.dubbo.config.spring.util.AnnotationUtils.resolveInterfaceName; + + +/** + * Dubbo {@link Service @Service} Bean Builder + * + * @see Service + * @see Reference + * @see ServiceBean + * @see ReferenceBean + * @since 2.6.5 + */ +class ServiceBeanNameBuilder { + + private static final String SEPARATOR = ":"; + + private final String interfaceClassName; + + private final Environment environment; + + // Optional + private String version; + + private String group; + + private ServiceBeanNameBuilder(String interfaceClassName, Environment environment) { + this.interfaceClassName = interfaceClassName; + this.environment = environment; + } + + private ServiceBeanNameBuilder(Class interfaceClass, Environment environment) { + this(interfaceClass.getName(), environment); + } + + private ServiceBeanNameBuilder(Service service, Class interfaceClass, Environment environment) { + this(resolveInterfaceName(service, interfaceClass), environment); + this.group(service.group()); + this.version(service.version()); + } + + private ServiceBeanNameBuilder(Reference reference, Class interfaceClass, Environment environment) { + this(resolveInterfaceName(reference, interfaceClass), environment); + this.group(reference.group()); + this.version(reference.version()); + } + + public static ServiceBeanNameBuilder create(Class interfaceClass, Environment environment) { + return new ServiceBeanNameBuilder(interfaceClass, environment); + } + + public static ServiceBeanNameBuilder create(Service service, Class interfaceClass, Environment environment) { + return new ServiceBeanNameBuilder(service, interfaceClass, environment); + } + + public static ServiceBeanNameBuilder create(Reference reference, Class interfaceClass, Environment environment) { + return new ServiceBeanNameBuilder(reference, interfaceClass, environment); + } + + private static void append(StringBuilder builder, String value) { + if (StringUtils.hasText(value)) { + builder.append(SEPARATOR).append(value); + } + } + + public ServiceBeanNameBuilder group(String group) { + this.group = group; + return this; + } + + public ServiceBeanNameBuilder version(String version) { + this.version = version; + return this; + } + + public String build() { + StringBuilder beanNameBuilder = new StringBuilder("ServiceBean"); + // Required + append(beanNameBuilder, interfaceClassName); + // Optional + append(beanNameBuilder, version); + append(beanNameBuilder, group); + // Build + String rawBeanName = beanNameBuilder.toString(); + // Resolve placeholders + return environment.resolvePlaceholders(rawBeanName); + } +} \ No newline at end of file diff --git a/dubbo-config/dubbo-config-spring/src/main/java/org/apache/dubbo/config/spring/context/annotation/DubboConfigBindingRegistrar.java b/dubbo-config/dubbo-config-spring/src/main/java/org/apache/dubbo/config/spring/context/annotation/DubboConfigBindingRegistrar.java index 52ab0e67129..e797e5585ec 100644 --- a/dubbo-config/dubbo-config-spring/src/main/java/org/apache/dubbo/config/spring/context/annotation/DubboConfigBindingRegistrar.java +++ b/dubbo-config/dubbo-config-spring/src/main/java/org/apache/dubbo/config/spring/context/annotation/DubboConfigBindingRegistrar.java @@ -86,7 +86,7 @@ private void registerDubboConfigBeans(String prefix, boolean multiple, BeanDefinitionRegistry registry) { - Map properties = getSubProperties(environment.getPropertySources(), prefix); + Map properties = getSubProperties(environment.getPropertySources(), prefix); if (CollectionUtils.isEmpty(properties)) { if (log.isDebugEnabled()) { @@ -158,7 +158,7 @@ public void setEnvironment(Environment environment) { } - private Set resolveMultipleBeanNames(Map properties) { + private Set resolveMultipleBeanNames(Map properties) { Set beanNames = new LinkedHashSet(); @@ -179,10 +179,10 @@ private Set resolveMultipleBeanNames(Map properties) { } - private String resolveSingleBeanName(Map properties, Class configClass, + private String resolveSingleBeanName(Map properties, Class configClass, BeanDefinitionRegistry registry) { - String beanName = properties.get("id"); + String beanName = (String) properties.get("id"); if (!StringUtils.hasText(beanName)) { BeanDefinitionBuilder builder = rootBeanDefinition(configClass); diff --git a/dubbo-config/dubbo-config-spring/src/main/java/org/apache/dubbo/config/spring/context/annotation/DubboConfigConfiguration.java b/dubbo-config/dubbo-config-spring/src/main/java/org/apache/dubbo/config/spring/context/annotation/DubboConfigConfiguration.java index 392a5732aef..3c5a43f0227 100644 --- a/dubbo-config/dubbo-config-spring/src/main/java/org/apache/dubbo/config/spring/context/annotation/DubboConfigConfiguration.java +++ b/dubbo-config/dubbo-config-spring/src/main/java/org/apache/dubbo/config/spring/context/annotation/DubboConfigConfiguration.java @@ -25,7 +25,6 @@ import org.apache.dubbo.config.ProtocolConfig; import org.apache.dubbo.config.ProviderConfig; import org.apache.dubbo.config.RegistryConfig; -import org.apache.dubbo.config.RegistryDataConfig; import org.apache.dubbo.config.spring.ConfigCenterBean; import org.springframework.context.annotation.Configuration; @@ -60,7 +59,6 @@ public class DubboConfigConfiguration { @EnableDubboConfigBinding(prefix = "dubbo.provider", type = ProviderConfig.class), @EnableDubboConfigBinding(prefix = "dubbo.consumer", type = ConsumerConfig.class), @EnableDubboConfigBinding(prefix = "dubbo.config-center", type = ConfigCenterBean.class), - @EnableDubboConfigBinding(prefix = "dubbo.registry-data", type = RegistryDataConfig.class), @EnableDubboConfigBinding(prefix = "dubbo.metadata-report", type = MetadataReportConfig.class) }) public static class Single { @@ -78,7 +76,8 @@ public static class Single { @EnableDubboConfigBinding(prefix = "dubbo.monitors", type = MonitorConfig.class, multiple = true), @EnableDubboConfigBinding(prefix = "dubbo.providers", type = ProviderConfig.class, multiple = true), @EnableDubboConfigBinding(prefix = "dubbo.consumers", type = ConsumerConfig.class, multiple = true), - @EnableDubboConfigBinding(prefix = "dubbo.config-centers", type = ConfigCenterBean.class, multiple = true) + @EnableDubboConfigBinding(prefix = "dubbo.config-centers", type = ConfigCenterBean.class, multiple = true), + @EnableDubboConfigBinding(prefix = "dubbo.metadata-reports", type = MetadataReportConfig.class, multiple = true) }) public static class Multiple { diff --git a/dubbo-config/dubbo-config-spring/src/main/java/org/apache/dubbo/config/spring/context/annotation/DubboConfigConfigurationSelector.java b/dubbo-config/dubbo-config-spring/src/main/java/org/apache/dubbo/config/spring/context/annotation/DubboConfigConfigurationRegistrar.java similarity index 66% rename from dubbo-config/dubbo-config-spring/src/main/java/org/apache/dubbo/config/spring/context/annotation/DubboConfigConfigurationSelector.java rename to dubbo-config/dubbo-config-spring/src/main/java/org/apache/dubbo/config/spring/context/annotation/DubboConfigConfigurationRegistrar.java index 639ad971b4d..cc5f4f8c722 100644 --- a/dubbo-config/dubbo-config-spring/src/main/java/org/apache/dubbo/config/spring/context/annotation/DubboConfigConfigurationSelector.java +++ b/dubbo-config/dubbo-config-spring/src/main/java/org/apache/dubbo/config/spring/context/annotation/DubboConfigConfigurationRegistrar.java @@ -18,22 +18,26 @@ import org.apache.dubbo.config.AbstractConfig; -import org.springframework.context.annotation.ImportSelector; +import org.springframework.beans.factory.support.BeanDefinitionRegistry; +import org.springframework.context.annotation.ImportBeanDefinitionRegistrar; import org.springframework.core.Ordered; import org.springframework.core.annotation.AnnotationAttributes; import org.springframework.core.type.AnnotationMetadata; +import static org.apache.dubbo.config.spring.util.AnnotatedBeanDefinitionRegistryUtils.registerBeans; + /** - * Dubbo {@link AbstractConfig Config} Registrar + * Dubbo {@link AbstractConfig Config} {@link ImportBeanDefinitionRegistrar register}, which order can be configured * * @see EnableDubboConfig * @see DubboConfigConfiguration + * @see Ordered * @since 2.5.8 */ -public class DubboConfigConfigurationSelector implements ImportSelector, Ordered { +public class DubboConfigConfigurationRegistrar implements ImportBeanDefinitionRegistrar { @Override - public String[] selectImports(AnnotationMetadata importingClassMetadata) { + public void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry) { AnnotationAttributes attributes = AnnotationAttributes.fromMap( importingClassMetadata.getAnnotationAttributes(EnableDubboConfig.class.getName())); @@ -41,20 +45,10 @@ public String[] selectImports(AnnotationMetadata importingClassMetadata) { boolean multiple = attributes.getBoolean("multiple"); if (multiple) { - return of(DubboConfigConfiguration.Multiple.class.getName()); + registerBeans(registry, DubboConfigConfiguration.Multiple.class); } else { - return of(DubboConfigConfiguration.Single.class.getName()); + registerBeans(registry, DubboConfigConfiguration.Single.class); } } - private static T[] of(T... values) { - return values; - } - - @Override - public int getOrder() { - return HIGHEST_PRECEDENCE; - } - - } diff --git a/dubbo-config/dubbo-config-spring/src/main/java/org/apache/dubbo/config/spring/context/annotation/EnableDubboConfig.java b/dubbo-config/dubbo-config-spring/src/main/java/org/apache/dubbo/config/spring/context/annotation/EnableDubboConfig.java index 889e39078b0..47bafa53b54 100644 --- a/dubbo-config/dubbo-config-spring/src/main/java/org/apache/dubbo/config/spring/context/annotation/EnableDubboConfig.java +++ b/dubbo-config/dubbo-config-spring/src/main/java/org/apache/dubbo/config/spring/context/annotation/EnableDubboConfig.java @@ -66,7 +66,7 @@ @Retention(RetentionPolicy.RUNTIME) @Inherited @Documented -@Import(DubboConfigConfigurationSelector.class) +@Import(DubboConfigConfigurationRegistrar.class) public @interface EnableDubboConfig { /** diff --git a/dubbo-config/dubbo-config-spring/src/main/java/org/apache/dubbo/config/spring/context/annotation/EnableDubboConfigBinding.java b/dubbo-config/dubbo-config-spring/src/main/java/org/apache/dubbo/config/spring/context/annotation/EnableDubboConfigBinding.java index 8b50f367286..54fc3373eac 100644 --- a/dubbo-config/dubbo-config-spring/src/main/java/org/apache/dubbo/config/spring/context/annotation/EnableDubboConfigBinding.java +++ b/dubbo-config/dubbo-config-spring/src/main/java/org/apache/dubbo/config/spring/context/annotation/EnableDubboConfigBinding.java @@ -27,6 +27,7 @@ import java.lang.annotation.Documented; import java.lang.annotation.ElementType; +import java.lang.annotation.Repeatable; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.lang.annotation.Target; @@ -48,6 +49,7 @@ @Target({ElementType.TYPE, ElementType.ANNOTATION_TYPE}) @Retention(RetentionPolicy.RUNTIME) @Documented +@Repeatable(EnableDubboConfigBindings.class) @Import(DubboConfigBindingRegistrar.class) public @interface EnableDubboConfigBinding { diff --git a/dubbo-config/dubbo-config-spring/src/main/java/org/apache/dubbo/config/spring/context/event/ServiceBeanExportedEvent.java b/dubbo-config/dubbo-config-spring/src/main/java/org/apache/dubbo/config/spring/context/event/ServiceBeanExportedEvent.java new file mode 100644 index 00000000000..93c950dfcde --- /dev/null +++ b/dubbo-config/dubbo-config-spring/src/main/java/org/apache/dubbo/config/spring/context/event/ServiceBeanExportedEvent.java @@ -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.config.spring.context.event; + +import org.apache.dubbo.config.spring.ServiceBean; + +import org.springframework.context.ApplicationEvent; +import org.springframework.context.ApplicationListener; + +/** + * A {@link ApplicationEvent} after {@link ServiceBean} {@link ServiceBean#export() export} invocation + * + * @see ApplicationEvent + * @see ApplicationListener + * @see ServiceBean + * @since 2.6.5 + */ +public class ServiceBeanExportedEvent extends ApplicationEvent { + + /** + * Create a new ApplicationEvent. + * + * @param serviceBean {@link ServiceBean} bean + */ + public ServiceBeanExportedEvent(ServiceBean serviceBean) { + super(serviceBean); + } + + /** + * Get {@link ServiceBean} instance + * + * @return non-null + */ + public ServiceBean getServiceBean() { + return (ServiceBean) super.getSource(); + } +} diff --git a/dubbo-config/dubbo-config-spring/src/main/java/org/apache/dubbo/config/spring/context/properties/DefaultDubboConfigBinder.java b/dubbo-config/dubbo-config-spring/src/main/java/org/apache/dubbo/config/spring/context/properties/DefaultDubboConfigBinder.java index e1d44da8f7f..ca10d3eb537 100644 --- a/dubbo-config/dubbo-config-spring/src/main/java/org/apache/dubbo/config/spring/context/properties/DefaultDubboConfigBinder.java +++ b/dubbo-config/dubbo-config-spring/src/main/java/org/apache/dubbo/config/spring/context/properties/DefaultDubboConfigBinder.java @@ -37,7 +37,7 @@ public void bind(String prefix, C dubboConfig) { dataBinder.setIgnoreInvalidFields(isIgnoreInvalidFields()); dataBinder.setIgnoreUnknownFields(isIgnoreUnknownFields()); // Get properties under specified prefix from PropertySources - Map properties = getSubProperties(getPropertySources(), prefix); + Map properties = getSubProperties(getPropertySources(), prefix); // Convert Map to MutablePropertyValues MutablePropertyValues propertyValues = new MutablePropertyValues(properties); // Bind @@ -45,3 +45,4 @@ public void bind(String prefix, C dubboConfig) { } } + diff --git a/dubbo-config/dubbo-config-spring/src/main/java/org/apache/dubbo/config/spring/schema/AnnotationBeanDefinitionParser.java b/dubbo-config/dubbo-config-spring/src/main/java/org/apache/dubbo/config/spring/schema/AnnotationBeanDefinitionParser.java index 918c916f3c8..4a8e963c111 100644 --- a/dubbo-config/dubbo-config-spring/src/main/java/org/apache/dubbo/config/spring/schema/AnnotationBeanDefinitionParser.java +++ b/dubbo-config/dubbo-config-spring/src/main/java/org/apache/dubbo/config/spring/schema/AnnotationBeanDefinitionParser.java @@ -16,7 +16,6 @@ */ package org.apache.dubbo.config.spring.schema; -import org.apache.dubbo.config.spring.AnnotationBean; import org.apache.dubbo.config.spring.beans.factory.annotation.ReferenceAnnotationBeanPostProcessor; import org.apache.dubbo.config.spring.beans.factory.annotation.ServiceAnnotationBeanPostProcessor; import org.apache.dubbo.config.spring.util.BeanRegistrar; @@ -26,7 +25,6 @@ import org.springframework.beans.factory.support.BeanDefinitionBuilder; import org.springframework.beans.factory.support.BeanDefinitionRegistry; import org.springframework.beans.factory.xml.AbstractSingleBeanDefinitionParser; -import org.springframework.beans.factory.xml.BeanDefinitionParser; import org.springframework.beans.factory.xml.ParserContext; import org.w3c.dom.Element; @@ -34,7 +32,7 @@ import static org.springframework.util.StringUtils.trimArrayElements; /** - * {@link AnnotationBean} {@link BeanDefinitionParser} + * @link BeanDefinitionParser} * * @see ServiceAnnotationBeanPostProcessor * @see ReferenceAnnotationBeanPostProcessor diff --git a/dubbo-config/dubbo-config-spring/src/main/java/org/apache/dubbo/config/spring/schema/DubboBeanDefinitionParser.java b/dubbo-config/dubbo-config-spring/src/main/java/org/apache/dubbo/config/spring/schema/DubboBeanDefinitionParser.java index a2f5499258b..9272b7f5a1b 100644 --- a/dubbo-config/dubbo-config-spring/src/main/java/org/apache/dubbo/config/spring/schema/DubboBeanDefinitionParser.java +++ b/dubbo-config/dubbo-config-spring/src/main/java/org/apache/dubbo/config/spring/schema/DubboBeanDefinitionParser.java @@ -165,7 +165,7 @@ private static BeanDefinition parse(Element element, ParserContext parserContext RegistryConfig registryConfig = new RegistryConfig(); registryConfig.setAddress(RegistryConfig.NO_AVAILABLE); beanDefinition.getPropertyValues().addPropertyValue(beanProperty, registryConfig); - } else if ("provider".equals(property) || "protocol".equals(property) || "registry".equals(property)) { + } else if ("provider".equals(property) || "registry".equals(property) || ("protocol".equals(property) && ServiceBean.class.equals(beanClass))) { /** * For 'provider' 'protocol' 'registry', keep literal value (should be id/name) and set the value to 'registryIds' 'providerIds' protocolIds' * The following process should make sure each id refers to the corresponding instance, here's how to find the instance for different use cases: diff --git a/dubbo-config/dubbo-config-spring/src/main/java/org/apache/dubbo/config/spring/schema/DubboNamespaceHandler.java b/dubbo-config/dubbo-config-spring/src/main/java/org/apache/dubbo/config/spring/schema/DubboNamespaceHandler.java index d4ea6ed33c8..4d7b0af461e 100644 --- a/dubbo-config/dubbo-config-spring/src/main/java/org/apache/dubbo/config/spring/schema/DubboNamespaceHandler.java +++ b/dubbo-config/dubbo-config-spring/src/main/java/org/apache/dubbo/config/spring/schema/DubboNamespaceHandler.java @@ -19,6 +19,7 @@ import org.apache.dubbo.common.Version; import org.apache.dubbo.config.ApplicationConfig; import org.apache.dubbo.config.ConsumerConfig; +import org.apache.dubbo.config.MetadataReportConfig; import org.apache.dubbo.config.ModuleConfig; import org.apache.dubbo.config.MonitorConfig; import org.apache.dubbo.config.ProtocolConfig; @@ -47,6 +48,7 @@ public void init() { registerBeanDefinitionParser("module", new DubboBeanDefinitionParser(ModuleConfig.class, true)); registerBeanDefinitionParser("registry", new DubboBeanDefinitionParser(RegistryConfig.class, true)); registerBeanDefinitionParser("config-center", new DubboBeanDefinitionParser(ConfigCenterBean.class, true)); + registerBeanDefinitionParser("metadata-report", new DubboBeanDefinitionParser(MetadataReportConfig.class, true)); registerBeanDefinitionParser("monitor", new DubboBeanDefinitionParser(MonitorConfig.class, true)); registerBeanDefinitionParser("provider", new DubboBeanDefinitionParser(ProviderConfig.class, true)); registerBeanDefinitionParser("consumer", new DubboBeanDefinitionParser(ConsumerConfig.class, true)); diff --git a/dubbo-config/dubbo-config-spring/src/main/java/org/apache/dubbo/config/spring/status/DataSourceStatusChecker.java b/dubbo-config/dubbo-config-spring/src/main/java/org/apache/dubbo/config/spring/status/DataSourceStatusChecker.java index b777f63f23e..3fba654c9db 100644 --- a/dubbo-config/dubbo-config-spring/src/main/java/org/apache/dubbo/config/spring/status/DataSourceStatusChecker.java +++ b/dubbo-config/dubbo-config-spring/src/main/java/org/apache/dubbo/config/spring/status/DataSourceStatusChecker.java @@ -67,27 +67,20 @@ public Status check() { buf.append(", "); } buf.append(entry.getKey()); - try { - Connection connection = dataSource.getConnection(); - try { - DatabaseMetaData metaData = connection.getMetaData(); - ResultSet resultSet = metaData.getTypeInfo(); - try { - if (!resultSet.next()) { - level = Status.Level.ERROR; - } - } finally { - resultSet.close(); + + try (Connection connection = dataSource.getConnection()) { + DatabaseMetaData metaData = connection.getMetaData(); + try (ResultSet resultSet = metaData.getTypeInfo()) { + if (!resultSet.next()) { + level = Status.Level.ERROR; } - buf.append(metaData.getURL()); - buf.append("("); - buf.append(metaData.getDatabaseProductName()); - buf.append("-"); - buf.append(metaData.getDatabaseProductVersion()); - buf.append(")"); - } finally { - connection.close(); } + buf.append(metaData.getURL()); + buf.append("("); + buf.append(metaData.getDatabaseProductName()); + buf.append("-"); + buf.append(metaData.getDatabaseProductVersion()); + buf.append(")"); } catch (Throwable e) { logger.warn(e.getMessage(), e); return new Status(level, e.getMessage()); diff --git a/dubbo-config/dubbo-config-spring/src/main/java/org/apache/dubbo/config/spring/util/AnnotatedBeanDefinitionRegistryUtils.java b/dubbo-config/dubbo-config-spring/src/main/java/org/apache/dubbo/config/spring/util/AnnotatedBeanDefinitionRegistryUtils.java new file mode 100644 index 00000000000..bf065f8b085 --- /dev/null +++ b/dubbo-config/dubbo-config-spring/src/main/java/org/apache/dubbo/config/spring/util/AnnotatedBeanDefinitionRegistryUtils.java @@ -0,0 +1,62 @@ +/* + * 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.spring.util; + +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; +import org.springframework.beans.factory.config.BeanDefinition; +import org.springframework.beans.factory.support.BeanDefinitionRegistry; +import org.springframework.context.annotation.AnnotatedBeanDefinitionReader; +import org.springframework.util.ObjectUtils; + +import java.lang.annotation.Annotation; +import java.util.Arrays; + +/** + * Annotated {@link BeanDefinition} Utilities + *

+ * The source code is cloned from https://github.com/alibaba/spring-context-support/blob/1.0.2/src/main/java/com/alibaba/spring/util/AnnotatedBeanDefinitionRegistryUtils.java + * @since 2.6.6 + */ +public abstract class AnnotatedBeanDefinitionRegistryUtils { + + private static final Log logger = LogFactory.getLog(AnnotatedBeanDefinitionRegistryUtils.class); + + /** + * Register Beans + * + * @param registry {@link BeanDefinitionRegistry} + * @param annotatedClasses {@link Annotation annotation} class + */ + public static void registerBeans(BeanDefinitionRegistry registry, Class... annotatedClasses) { + + if (ObjectUtils.isEmpty(annotatedClasses)) { + return; + } + + boolean debugEnabled = logger.isDebugEnabled(); + + AnnotatedBeanDefinitionReader reader = new AnnotatedBeanDefinitionReader(registry); + + if (debugEnabled) { + logger.debug(registry.getClass().getSimpleName() + " will register annotated classes : " + Arrays.asList(annotatedClasses) + " ."); + } + + reader.register(annotatedClasses); + + } +} diff --git a/dubbo-config/dubbo-config-spring/src/main/java/org/apache/dubbo/config/spring/util/AnnotationUtils.java b/dubbo-config/dubbo-config-spring/src/main/java/org/apache/dubbo/config/spring/util/AnnotationUtils.java index 70c04ccb436..ed2a607bffe 100644 --- a/dubbo-config/dubbo-config-spring/src/main/java/org/apache/dubbo/config/spring/util/AnnotationUtils.java +++ b/dubbo-config/dubbo-config-spring/src/main/java/org/apache/dubbo/config/spring/util/AnnotationUtils.java @@ -16,20 +16,34 @@ */ package org.apache.dubbo.config.spring.util; +import org.apache.dubbo.config.annotation.Reference; +import org.apache.dubbo.config.annotation.Service; + +import org.springframework.core.env.Environment; import org.springframework.core.env.PropertyResolver; +import org.springframework.util.StringUtils; import java.lang.annotation.Annotation; +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; +import java.lang.reflect.Method; +import java.util.Collections; import java.util.HashSet; import java.util.LinkedHashMap; +import java.util.LinkedList; +import java.util.List; import java.util.Map; import java.util.Set; import static java.lang.String.valueOf; +import static org.springframework.core.annotation.AnnotationUtils.findAnnotation; import static org.springframework.core.annotation.AnnotationUtils.getAnnotationAttributes; import static org.springframework.core.annotation.AnnotationUtils.getDefaultValue; import static org.springframework.util.CollectionUtils.arrayToList; import static org.springframework.util.ObjectUtils.nullSafeEquals; -import static org.springframework.util.StringUtils.trimAllWhitespace; +import static org.springframework.util.StringUtils.trimWhitespace; /** * Annotation Utilities Class @@ -39,13 +53,186 @@ */ public class AnnotationUtils { + public static String resolveInterfaceName(Service service, Class defaultInterfaceClass) + throws IllegalStateException { + + String interfaceName; + if (StringUtils.hasText(service.interfaceName())) { + interfaceName = service.interfaceName(); + } else if (!void.class.equals(service.interfaceClass())) { + interfaceName = service.interfaceClass().getName(); + } else if (defaultInterfaceClass.isInterface()) { + interfaceName = defaultInterfaceClass.getName(); + } else { + throw new IllegalStateException( + "The @Service undefined interfaceClass or interfaceName, and the type " + + defaultInterfaceClass.getName() + " is not a interface."); + } + + return interfaceName; + + } + + public static String resolveInterfaceName(Reference reference, Class defaultInterfaceClass) + throws IllegalStateException { + + String interfaceName; + if (!"".equals(reference.interfaceName())) { + interfaceName = reference.interfaceName(); + } else if (!void.class.equals(reference.interfaceClass())) { + interfaceName = reference.interfaceClass().getName(); + } else if (defaultInterfaceClass.isInterface()) { + interfaceName = defaultInterfaceClass.getName(); + } else { + throw new IllegalStateException( + "The @Reference undefined interfaceClass or interfaceName, and the type " + + defaultInterfaceClass.getName() + " is not a interface."); + } + + return interfaceName; + + } + + + // Cloned from https://github.com/alibaba/spring-context-support/blob/1.0.2/src/main/java/com/alibaba/spring/util/AnnotationUtils.java + /** - * Get {@link Annotation} attributes + * Is specified {@link Annotation} present on {@link Method}'s declaring class or parameters or itself. * - * @param annotation - * @param propertyResolver - * @param ignoreDefaultValue + * @param method {@link Method} + * @param annotationClass {@link Annotation} type + * @param {@link Annotation} type + * @return If present , return true , or false + * @since 2.6.6 + */ + public static boolean isPresent(Method method, Class annotationClass) { + + Map> annotationsMap = findAnnotations(method, annotationClass); + + return !annotationsMap.isEmpty(); + + } + + /** + * Find specified {@link Annotation} type maps from {@link Method} + * + * @param method {@link Method} + * @param annotationClass {@link Annotation} type + * @param {@link Annotation} type + * @return {@link Annotation} type maps , the {@link ElementType} as key , + * the list of {@link Annotation} as value. + * If {@link Annotation} was annotated on {@link Method}'s parameters{@link ElementType#PARAMETER} , + * the associated {@link Annotation} list may contain multiple elements. + * @since 2.6.6 + */ + public static Map> findAnnotations(Method method, + Class annotationClass) { + + Retention retention = annotationClass.getAnnotation(Retention.class); + + RetentionPolicy retentionPolicy = retention.value(); + + if (!RetentionPolicy.RUNTIME.equals(retentionPolicy)) { + return Collections.emptyMap(); + } + + Map> annotationsMap = new LinkedHashMap>(); + + Target target = annotationClass.getAnnotation(Target.class); + + ElementType[] elementTypes = target.value(); + + + for (ElementType elementType : elementTypes) { + + List annotationsList = new LinkedList(); + + switch (elementType) { + + case PARAMETER: + + Annotation[][] parameterAnnotations = method.getParameterAnnotations(); + + for (Annotation[] annotations : parameterAnnotations) { + + for (Annotation annotation : annotations) { + + if (annotationClass.equals(annotation.annotationType())) { + + annotationsList.add((A) annotation); + + } + + } + + } + + break; + + case METHOD: + + A annotation = findAnnotation(method, annotationClass); + + if (annotation != null) { + + annotationsList.add(annotation); + + } + + break; + + case TYPE: + + Class beanType = method.getDeclaringClass(); + + A annotation2 = findAnnotation(beanType, annotationClass); + + if (annotation2 != null) { + + annotationsList.add(annotation2); + + } + + break; + + } + + if (!annotationsList.isEmpty()) { + + annotationsMap.put(elementType, annotationsList); + + } + + + } + + return Collections.unmodifiableMap(annotationsMap); + + } + + /** + * Get the {@link Annotation} attributes + * + * @param annotation specified {@link Annotation} + * @param ignoreDefaultValue whether ignore default value or not + * @param ignoreAttributeNames the attribute names of annotation should be ignored * @return non-null + * @since 2.6.6 + */ + public static Map getAttributes(Annotation annotation, boolean ignoreDefaultValue, + String... ignoreAttributeNames) { + return getAttributes(annotation, null, ignoreDefaultValue, ignoreAttributeNames); + } + + /** + * Get the {@link Annotation} attributes + * + * @param annotation specified {@link Annotation} + * @param propertyResolver {@link PropertyResolver} instance, e.g {@link Environment} + * @param ignoreDefaultValue whether ignore default value or not + * @param ignoreAttributeNames the attribute names of annotation should be ignored + * @return non-null + * @since 2.6.6 */ public static Map getAttributes(Annotation annotation, PropertyResolver propertyResolver, boolean ignoreDefaultValue, String... ignoreAttributeNames) { @@ -56,8 +243,6 @@ public static Map getAttributes(Annotation annotation, PropertyR Map actualAttributes = new LinkedHashMap(); - boolean requiredResolve = propertyResolver != null; - for (Map.Entry entry : attributes.entrySet()) { String attributeName = entry.getKey(); @@ -73,17 +258,27 @@ public static Map getAttributes(Annotation annotation, PropertyR continue; } - if (requiredResolve && attributeValue instanceof String) { // Resolve Placeholder - String resolvedValue = propertyResolver.resolvePlaceholders(valueOf(attributeValue)); - attributeValue = trimAllWhitespace(resolvedValue); + if (attributeValue instanceof String) { + attributeValue = resolvePlaceholders(valueOf(attributeValue), propertyResolver); + } else if (attributeValue instanceof String[]) { + String[] values = (String[]) attributeValue; + for (int i = 0; i < values.length; i++) { + values[i] = resolvePlaceholders(values[i], propertyResolver); + } + attributeValue = values; } - actualAttributes.put(attributeName, attributeValue); - } - return actualAttributes; + } + private static String resolvePlaceholders(String attributeValue, PropertyResolver propertyResolver) { + String resolvedValue = attributeValue; + if (propertyResolver != null) { + resolvedValue = propertyResolver.resolvePlaceholders(resolvedValue); + resolvedValue = trimWhitespace(resolvedValue); + } + return resolvedValue; } -} +} \ No newline at end of file diff --git a/dubbo-config/dubbo-config-spring/src/main/java/org/apache/dubbo/config/spring/util/BeanFactoryUtils.java b/dubbo-config/dubbo-config-spring/src/main/java/org/apache/dubbo/config/spring/util/BeanFactoryUtils.java index e519cdee280..71fb7676f88 100644 --- a/dubbo-config/dubbo-config-spring/src/main/java/org/apache/dubbo/config/spring/util/BeanFactoryUtils.java +++ b/dubbo-config/dubbo-config-spring/src/main/java/org/apache/dubbo/config/spring/util/BeanFactoryUtils.java @@ -16,8 +16,6 @@ */ package org.apache.dubbo.config.spring.util; -import org.apache.dubbo.common.utils.StringUtils; - import org.springframework.beans.factory.BeanFactory; import org.springframework.beans.factory.ListableBeanFactory; import org.springframework.beans.factory.config.ConfigurableBeanFactory; @@ -33,6 +31,7 @@ import static org.springframework.beans.factory.BeanFactoryUtils.beanNamesForTypeIncludingAncestors; import static org.springframework.beans.factory.BeanFactoryUtils.beansOfTypeIncludingAncestors; +import static org.springframework.util.ObjectUtils.containsElement; /** * {@link BeanFactory} Utilities class @@ -44,6 +43,29 @@ */ public class BeanFactoryUtils { + public static boolean addApplicationListener(ApplicationContext applicationContext, ApplicationListener listener) { + try { + // backward compatibility to spring 2.0.1 + Method method = applicationContext.getClass().getMethod("addApplicationListener", ApplicationListener.class); + method.invoke(applicationContext, listener); + return true; + } catch (Throwable t) { + if (applicationContext instanceof AbstractApplicationContext) { + try { + // backward compatibility to spring 2.0.1 + Method method = AbstractApplicationContext.class.getDeclaredMethod("addListener", ApplicationListener.class); + if (!method.isAccessible()) { + method.setAccessible(true); + } + method.invoke(applicationContext, listener); + return true; + } catch (Throwable t2) { + // ignore + } + } + } + return false; + } /** * Get optional Bean @@ -53,12 +75,13 @@ public class BeanFactoryUtils { * @param beanType the {@link Class type} of Bean * @param the {@link Class type} of Bean * @return A bean if present , or null + * @since 2.6.6 */ public static T getOptionalBean(ListableBeanFactory beanFactory, String beanName, Class beanType) { String[] allBeanNames = beanNamesForTypeIncludingAncestors(beanFactory, beanType); - if (!StringUtils.isContains(allBeanNames, beanName)) { + if (!containsElement(allBeanNames, beanName)) { return null; } @@ -76,7 +99,8 @@ public static T getOptionalBean(ListableBeanFactory beanFactory, String bean * @param beanNames the names of Bean * @param beanType the {@link Class type} of Bean * @param the {@link Class type} of Bean - * @return + * @return the read-only and non-null {@link List} of Bean names + * @since 2.6.6 */ public static List getBeans(ListableBeanFactory beanFactory, String[] beanNames, Class beanType) { @@ -85,36 +109,11 @@ public static List getBeans(ListableBeanFactory beanFactory, String[] bea List beans = new ArrayList(beanNames.length); for (String beanName : beanNames) { - if (StringUtils.isContains(allBeanNames, beanName)) { + if (containsElement(allBeanNames, beanName)) { beans.add(beanFactory.getBean(beanName, beanType)); } } return Collections.unmodifiableList(beans); - - } - - public static boolean addApplicationListener(ApplicationContext applicationContext, ApplicationListener listener) { - try { - // backward compatibility to spring 2.0.1 - Method method = applicationContext.getClass().getMethod("addApplicationListener", ApplicationListener.class); - method.invoke(applicationContext, listener); - return true; - } catch (Throwable t) { - if (applicationContext instanceof AbstractApplicationContext) { - try { - // backward compatibility to spring 2.0.1 - Method method = AbstractApplicationContext.class.getDeclaredMethod("addListener", ApplicationListener.class); - if (!method.isAccessible()) { - method.setAccessible(true); - } - method.invoke(applicationContext, listener); - return true; - } catch (Throwable t2) { - // ignore - } - } - } - return false; } } diff --git a/dubbo-config/dubbo-config-spring/src/main/java/org/apache/dubbo/config/spring/util/ClassUtils.java b/dubbo-config/dubbo-config-spring/src/main/java/org/apache/dubbo/config/spring/util/ClassUtils.java new file mode 100644 index 00000000000..29cd6378748 --- /dev/null +++ b/dubbo-config/dubbo-config-spring/src/main/java/org/apache/dubbo/config/spring/util/ClassUtils.java @@ -0,0 +1,37 @@ +/* + * 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.spring.util; + +import java.lang.reflect.ParameterizedType; +import java.lang.reflect.Type; + +/** + * {@link Class} Utilities + *

+ * The source code is cloned from + * https://github.com/alibaba/spring-context-support/blob/1.0.2/src/main/java/com/alibaba/spring/util/ClassUtils.java + * + * @since 2.6.6 + */ +public abstract class ClassUtils { + + public static Class resolveGenericType(Class declaredClass) { + ParameterizedType parameterizedType = (ParameterizedType) declaredClass.getGenericSuperclass(); + Type[] actualTypeArguments = parameterizedType.getActualTypeArguments(); + return (Class) actualTypeArguments[0]; + } +} diff --git a/dubbo-config/dubbo-config-spring/src/main/java/org/apache/dubbo/config/spring/util/ObjectUtils.java b/dubbo-config/dubbo-config-spring/src/main/java/org/apache/dubbo/config/spring/util/ObjectUtils.java index 0ffd7a77a5d..57832cc926b 100644 --- a/dubbo-config/dubbo-config-spring/src/main/java/org/apache/dubbo/config/spring/util/ObjectUtils.java +++ b/dubbo-config/dubbo-config-spring/src/main/java/org/apache/dubbo/config/spring/util/ObjectUtils.java @@ -17,18 +17,18 @@ package org.apache.dubbo.config.spring.util; /** - * Object Utilities Class + * Object Utilities * - * @since 2.5.11 + * @since 2.6.6 */ -public class ObjectUtils { +public abstract class ObjectUtils { /** - * of factory method + * Convert from variable arguments to array * - * @param values - * @param - * @return + * @param values variable arguments + * @param The class + * @return array */ public static T[] of(T... values) { return values; diff --git a/dubbo-config/dubbo-config-spring/src/main/java/org/apache/dubbo/config/spring/util/PropertySourcesUtils.java b/dubbo-config/dubbo-config-spring/src/main/java/org/apache/dubbo/config/spring/util/PropertySourcesUtils.java index 28d43fc2179..8a070579b34 100644 --- a/dubbo-config/dubbo-config-spring/src/main/java/org/apache/dubbo/config/spring/util/PropertySourcesUtils.java +++ b/dubbo-config/dubbo-config-spring/src/main/java/org/apache/dubbo/config/spring/util/PropertySourcesUtils.java @@ -16,20 +16,25 @@ */ package org.apache.dubbo.config.spring.util; +import org.springframework.core.env.AbstractEnvironment; +import org.springframework.core.env.ConfigurableEnvironment; import org.springframework.core.env.EnumerablePropertySource; +import org.springframework.core.env.MutablePropertySources; import org.springframework.core.env.PropertySource; import org.springframework.core.env.PropertySources; -import org.springframework.core.env.PropertySourcesPropertyResolver; +import java.util.Collections; import java.util.LinkedHashMap; import java.util.Map; import java.util.Properties; + /** * {@link PropertySources} Utilities + *

+ * The source code is cloned from https://github.com/alibaba/spring-context-support/blob/1.0.2/src/main/java/com/alibaba/spring/util/PropertySourcesUtils.java * - * @see PropertySources - * @since 2.5.8 + * @since 2.6.6 */ public abstract class PropertySourcesUtils { @@ -38,30 +43,60 @@ public abstract class PropertySourcesUtils { * * @param propertySources {@link PropertySource} Iterable * @param prefix the prefix of property name - * @return Map + * @return Map * @see Properties */ - public static Map getSubProperties(Iterable> propertySources, String prefix) { + public static Map getSubProperties(Iterable> propertySources, String prefix) { - Map subProperties = new LinkedHashMap(); + // Non-Extension AbstractEnvironment + AbstractEnvironment environment = new AbstractEnvironment() { + }; - String normalizedPrefix = normalizePrefix(prefix); + MutablePropertySources mutablePropertySources = environment.getPropertySources(); + + for (PropertySource source : propertySources) { + mutablePropertySources.addLast(source); + } + + return getSubProperties(environment, prefix); + + } + + /** + * Get Sub {@link Properties} + * + * @param environment {@link ConfigurableEnvironment} + * @param prefix the prefix of property name + * @return Map + * @see Properties + */ + public static Map getSubProperties(ConfigurableEnvironment environment, String prefix) { - PropertySourcesPropertyResolver propertyResolver = new PropertySourcesPropertyResolver((PropertySources) propertySources); + Map subProperties = new LinkedHashMap(); + + MutablePropertySources propertySources = environment.getPropertySources(); + + String normalizedPrefix = normalizePrefix(prefix); for (PropertySource source : propertySources) { if (source instanceof EnumerablePropertySource) { for (String name : ((EnumerablePropertySource) source).getPropertyNames()) { - if (name.startsWith(normalizedPrefix)) { + if (!subProperties.containsKey(name) && name.startsWith(normalizedPrefix)) { String subName = name.substring(normalizedPrefix.length()); - String value = propertyResolver.getProperty(name); - subProperties.putIfAbsent(subName, value); + if (!subProperties.containsKey(subName)) { // take first one + Object value = source.getProperty(name); + if (value instanceof String) { + // Resolve placeholder + value = environment.resolvePlaceholders((String) value); + } + subProperties.put(subName, value); + } } } } } - return subProperties; + return Collections.unmodifiableMap(subProperties); } @@ -74,5 +109,4 @@ public static Map getSubProperties(Iterable> p public static String normalizePrefix(String prefix) { return prefix.endsWith(".") ? prefix : prefix + "."; } - } diff --git a/dubbo-config/dubbo-config-spring/src/main/resources/META-INF/compat/dubbo.xsd b/dubbo-config/dubbo-config-spring/src/main/resources/META-INF/compat/dubbo.xsd index e3253e41114..4f0b1bf7a16 100644 --- a/dubbo-config/dubbo-config-spring/src/main/resources/META-INF/compat/dubbo.xsd +++ b/dubbo-config/dubbo-config-spring/src/main/resources/META-INF/compat/dubbo.xsd @@ -565,16 +565,16 @@ - - - - - - - - - - + + + + + + + + + + @@ -606,6 +606,32 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + @@ -669,7 +695,7 @@ - + @@ -1284,31 +1310,6 @@ - - - - - - - - - - - - - - - - - - - - - - - - - @@ -1342,7 +1343,7 @@ - + diff --git a/dubbo-config/dubbo-config-spring/src/main/resources/META-INF/dubbo.xsd b/dubbo-config/dubbo-config-spring/src/main/resources/META-INF/dubbo.xsd index b943684d444..c5b890c7fc4 100644 --- a/dubbo-config/dubbo-config-spring/src/main/resources/META-INF/dubbo.xsd +++ b/dubbo-config/dubbo-config-spring/src/main/resources/META-INF/dubbo.xsd @@ -559,16 +559,16 @@ - - - - - - - - - - + + + + + + + + + + @@ -600,6 +600,32 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + @@ -663,7 +689,7 @@ - + @@ -1336,7 +1362,7 @@ - + diff --git a/dubbo-config/dubbo-config-spring/src/test/java/org/apache/dubbo/config/spring/ConfigTest.java b/dubbo-config/dubbo-config-spring/src/test/java/org/apache/dubbo/config/spring/ConfigTest.java index f69beedaa53..acd75bf98a1 100644 --- a/dubbo-config/dubbo-config-spring/src/test/java/org/apache/dubbo/config/spring/ConfigTest.java +++ b/dubbo-config/dubbo-config-spring/src/test/java/org/apache/dubbo/config/spring/ConfigTest.java @@ -1,1022 +1,1022 @@ -/* - * 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.spring; - -import org.apache.dubbo.common.Constants; -import org.apache.dubbo.common.URL; -import org.apache.dubbo.common.extension.ExtensionLoader; -import org.apache.dubbo.common.utils.NetUtils; -import org.apache.dubbo.common.utils.StringUtils; -import org.apache.dubbo.config.ApplicationConfig; -import org.apache.dubbo.config.ConsumerConfig; -import org.apache.dubbo.config.ProtocolConfig; -import org.apache.dubbo.config.ProviderConfig; -import org.apache.dubbo.config.ReferenceConfig; -import org.apache.dubbo.config.RegistryConfig; -import org.apache.dubbo.config.ServiceConfig; -import org.apache.dubbo.config.spring.action.DemoActionByAnnotation; -import org.apache.dubbo.config.spring.action.DemoActionBySetter; -import org.apache.dubbo.config.spring.annotation.consumer.AnnotationAction; -import org.apache.dubbo.config.spring.api.DemoService; -import org.apache.dubbo.config.spring.api.HelloService; -import org.apache.dubbo.config.spring.context.annotation.provider.ProviderConfiguration; -import org.apache.dubbo.config.spring.filter.MockFilter; -import org.apache.dubbo.config.spring.impl.DemoServiceImpl; -import org.apache.dubbo.config.spring.impl.HelloServiceImpl; -import org.apache.dubbo.config.spring.registry.MockRegistry; -import org.apache.dubbo.config.spring.registry.MockRegistryFactory; -import org.apache.dubbo.registry.Registry; -import org.apache.dubbo.registry.RegistryService; -import org.apache.dubbo.rpc.Exporter; -import org.apache.dubbo.rpc.Filter; -import org.apache.dubbo.rpc.RpcContext; -import org.apache.dubbo.rpc.RpcException; -import org.apache.dubbo.rpc.service.GenericException; -import org.apache.dubbo.rpc.service.GenericService; - -import org.junit.jupiter.api.Assertions; -import org.junit.jupiter.api.Disabled; -import org.junit.jupiter.api.Test; -import org.springframework.beans.factory.BeanCreationException; -import org.springframework.context.annotation.AnnotationConfigApplicationContext; -import org.springframework.context.support.ClassPathXmlApplicationContext; - -import java.util.Collection; -import java.util.List; - -import static org.hamcrest.MatcherAssert.assertThat; -import static org.hamcrest.Matchers.containsString; -import static org.junit.jupiter.api.Assertions.assertEquals; -import static org.junit.jupiter.api.Assertions.assertNotNull; -import static org.junit.jupiter.api.Assertions.assertNull; -import static org.junit.jupiter.api.Assertions.assertTrue; -import static org.junit.jupiter.api.Assertions.fail; - - -/** - * ConfigTest - */ -@Disabled -public class ConfigTest { - - private static void unexportService(ServiceConfig config) { - if (config != null) { - config.unexport(); - } - } - - @Test - public void testSpringExtensionInject() { - ClassPathXmlApplicationContext ctx = new ClassPathXmlApplicationContext(ConfigTest.class.getPackage().getName().replace('.', '/') + "/spring-extension-inject.xml"); - ctx.start(); - try { - MockFilter filter = (MockFilter) ExtensionLoader.getExtensionLoader(Filter.class).getExtension("mymock"); - assertNotNull(filter.getMockDao()); - assertNotNull(filter.getProtocol()); - assertNotNull(filter.getLoadBalance()); - } finally { - ctx.stop(); - ctx.close(); - } - } - - @Test - public void testServiceClass() { - ClassPathXmlApplicationContext ctx = new ClassPathXmlApplicationContext(ConfigTest.class.getPackage().getName().replace('.', '/') + "/service-class.xml"); - ctx.start(); - try { - DemoService demoService = refer("dubbo://127.0.0.1:30887"); - String hello = demoService.sayName("hello"); - assertEquals("welcome:hello", hello); - } finally { - ctx.stop(); - ctx.close(); - } - } - - @Test - public void testServiceAnnotation() { - AnnotationConfigApplicationContext providerContext = new AnnotationConfigApplicationContext(); - providerContext.register(ProviderConfiguration.class); - - providerContext.refresh(); - - ReferenceConfig reference = new ReferenceConfig(); - reference.setApplication(new ApplicationConfig("consumer")); - reference.setRegistry(new RegistryConfig(RegistryConfig.NO_AVAILABLE)); - reference.setInterface(HelloService.class); - reference.setUrl("dubbo://127.0.0.1:12345"); - String hello = reference.get().sayHello("hello"); - assertEquals("Hello, hello", hello); - - } - - @Test - @SuppressWarnings("unchecked") - public void testProviderNestedService() { - ClassPathXmlApplicationContext ctx = new ClassPathXmlApplicationContext(ConfigTest.class.getPackage().getName().replace('.', '/') + "/provider-nested-service.xml"); - ctx.start(); - try { - ServiceConfig serviceConfig = (ServiceConfig) ctx.getBean("serviceConfig"); - assertNotNull(serviceConfig.getProvider()); - assertEquals(2000, serviceConfig.getProvider().getTimeout().intValue()); - - ServiceConfig serviceConfig2 = (ServiceConfig) ctx.getBean("serviceConfig2"); - assertNotNull(serviceConfig2.getProvider()); - assertEquals(1000, serviceConfig2.getProvider().getTimeout().intValue()); - } finally { - ctx.stop(); - ctx.close(); - } - } - - private DemoService refer(String url) { - ReferenceConfig reference = new ReferenceConfig(); - reference.setApplication(new ApplicationConfig("consumer")); - reference.setRegistry(new RegistryConfig(RegistryConfig.NO_AVAILABLE)); - reference.setInterface(DemoService.class); - reference.setUrl(url); - return reference.get(); - } - - @Test - public void testToString() { - ReferenceConfig reference = new ReferenceConfig(); - reference.setApplication(new ApplicationConfig("consumer")); - reference.setRegistry(new RegistryConfig(RegistryConfig.NO_AVAILABLE)); - reference.setInterface(DemoService.class); - reference.setUrl("dubbo://127.0.0.1:20881"); - String str = reference.toString(); - assertTrue(str.startsWith("")); - } - - @Test - public void testForks() { - ReferenceConfig reference = new ReferenceConfig(); - reference.setApplication(new ApplicationConfig("consumer")); - reference.setRegistry(new RegistryConfig(RegistryConfig.NO_AVAILABLE)); - reference.setInterface(DemoService.class); - reference.setUrl("dubbo://127.0.0.1:20881"); - - int forks = 10; - reference.setForks(forks); - String str = reference.toString(); - assertTrue(str.contains("forks=\"" + forks + "\"")); - } - - @Test - public void testMultiProtocol() { - ClassPathXmlApplicationContext ctx = new ClassPathXmlApplicationContext(ConfigTest.class.getPackage().getName().replace('.', '/') + "/multi-protocol.xml"); - ctx.start(); - try { - DemoService demoService = refer("dubbo://127.0.0.1:20881"); - String hello = demoService.sayName("hello"); - assertEquals("say:hello", hello); - } finally { - ctx.stop(); - ctx.close(); - } - } - - @Test - public void testMultiProtocolDefault() { - ClassPathXmlApplicationContext ctx = new ClassPathXmlApplicationContext(ConfigTest.class.getPackage().getName().replace('.', '/') + "/multi-protocol-default.xml"); - ctx.start(); - try { - DemoService demoService = refer("rmi://127.0.0.1:10991"); - String hello = demoService.sayName("hello"); - assertEquals("say:hello", hello); - } finally { - ctx.stop(); - ctx.close(); - } - } - - @Test - public void testMultiProtocolError() { - try { - ClassPathXmlApplicationContext ctx = new ClassPathXmlApplicationContext(ConfigTest.class.getPackage().getName().replace('.', '/') + "/multi-protocol-error.xml"); - ctx.start(); - ctx.stop(); - ctx.close(); - } catch (BeanCreationException e) { - assertTrue(e.getMessage().contains("Found multi-protocols")); - } - } - - @Test - public void testMultiProtocolRegister() { - SimpleRegistryService registryService = new SimpleRegistryService(); - Exporter exporter = SimpleRegistryExporter.export(4547, registryService); - ClassPathXmlApplicationContext ctx = new ClassPathXmlApplicationContext(ConfigTest.class.getPackage().getName().replace('.', '/') + "/multi-protocol-register.xml"); - ctx.start(); - try { - List urls = registryService.getRegistered().get("org.apache.dubbo.config.spring.api.DemoService"); - assertNotNull(urls); - assertEquals(1, urls.size()); - assertEquals("dubbo://" + NetUtils.getLocalHost() + ":20824/org.apache.dubbo.config.spring.api.DemoService", urls.get(0).toIdentityString()); - } finally { - ctx.stop(); - ctx.close(); - exporter.unexport(); - } - } - - @Test - public void testMultiRegistry() { - SimpleRegistryService registryService1 = new SimpleRegistryService(); - Exporter exporter1 = SimpleRegistryExporter.export(4545, registryService1); - SimpleRegistryService registryService2 = new SimpleRegistryService(); - Exporter exporter2 = SimpleRegistryExporter.export(4546, registryService2); - ClassPathXmlApplicationContext ctx = new ClassPathXmlApplicationContext(ConfigTest.class.getPackage().getName().replace('.', '/') + "/multi-registry.xml"); - ctx.start(); - try { - List urls1 = registryService1.getRegistered().get("org.apache.dubbo.config.spring.api.DemoService"); - assertNull(urls1); - List urls2 = registryService2.getRegistered().get("org.apache.dubbo.config.spring.api.DemoService"); - assertNotNull(urls2); - assertEquals(1, urls2.size()); - assertEquals("dubbo://" + NetUtils.getLocalHost() + ":20880/org.apache.dubbo.config.spring.api.DemoService", urls2.get(0).toIdentityString()); - } finally { - ctx.stop(); - ctx.close(); - exporter1.unexport(); - exporter2.unexport(); - } - } - - @Test - public void testDelayFixedTime() throws Exception { - SimpleRegistryService registryService = new SimpleRegistryService(); - Exporter exporter = SimpleRegistryExporter.export(4548, registryService); - ClassPathXmlApplicationContext ctx = new ClassPathXmlApplicationContext(ConfigTest.class.getPackage().getName().replace('.', '/') + "/delay-fixed-time.xml"); - ctx.start(); - try { - List urls = registryService.getRegistered().get("org.apache.dubbo.config.spring.api.DemoService"); - assertNull(urls); - int i = 0; - while ((i++) < 60 && urls == null) { - urls = registryService.getRegistered().get("org.apache.dubbo.config.spring.api.DemoService"); - Thread.sleep(10); - } - assertNotNull(urls); - assertEquals(1, urls.size()); - assertEquals("dubbo://" + NetUtils.getLocalHost() + ":20888/org.apache.dubbo.config.spring.api.DemoService", urls.get(0).toIdentityString()); - } finally { - ctx.stop(); - ctx.close(); - exporter.unexport(); - } - } - - @Test - public void testDelayOnInitialized() throws Exception { - SimpleRegistryService registryService = new SimpleRegistryService(); - Exporter exporter = SimpleRegistryExporter.export(4548, registryService); - ClassPathXmlApplicationContext ctx = new ClassPathXmlApplicationContext(ConfigTest.class.getPackage().getName().replace('.', '/') + "/delay-on-initialized.xml"); - //ctx.start(); - try { - List urls = registryService.getRegistered().get("org.apache.dubbo.config.spring.api.DemoService"); - assertNotNull(urls); - assertEquals(1, urls.size()); - assertEquals("dubbo://" + NetUtils.getLocalHost() + ":20888/org.apache.dubbo.config.spring.api.DemoService", urls.get(0).toIdentityString()); - } finally { - ctx.stop(); - ctx.close(); - exporter.unexport(); - } - } - - @Test - public void testRmiTimeout() throws Exception { - if (System.getProperty("sun.rmi.transport.tcp.responseTimeout") != null) { - System.setProperty("sun.rmi.transport.tcp.responseTimeout", ""); - } - ConsumerConfig consumer = new ConsumerConfig(); - consumer.setTimeout(1000); - assertEquals("1000", System.getProperty("sun.rmi.transport.tcp.responseTimeout")); - consumer.setTimeout(2000); - assertEquals("1000", System.getProperty("sun.rmi.transport.tcp.responseTimeout")); - } - - @Test - public void testAutowireAndAOP() throws Exception { - ClassPathXmlApplicationContext providerContext = new ClassPathXmlApplicationContext(ConfigTest.class.getPackage().getName().replace('.', '/') + "/demo-provider.xml"); - providerContext.start(); - try { - ClassPathXmlApplicationContext byNameContext = new ClassPathXmlApplicationContext(ConfigTest.class.getPackage().getName().replace('.', '/') + "/aop-autowire-byname.xml"); - byNameContext.start(); - try { - DemoActionBySetter demoActionBySetter = (DemoActionBySetter) byNameContext.getBean("demoActionBySetter"); - assertNotNull(demoActionBySetter.getDemoService()); - assertEquals("aop:say:hello", demoActionBySetter.getDemoService().sayName("hello")); - DemoActionByAnnotation demoActionByAnnotation = (DemoActionByAnnotation) byNameContext.getBean("demoActionByAnnotation"); - assertNotNull(demoActionByAnnotation.getDemoService()); - assertEquals("aop:say:hello", demoActionByAnnotation.getDemoService().sayName("hello")); - } finally { - byNameContext.stop(); - byNameContext.close(); - } - ClassPathXmlApplicationContext byTypeContext = new ClassPathXmlApplicationContext(ConfigTest.class.getPackage().getName().replace('.', '/') + "/aop-autowire-bytype.xml"); - byTypeContext.start(); - try { - DemoActionBySetter demoActionBySetter = (DemoActionBySetter) byTypeContext.getBean("demoActionBySetter"); - assertNotNull(demoActionBySetter.getDemoService()); - assertEquals("aop:say:hello", demoActionBySetter.getDemoService().sayName("hello")); - DemoActionByAnnotation demoActionByAnnotation = (DemoActionByAnnotation) byTypeContext.getBean("demoActionByAnnotation"); - assertNotNull(demoActionByAnnotation.getDemoService()); - assertEquals("aop:say:hello", demoActionByAnnotation.getDemoService().sayName("hello")); - } finally { - byTypeContext.stop(); - byTypeContext.close(); - } - } finally { - providerContext.stop(); - providerContext.close(); - } - } - - @Test - public void testAppendFilter() throws Exception { - ProviderConfig provider = new ProviderConfig(); - provider.setFilter("classloader,monitor"); - ServiceConfig service = new ServiceConfig(); - service.setFilter("accesslog,trace"); - service.setProvider(provider); - service.setProtocol(new ProtocolConfig("dubbo", 20880)); - service.setApplication(new ApplicationConfig("provider")); - service.setRegistry(new RegistryConfig(RegistryConfig.NO_AVAILABLE)); - service.setInterface(DemoService.class); - service.setRef(new DemoServiceImpl()); - try { - service.export(); - List urls = service.toUrls(); - assertNotNull(urls); - assertEquals(1, urls.size()); - assertEquals("classloader,monitor,accesslog,trace", urls.get(0).getParameter("service.filter")); - - ConsumerConfig consumer = new ConsumerConfig(); - consumer.setFilter("classloader,monitor"); - ReferenceConfig reference = new ReferenceConfig(); - reference.setFilter("accesslog,trace"); - reference.setConsumer(consumer); - reference.setApplication(new ApplicationConfig("consumer")); - reference.setRegistry(new RegistryConfig(RegistryConfig.NO_AVAILABLE)); - reference.setInterface(DemoService.class); - reference.setUrl("dubbo://" + NetUtils.getLocalHost() + ":20880?" + DemoService.class.getName() + "?check=false"); - try { - reference.get(); - urls = reference.toUrls(); - assertNotNull(urls); - assertEquals(1, urls.size()); - assertEquals("classloader,monitor,accesslog,trace", urls.get(0).getParameter("reference.filter")); - } finally { - reference.destroy(); - } - } finally { - service.unexport(); - } - } - - @Test - public void testInitReference() throws Exception { - ClassPathXmlApplicationContext providerContext = new ClassPathXmlApplicationContext(ConfigTest.class.getPackage().getName().replace('.', '/') + "/demo-provider.xml"); - providerContext.start(); - try { - ClassPathXmlApplicationContext ctx = new ClassPathXmlApplicationContext(ConfigTest.class.getPackage().getName().replace('.', '/') + "/init-reference.xml"); - ctx.start(); - try { - DemoService demoService = (DemoService) ctx.getBean("demoService"); - assertEquals("say:world", demoService.sayName("world")); - } finally { - ctx.stop(); - ctx.close(); - } - } finally { - providerContext.stop(); - providerContext.close(); - } - } - - // DUBBO-571 methods key in provider's URLONE doesn't contain the methods from inherited super interface - @Test - public void test_noMethodInterface_methodsKeyHasValue() throws Exception { - ClassPathXmlApplicationContext ctx = new ClassPathXmlApplicationContext(ConfigTest.class.getPackage().getName().replace('.', '/') + "/demo-provider-no-methods-interface.xml"); - ctx.start(); - try { - ServiceBean bean = (ServiceBean) ctx.getBean("service"); - List urls = bean.getExportedUrls(); - assertEquals(1, urls.size()); - URL url = urls.get(0); - assertEquals("sayName,getBox", url.getParameter("methods")); - } finally { - ctx.stop(); - ctx.close(); - } - } - - // DUBBO-147 find all invoker instances which have been tried from RpcContext - @Test - public void test_RpcContext_getUrls() throws Exception { - ClassPathXmlApplicationContext providerContext = new ClassPathXmlApplicationContext( - ConfigTest.class.getPackage().getName().replace('.', '/') + "/demo-provider-long-waiting.xml"); - providerContext.start(); - - try { - ClassPathXmlApplicationContext ctx = new ClassPathXmlApplicationContext( - ConfigTest.class.getPackage().getName().replace('.', '/') - + "/init-reference-getUrls.xml"); - ctx.start(); - try { - DemoService demoService = (DemoService) ctx.getBean("demoService"); - try { - demoService.sayName("Haha"); - fail(); - } catch (RpcException expected) { - assertThat(expected.getMessage(), containsString("Tried 3 times")); - } - - assertEquals(3, RpcContext.getContext().getUrls().size()); - } finally { - ctx.stop(); - ctx.close(); - } - } finally { - providerContext.stop(); - providerContext.close(); - } - } - - // BUG: DUBBO-846 in version 2.0.9, config retry="false" on provider's method doesn't work - @Test - public void test_retrySettingFail() throws Exception { - ClassPathXmlApplicationContext providerContext = new ClassPathXmlApplicationContext( - ConfigTest.class.getPackage().getName().replace('.', '/') + "/demo-provider-long-waiting.xml"); - providerContext.start(); - - try { - ClassPathXmlApplicationContext ctx = new ClassPathXmlApplicationContext( - ConfigTest.class.getPackage().getName().replace('.', '/') - + "/init-reference-retry-false.xml"); - ctx.start(); - try { - DemoService demoService = (DemoService) ctx.getBean("demoService"); - try { - demoService.sayName("Haha"); - fail(); - } catch (RpcException expected) { - assertThat(expected.getMessage(), containsString("Tried 1 times")); - } - - assertEquals(1, RpcContext.getContext().getUrls().size()); - } finally { - ctx.stop(); - ctx.close(); - } - } finally { - providerContext.stop(); - providerContext.close(); - } - } - - // BuG: DUBBO-146 Provider doesn't have exception output, and consumer has timeout error when serialization fails - // for example, object transported on the wire doesn't implement Serializable - @Test - public void test_returnSerializationFail() throws Exception { - ClassPathXmlApplicationContext providerContext = new ClassPathXmlApplicationContext(ConfigTest.class.getPackage().getName().replace('.', '/') + "/demo-provider-UnserializableBox.xml"); - providerContext.start(); - try { - ClassPathXmlApplicationContext ctx = new ClassPathXmlApplicationContext(ConfigTest.class.getPackage().getName().replace('.', '/') + "/init-reference.xml"); - ctx.start(); - try { - DemoService demoService = (DemoService) ctx.getBean("demoService"); - try { - demoService.getBox(); - fail(); - } catch (RpcException expected) { - assertThat(expected.getMessage(), containsString("must implement java.io.Serializable")); - } - } finally { - ctx.stop(); - ctx.close(); - } - } finally { - providerContext.stop(); - providerContext.close(); - } - } - - @Test - public void testXmlOverrideProperties() throws Exception { - ClassPathXmlApplicationContext providerContext = new ClassPathXmlApplicationContext(ConfigTest.class.getPackage().getName().replace('.', '/') + "/xml-override-properties.xml"); - providerContext.start(); - try { - ApplicationConfig application = (ApplicationConfig) providerContext.getBean("application"); - assertEquals("demo-provider", application.getName()); - assertEquals("world", application.getOwner()); - - RegistryConfig registry = (RegistryConfig) providerContext.getBean("registry"); - assertEquals("N/A", registry.getAddress()); - - ProtocolConfig dubbo = (ProtocolConfig) providerContext.getBean("dubbo"); - assertEquals(20813, dubbo.getPort().intValue()); - - } finally { - providerContext.stop(); - providerContext.close(); - } - } - - @Test - public void testApiOverrideProperties() throws Exception { - ApplicationConfig application = new ApplicationConfig(); - application.setName("api-override-properties"); - - RegistryConfig registry = new RegistryConfig(); - registry.setAddress("N/A"); - - ProtocolConfig protocol = new ProtocolConfig(); - protocol.setName("dubbo"); - protocol.setPort(13123); - - ServiceConfig service = new ServiceConfig(); - service.setInterface(DemoService.class); - service.setRef(new DemoServiceImpl()); - service.setApplication(application); - service.setRegistry(registry); - service.setProtocol(protocol); - service.export(); - - try { - URL url = service.toUrls().get(0); - assertEquals("api-override-properties", url.getParameter("application")); - assertEquals("world", url.getParameter("owner")); - assertEquals(13123, url.getPort()); - - ReferenceConfig reference = new ReferenceConfig(); - reference.setApplication(new ApplicationConfig("consumer")); - reference.setRegistry(new RegistryConfig(RegistryConfig.NO_AVAILABLE)); - reference.setInterface(DemoService.class); - reference.setUrl("dubbo://127.0.0.1:13123"); - reference.get(); - try { - url = reference.toUrls().get(0); - assertEquals("2000", url.getParameter("timeout")); - } finally { - reference.destroy(); - } - } finally { - service.unexport(); - } - } - - @Test - public void testSystemPropertyOverrideProtocol() throws Exception { - System.setProperty("dubbo.protocol.port", "20812"); - ClassPathXmlApplicationContext providerContext = new ClassPathXmlApplicationContext(ConfigTest.class.getPackage().getName().replace('.', '/') + "/override-protocol.xml"); - providerContext.start(); - try { - ProtocolConfig dubbo = (ProtocolConfig) providerContext.getBean("dubbo"); - assertEquals(20812, dubbo.getPort().intValue()); - } finally { - System.setProperty("dubbo.protocol.port", ""); - providerContext.stop(); - providerContext.close(); - } - } - - @Test - public void testSystemPropertyOverrideMultiProtocol() throws Exception { - System.setProperty("dubbo.protocol.dubbo.port", "20814"); - System.setProperty("dubbo.protocol.rmi.port", "10914"); - ClassPathXmlApplicationContext providerContext = new ClassPathXmlApplicationContext(ConfigTest.class.getPackage().getName().replace('.', '/') + "/override-multi-protocol.xml"); - providerContext.start(); - try { - ProtocolConfig dubbo = (ProtocolConfig) providerContext.getBean("dubbo"); - assertEquals(20814, dubbo.getPort().intValue()); - ProtocolConfig rmi = (ProtocolConfig) providerContext.getBean("rmi"); - assertEquals(10914, rmi.getPort().intValue()); - } finally { - System.setProperty("dubbo.protocol.dubbo.port", ""); - System.setProperty("dubbo.protocol.rmi.port", ""); - providerContext.stop(); - providerContext.close(); - } - } - - @SuppressWarnings("unchecked") - @Test - public void testSystemPropertyOverrideXmlDefault() throws Exception { - System.setProperty("dubbo.application.name", "sysover"); - System.setProperty("dubbo.application.owner", "sysowner"); - System.setProperty("dubbo.registry.address", "N/A"); - System.setProperty("dubbo.protocol.name", "dubbo"); - System.setProperty("dubbo.protocol.port", "20819"); - ClassPathXmlApplicationContext providerContext = new ClassPathXmlApplicationContext(ConfigTest.class.getPackage().getName().replace('.', '/') + "/system-properties-override-default.xml"); - providerContext.start(); - try { - ServiceConfig service = (ServiceConfig) providerContext.getBean("demoServiceConfig"); - assertEquals("sysover", service.getApplication().getName()); - assertEquals("sysowner", service.getApplication().getOwner()); - assertEquals("N/A", service.getRegistry().getAddress()); - assertEquals("dubbo", service.getProtocol().getName()); - assertEquals(20819, service.getProtocol().getPort().intValue()); - } finally { - System.setProperty("dubbo.application.name", ""); - System.setProperty("dubbo.application.owner", ""); - System.setProperty("dubbo.registry.address", ""); - System.setProperty("dubbo.protocol.name", ""); - System.setProperty("dubbo.protocol.port", ""); - providerContext.stop(); - providerContext.close(); - } - } - - @SuppressWarnings("unchecked") - @Test - public void testSystemPropertyOverrideXml() throws Exception { - System.setProperty("dubbo.application.name", "sysover"); - System.setProperty("dubbo.application.owner", "sysowner"); - System.setProperty("dubbo.registry.address", "N/A"); - System.setProperty("dubbo.protocol.name", "dubbo"); - System.setProperty("dubbo.protocol.port", "20819"); - System.setProperty("dubbo.service.register", "false"); - ClassPathXmlApplicationContext providerContext = new ClassPathXmlApplicationContext(ConfigTest.class.getPackage().getName().replace('.', '/') + "/system-properties-override.xml"); - providerContext.start(); - try { - ServiceConfig service = (ServiceConfig) providerContext.getBean("demoServiceConfig"); - URL url = service.toUrls().get(0); - assertEquals("sysover", url.getParameter("application")); - assertEquals("sysowner", url.getParameter("owner")); - assertEquals("dubbo", url.getProtocol()); - assertEquals(20819, url.getPort()); - String register = url.getParameter("register"); - assertTrue(register != null && !"".equals(register)); - assertEquals(false, Boolean.valueOf(register)); - } finally { - System.setProperty("dubbo.application.name", ""); - System.setProperty("dubbo.application.owner", ""); - System.setProperty("dubbo.registry.address", ""); - System.setProperty("dubbo.protocol.name", ""); - System.setProperty("dubbo.protocol.port", ""); - System.setProperty("dubbo.service.register", ""); - providerContext.stop(); - providerContext.close(); - } - } - - @Test - public void testSystemPropertyOverrideReferenceConfig() throws Exception { - System.setProperty("dubbo.reference.retries", "5"); - - try { - ServiceConfig service = new ServiceConfig(); - service.setInterface(DemoService.class); - service.setRef(new DemoServiceImpl()); - service.setRegistry(new RegistryConfig(RegistryConfig.NO_AVAILABLE)); - ProtocolConfig protocolConfig = new ProtocolConfig("injvm"); - service.setProtocol(protocolConfig); - service.export(); - - ReferenceConfig reference = new ReferenceConfig(); - reference.setInterface(DemoService.class); - reference.setInjvm(true); - reference.setRetries(2); - reference.get(); - assertEquals(Integer.valueOf(5), reference.getRetries()); - } finally { - System.setProperty("dubbo.reference.retries", ""); - } - } - - @Test - public void testSystemPropertyOverrideApiDefault() throws Exception { - System.setProperty("dubbo.application.name", "sysover"); - System.setProperty("dubbo.application.owner", "sysowner"); - System.setProperty("dubbo.registry.address", "N/A"); - System.setProperty("dubbo.protocol.name", "dubbo"); - System.setProperty("dubbo.protocol.port", "20834"); - try { - ServiceConfig serviceConfig = new ServiceConfig(); - serviceConfig.setInterface(DemoService.class); - serviceConfig.setRef(new DemoServiceImpl()); - serviceConfig.export(); - try { - assertEquals("sysover", serviceConfig.getApplication().getName()); - assertEquals("sysowner", serviceConfig.getApplication().getOwner()); - assertEquals("N/A", serviceConfig.getRegistry().getAddress()); - assertEquals("dubbo", serviceConfig.getProtocol().getName()); - assertEquals(20834, serviceConfig.getProtocol().getPort().intValue()); - } finally { - serviceConfig.unexport(); - } - } finally { - System.setProperty("dubbo.application.name", ""); - System.setProperty("dubbo.application.owner", ""); - System.setProperty("dubbo.registry.address", ""); - System.setProperty("dubbo.protocol.name", ""); - System.setProperty("dubbo.protocol.port", ""); - } - } - - @Test - public void testSystemPropertyOverrideApi() throws Exception { - System.setProperty("dubbo.application.name", "sysover"); - System.setProperty("dubbo.application.owner", "sysowner"); - System.setProperty("dubbo.registry.address", "N/A"); - System.setProperty("dubbo.protocol.name", "dubbo"); - System.setProperty("dubbo.protocol.port", "20834"); - try { - ApplicationConfig application = new ApplicationConfig(); - application.setName("aaa"); - - RegistryConfig registry = new RegistryConfig(); - registry.setAddress("127.0.0.1"); - - ProtocolConfig protocol = new ProtocolConfig(); - protocol.setName("rmi"); - protocol.setPort(1099); - - ServiceConfig service = new ServiceConfig(); - service.setInterface(DemoService.class); - service.setRef(new DemoServiceImpl()); - service.setApplication(application); - service.setRegistry(registry); - service.setProtocol(protocol); - service.export(); - - try { - URL url = service.toUrls().get(0); - assertEquals("sysover", url.getParameter("application")); - assertEquals("sysowner", url.getParameter("owner")); - assertEquals("dubbo", url.getProtocol()); - assertEquals(20834, url.getPort()); - } finally { - service.unexport(); - } - } finally { - System.setProperty("dubbo.application.name", ""); - System.setProperty("dubbo.application.owner", ""); - System.setProperty("dubbo.registry.address", ""); - System.setProperty("dubbo.protocol.name", ""); - System.setProperty("dubbo.protocol.port", ""); - } - } - - @Test - public void testSystemPropertyOverrideProperties() throws Exception { - String portString = System.getProperty("dubbo.protocol.port"); - System.clearProperty("dubbo.protocol.port"); - try { - int port = 1234; - System.setProperty("dubbo.protocol.port", String.valueOf(port)); - ApplicationConfig application = new ApplicationConfig(); - application.setName("aaa"); - - RegistryConfig registry = new RegistryConfig(); - registry.setAddress("N/A"); - - ProtocolConfig protocol = new ProtocolConfig(); - protocol.setName("rmi"); - - ServiceConfig service = new ServiceConfig(); - service.setInterface(DemoService.class); - service.setRef(new DemoServiceImpl()); - service.setApplication(application); - service.setRegistry(registry); - service.setProtocol(protocol); - service.export(); - - try { - URL url = service.toUrls().get(0); - // from api - assertEquals("aaa", url.getParameter("application")); - // from dubbo.properties - assertEquals("world", url.getParameter("owner")); - // from system property - assertEquals(1234, url.getPort()); - } finally { - service.unexport(); - } - } finally { - if (portString != null) { - System.setProperty("dubbo.protocol.port", portString); - } - } - } - - @Test - @SuppressWarnings("unchecked") - public void testCustomizeParameter() throws Exception { - ClassPathXmlApplicationContext context = - new ClassPathXmlApplicationContext(ConfigTest.class.getPackage().getName().replace('.', '/') + "/customize-parameter.xml"); - context.start(); - ServiceBean serviceBean = (ServiceBean) context.getBean("demoServiceExport"); - URL url = (URL) serviceBean.toUrls().get(0); - assertEquals("protocol-paramA", url.getParameter("protocol.paramA")); - assertEquals("service-paramA", url.getParameter("service.paramA")); - } - - @Test - public void testPath() throws Exception { - ServiceConfig service = new ServiceConfig(); - service.setPath("a/b$c"); - try { - service.setPath("a?b"); - fail(); - } catch (IllegalStateException e) { - assertTrue(e.getMessage().contains("")); - } - } - - @Test - public void testAnnotation() { - SimpleRegistryService registryService = new SimpleRegistryService(); - Exporter exporter = SimpleRegistryExporter.export(4548, registryService); - try { - ClassPathXmlApplicationContext providerContext = new ClassPathXmlApplicationContext(ConfigTest.class.getPackage().getName().replace('.', '/') + "/annotation-provider.xml"); - providerContext.start(); - try { - ClassPathXmlApplicationContext consumerContext = new ClassPathXmlApplicationContext(ConfigTest.class.getPackage().getName().replace('.', '/') + "/annotation-consumer.xml"); - consumerContext.start(); - try { - AnnotationAction annotationAction = (AnnotationAction) consumerContext.getBean("annotationAction"); - String hello = annotationAction.doSayName("hello"); - assertEquals("annotation:hello", hello); - } finally { - consumerContext.stop(); - consumerContext.close(); - } - } finally { - providerContext.stop(); - providerContext.close(); - } - } finally { - exporter.unexport(); - } - } - - @Test - public void testDubboProtocolPortOverride() throws Exception { - String dubboPort = System.getProperty("dubbo.protocol.dubbo.port"); - int port = 55555; - System.setProperty("dubbo.protocol.dubbo.port", String.valueOf(port)); - ServiceConfig service = null; - try { - ApplicationConfig application = new ApplicationConfig(); - application.setName("dubbo-protocol-port-override"); - - RegistryConfig registry = new RegistryConfig(); - registry.setAddress("N/A"); - - ProtocolConfig protocol = new ProtocolConfig(); - - service = new ServiceConfig(); - service.setInterface(DemoService.class); - service.setRef(new DemoServiceImpl()); - service.setApplication(application); - service.setRegistry(registry); - service.setProtocol(protocol); - service.export(); - - Assertions.assertEquals(port, service.getExportedUrls().get(0).getPort()); - } finally { - if (StringUtils.isNotEmpty(dubboPort)) { - System.setProperty("dubbo.protocol.dubbo.port", dubboPort); - } - if (service != null) { - service.unexport(); - } - } - } - - @Test - public void testProtocolRandomPort() throws Exception { - ServiceConfig demoService = null; - ServiceConfig helloService = null; - - ApplicationConfig application = new ApplicationConfig(); - application.setName("test-protocol-random-port"); - - RegistryConfig registry = new RegistryConfig(); - registry.setAddress("N/A"); - - ProtocolConfig protocol = new ProtocolConfig(); - protocol.setName("dubbo"); - protocol.setPort(-1); - - demoService = new ServiceConfig(); - demoService.setInterface(DemoService.class); - demoService.setRef(new DemoServiceImpl()); - demoService.setApplication(application); - demoService.setRegistry(registry); - demoService.setProtocol(protocol); - - helloService = new ServiceConfig(); - helloService.setInterface(HelloService.class); - helloService.setRef(new HelloServiceImpl()); - helloService.setApplication(application); - helloService.setRegistry(registry); - helloService.setProtocol(protocol); - - try { - demoService.export(); - helloService.export(); - - Assertions.assertEquals(demoService.getExportedUrls().get(0).getPort(), - helloService.getExportedUrls().get(0).getPort()); - } finally { - unexportService(demoService); - unexportService(helloService); - } - } - - @Test - public void testReferGenericExport() throws Exception { - ApplicationConfig ac = new ApplicationConfig("test-refer-generic-export"); - RegistryConfig rc = new RegistryConfig(); - rc.setAddress(RegistryConfig.NO_AVAILABLE); - - ServiceConfig sc = new ServiceConfig(); - sc.setApplication(ac); - sc.setRegistry(rc); - sc.setInterface(DemoService.class.getName()); - sc.setRef(new GenericService() { - - public Object $invoke(String method, String[] parameterTypes, Object[] args) throws GenericException { - return null; - } - }); - - ReferenceConfig ref = new ReferenceConfig(); - ref.setApplication(ac); - ref.setRegistry(rc); - ref.setInterface(DemoService.class.getName()); - - try { - sc.export(); - ref.get(); - Assertions.fail(); - } catch (Exception e) { - e.printStackTrace(); - } finally { - sc.unexport(); - ref.destroy(); - } - } - - @Test - public void testGenericServiceConfig() throws Exception { - ServiceConfig service = new ServiceConfig(); - service.setApplication(new ApplicationConfig("test")); - service.setRegistry(new RegistryConfig("mock://localhost")); - service.setInterface(DemoService.class.getName()); - service.setGeneric(Constants.GENERIC_SERIALIZATION_BEAN); - service.setRef(new GenericService() { - - public Object $invoke(String method, String[] parameterTypes, Object[] args) throws GenericException { - return null; - } - }); - try { - service.export(); - Collection collection = MockRegistryFactory.getCachedRegistry(); - MockRegistry registry = (MockRegistry) collection.iterator().next(); - URL url = registry.getRegistered().get(0); - Assertions.assertEquals(Constants.GENERIC_SERIALIZATION_BEAN, url.getParameter(Constants.GENERIC_KEY)); - } finally { - MockRegistryFactory.cleanCachedRegistry(); - service.unexport(); - } - } - - @Test - public void testGenericServiceConfigThroughSpring() throws Exception { - ClassPathXmlApplicationContext ctx = new ClassPathXmlApplicationContext(ConfigTest.class.getPackage().getName().replace('.', '/') + "/generic-export.xml"); - try { - ctx.start(); - ServiceConfig serviceConfig = (ServiceConfig) ctx.getBean("dubboDemoService"); - URL url = (URL) serviceConfig.getExportedUrls().get(0); - Assertions.assertEquals(Constants.GENERIC_SERIALIZATION_BEAN, url.getParameter(Constants.GENERIC_KEY)); - } finally { - ctx.destroy(); - } - } +/* + * 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.spring; + +import org.apache.dubbo.common.Constants; +import org.apache.dubbo.common.URL; +import org.apache.dubbo.common.extension.ExtensionLoader; +import org.apache.dubbo.common.utils.NetUtils; +import org.apache.dubbo.common.utils.StringUtils; +import org.apache.dubbo.config.ApplicationConfig; +import org.apache.dubbo.config.ConsumerConfig; +import org.apache.dubbo.config.ProtocolConfig; +import org.apache.dubbo.config.ProviderConfig; +import org.apache.dubbo.config.ReferenceConfig; +import org.apache.dubbo.config.RegistryConfig; +import org.apache.dubbo.config.ServiceConfig; +import org.apache.dubbo.config.spring.action.DemoActionByAnnotation; +import org.apache.dubbo.config.spring.action.DemoActionBySetter; +import org.apache.dubbo.config.spring.annotation.consumer.AnnotationAction; +import org.apache.dubbo.config.spring.api.DemoService; +import org.apache.dubbo.config.spring.api.HelloService; +import org.apache.dubbo.config.spring.context.annotation.provider.ProviderConfiguration; +import org.apache.dubbo.config.spring.filter.MockFilter; +import org.apache.dubbo.config.spring.impl.DemoServiceImpl; +import org.apache.dubbo.config.spring.impl.HelloServiceImpl; +import org.apache.dubbo.config.spring.registry.MockRegistry; +import org.apache.dubbo.config.spring.registry.MockRegistryFactory; +import org.apache.dubbo.registry.Registry; +import org.apache.dubbo.registry.RegistryService; +import org.apache.dubbo.rpc.Exporter; +import org.apache.dubbo.rpc.Filter; +import org.apache.dubbo.rpc.RpcContext; +import org.apache.dubbo.rpc.RpcException; +import org.apache.dubbo.rpc.service.GenericException; +import org.apache.dubbo.rpc.service.GenericService; + +import org.junit.Assert; +import org.junit.Ignore; +import org.junit.Test; +import org.springframework.beans.factory.BeanCreationException; +import org.springframework.context.annotation.AnnotationConfigApplicationContext; +import org.springframework.context.support.ClassPathXmlApplicationContext; + +import java.util.Collection; +import java.util.List; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertNotNull; +import static org.junit.Assert.assertNull; +import static org.junit.Assert.assertThat; +import static org.junit.Assert.assertTrue; +import static org.junit.Assert.fail; +import static org.junit.matchers.JUnitMatchers.containsString; + + +/** + * ConfigTest + */ +@Ignore +public class ConfigTest { + + private static void unexportService(ServiceConfig config) { + if (config != null) { + config.unexport(); + } + } + + @Test + public void testSpringExtensionInject() { + ClassPathXmlApplicationContext ctx = new ClassPathXmlApplicationContext(ConfigTest.class.getPackage().getName().replace('.', '/') + "/spring-extension-inject.xml"); + ctx.start(); + try { + MockFilter filter = (MockFilter) ExtensionLoader.getExtensionLoader(Filter.class).getExtension("mymock"); + assertNotNull(filter.getMockDao()); + assertNotNull(filter.getProtocol()); + assertNotNull(filter.getLoadBalance()); + } finally { + ctx.stop(); + ctx.close(); + } + } + + @Test + public void testServiceClass() { + ClassPathXmlApplicationContext ctx = new ClassPathXmlApplicationContext(ConfigTest.class.getPackage().getName().replace('.', '/') + "/service-class.xml"); + ctx.start(); + try { + DemoService demoService = refer("dubbo://127.0.0.1:30887"); + String hello = demoService.sayName("hello"); + assertEquals("welcome:hello", hello); + } finally { + ctx.stop(); + ctx.close(); + } + } + + @Test + public void testServiceAnnotation() { + AnnotationConfigApplicationContext providerContext = new AnnotationConfigApplicationContext(); + providerContext.register(ProviderConfiguration.class); + + providerContext.refresh(); + + ReferenceConfig reference = new ReferenceConfig(); + reference.setApplication(new ApplicationConfig("consumer")); + reference.setRegistry(new RegistryConfig(RegistryConfig.NO_AVAILABLE)); + reference.setInterface(HelloService.class); + reference.setUrl("dubbo://127.0.0.1:12345"); + String hello = reference.get().sayHello("hello"); + assertEquals("Hello, hello", hello); + + } + + @Test + @SuppressWarnings("unchecked") + public void testProviderNestedService() { + ClassPathXmlApplicationContext ctx = new ClassPathXmlApplicationContext(ConfigTest.class.getPackage().getName().replace('.', '/') + "/provider-nested-service.xml"); + ctx.start(); + try { + ServiceConfig serviceConfig = (ServiceConfig) ctx.getBean("serviceConfig"); + assertNotNull(serviceConfig.getProvider()); + assertEquals(2000, serviceConfig.getProvider().getTimeout().intValue()); + + ServiceConfig serviceConfig2 = (ServiceConfig) ctx.getBean("serviceConfig2"); + assertNotNull(serviceConfig2.getProvider()); + assertEquals(1000, serviceConfig2.getProvider().getTimeout().intValue()); + } finally { + ctx.stop(); + ctx.close(); + } + } + + private DemoService refer(String url) { + ReferenceConfig reference = new ReferenceConfig(); + reference.setApplication(new ApplicationConfig("consumer")); + reference.setRegistry(new RegistryConfig(RegistryConfig.NO_AVAILABLE)); + reference.setInterface(DemoService.class); + reference.setUrl(url); + return reference.get(); + } + + @Test + public void testToString() { + ReferenceConfig reference = new ReferenceConfig(); + reference.setApplication(new ApplicationConfig("consumer")); + reference.setRegistry(new RegistryConfig(RegistryConfig.NO_AVAILABLE)); + reference.setInterface(DemoService.class); + reference.setUrl("dubbo://127.0.0.1:20881"); + String str = reference.toString(); + assertTrue(str.startsWith("")); + } + + @Test + public void testForks() { + ReferenceConfig reference = new ReferenceConfig(); + reference.setApplication(new ApplicationConfig("consumer")); + reference.setRegistry(new RegistryConfig(RegistryConfig.NO_AVAILABLE)); + reference.setInterface(DemoService.class); + reference.setUrl("dubbo://127.0.0.1:20881"); + + int forks = 10; + reference.setForks(forks); + String str = reference.toString(); + assertTrue(str.contains("forks=\"" + forks + "\"")); + } + + @Test + public void testMultiProtocol() { + ClassPathXmlApplicationContext ctx = new ClassPathXmlApplicationContext(ConfigTest.class.getPackage().getName().replace('.', '/') + "/multi-protocol.xml"); + ctx.start(); + try { + DemoService demoService = refer("dubbo://127.0.0.1:20881"); + String hello = demoService.sayName("hello"); + assertEquals("say:hello", hello); + } finally { + ctx.stop(); + ctx.close(); + } + } + + @Test + public void testMultiProtocolDefault() { + ClassPathXmlApplicationContext ctx = new ClassPathXmlApplicationContext(ConfigTest.class.getPackage().getName().replace('.', '/') + "/multi-protocol-default.xml"); + ctx.start(); + try { + DemoService demoService = refer("rmi://127.0.0.1:10991"); + String hello = demoService.sayName("hello"); + assertEquals("say:hello", hello); + } finally { + ctx.stop(); + ctx.close(); + } + } + + @Test + public void testMultiProtocolError() { + try { + ClassPathXmlApplicationContext ctx = new ClassPathXmlApplicationContext(ConfigTest.class.getPackage().getName().replace('.', '/') + "/multi-protocol-error.xml"); + ctx.start(); + ctx.stop(); + ctx.close(); + } catch (BeanCreationException e) { + assertTrue(e.getMessage().contains("Found multi-protocols")); + } + } + + @Test + public void testMultiProtocolRegister() { + SimpleRegistryService registryService = new SimpleRegistryService(); + Exporter exporter = SimpleRegistryExporter.export(4547, registryService); + ClassPathXmlApplicationContext ctx = new ClassPathXmlApplicationContext(ConfigTest.class.getPackage().getName().replace('.', '/') + "/multi-protocol-register.xml"); + ctx.start(); + try { + List urls = registryService.getRegistered().get("org.apache.dubbo.config.spring.api.DemoService"); + assertNotNull(urls); + assertEquals(1, urls.size()); + assertEquals("dubbo://" + NetUtils.getLocalHost() + ":20824/org.apache.dubbo.config.spring.api.DemoService", urls.get(0).toIdentityString()); + } finally { + ctx.stop(); + ctx.close(); + exporter.unexport(); + } + } + + @Test + public void testMultiRegistry() { + SimpleRegistryService registryService1 = new SimpleRegistryService(); + Exporter exporter1 = SimpleRegistryExporter.export(4545, registryService1); + SimpleRegistryService registryService2 = new SimpleRegistryService(); + Exporter exporter2 = SimpleRegistryExporter.export(4546, registryService2); + ClassPathXmlApplicationContext ctx = new ClassPathXmlApplicationContext(ConfigTest.class.getPackage().getName().replace('.', '/') + "/multi-registry.xml"); + ctx.start(); + try { + List urls1 = registryService1.getRegistered().get("org.apache.dubbo.config.spring.api.DemoService"); + assertNull(urls1); + List urls2 = registryService2.getRegistered().get("org.apache.dubbo.config.spring.api.DemoService"); + assertNotNull(urls2); + assertEquals(1, urls2.size()); + assertEquals("dubbo://" + NetUtils.getLocalHost() + ":20880/org.apache.dubbo.config.spring.api.DemoService", urls2.get(0).toIdentityString()); + } finally { + ctx.stop(); + ctx.close(); + exporter1.unexport(); + exporter2.unexport(); + } + } + + @Test + public void testDelayFixedTime() throws Exception { + SimpleRegistryService registryService = new SimpleRegistryService(); + Exporter exporter = SimpleRegistryExporter.export(4548, registryService); + ClassPathXmlApplicationContext ctx = new ClassPathXmlApplicationContext(ConfigTest.class.getPackage().getName().replace('.', '/') + "/delay-fixed-time.xml"); + ctx.start(); + try { + List urls = registryService.getRegistered().get("org.apache.dubbo.config.spring.api.DemoService"); + assertNull(urls); + int i = 0; + while ((i++) < 60 && urls == null) { + urls = registryService.getRegistered().get("org.apache.dubbo.config.spring.api.DemoService"); + Thread.sleep(10); + } + assertNotNull(urls); + assertEquals(1, urls.size()); + assertEquals("dubbo://" + NetUtils.getLocalHost() + ":20888/org.apache.dubbo.config.spring.api.DemoService", urls.get(0).toIdentityString()); + } finally { + ctx.stop(); + ctx.close(); + exporter.unexport(); + } + } + + @Test + public void testDelayOnInitialized() throws Exception { + SimpleRegistryService registryService = new SimpleRegistryService(); + Exporter exporter = SimpleRegistryExporter.export(4548, registryService); + ClassPathXmlApplicationContext ctx = new ClassPathXmlApplicationContext(ConfigTest.class.getPackage().getName().replace('.', '/') + "/delay-on-initialized.xml"); + //ctx.start(); + try { + List urls = registryService.getRegistered().get("org.apache.dubbo.config.spring.api.DemoService"); + assertNotNull(urls); + assertEquals(1, urls.size()); + assertEquals("dubbo://" + NetUtils.getLocalHost() + ":20888/org.apache.dubbo.config.spring.api.DemoService", urls.get(0).toIdentityString()); + } finally { + ctx.stop(); + ctx.close(); + exporter.unexport(); + } + } + + @Test + public void testRmiTimeout() throws Exception { + if (System.getProperty("sun.rmi.transport.tcp.responseTimeout") != null) { + System.setProperty("sun.rmi.transport.tcp.responseTimeout", ""); + } + ConsumerConfig consumer = new ConsumerConfig(); + consumer.setTimeout(1000); + assertEquals("1000", System.getProperty("sun.rmi.transport.tcp.responseTimeout")); + consumer.setTimeout(2000); + assertEquals("1000", System.getProperty("sun.rmi.transport.tcp.responseTimeout")); + } + + @Test + public void testAutowireAndAOP() throws Exception { + ClassPathXmlApplicationContext providerContext = new ClassPathXmlApplicationContext(ConfigTest.class.getPackage().getName().replace('.', '/') + "/demo-provider.xml"); + providerContext.start(); + try { + ClassPathXmlApplicationContext byNameContext = new ClassPathXmlApplicationContext(ConfigTest.class.getPackage().getName().replace('.', '/') + "/aop-autowire-byname.xml"); + byNameContext.start(); + try { + DemoActionBySetter demoActionBySetter = (DemoActionBySetter) byNameContext.getBean("demoActionBySetter"); + assertNotNull(demoActionBySetter.getDemoService()); + assertEquals("aop:say:hello", demoActionBySetter.getDemoService().sayName("hello")); + DemoActionByAnnotation demoActionByAnnotation = (DemoActionByAnnotation) byNameContext.getBean("demoActionByAnnotation"); + assertNotNull(demoActionByAnnotation.getDemoService()); + assertEquals("aop:say:hello", demoActionByAnnotation.getDemoService().sayName("hello")); + } finally { + byNameContext.stop(); + byNameContext.close(); + } + ClassPathXmlApplicationContext byTypeContext = new ClassPathXmlApplicationContext(ConfigTest.class.getPackage().getName().replace('.', '/') + "/aop-autowire-bytype.xml"); + byTypeContext.start(); + try { + DemoActionBySetter demoActionBySetter = (DemoActionBySetter) byTypeContext.getBean("demoActionBySetter"); + assertNotNull(demoActionBySetter.getDemoService()); + assertEquals("aop:say:hello", demoActionBySetter.getDemoService().sayName("hello")); + DemoActionByAnnotation demoActionByAnnotation = (DemoActionByAnnotation) byTypeContext.getBean("demoActionByAnnotation"); + assertNotNull(demoActionByAnnotation.getDemoService()); + assertEquals("aop:say:hello", demoActionByAnnotation.getDemoService().sayName("hello")); + } finally { + byTypeContext.stop(); + byTypeContext.close(); + } + } finally { + providerContext.stop(); + providerContext.close(); + } + } + + @Test + public void testAppendFilter() throws Exception { + ProviderConfig provider = new ProviderConfig(); + provider.setFilter("classloader,monitor"); + ServiceConfig service = new ServiceConfig(); + service.setFilter("accesslog,trace"); + service.setProvider(provider); + service.setProtocol(new ProtocolConfig("dubbo", 20880)); + service.setApplication(new ApplicationConfig("provider")); + service.setRegistry(new RegistryConfig(RegistryConfig.NO_AVAILABLE)); + service.setInterface(DemoService.class); + service.setRef(new DemoServiceImpl()); + try { + service.export(); + List urls = service.toUrls(); + assertNotNull(urls); + assertEquals(1, urls.size()); + assertEquals("classloader,monitor,accesslog,trace", urls.get(0).getParameter("service.filter")); + + ConsumerConfig consumer = new ConsumerConfig(); + consumer.setFilter("classloader,monitor"); + ReferenceConfig reference = new ReferenceConfig(); + reference.setFilter("accesslog,trace"); + reference.setConsumer(consumer); + reference.setApplication(new ApplicationConfig("consumer")); + reference.setRegistry(new RegistryConfig(RegistryConfig.NO_AVAILABLE)); + reference.setInterface(DemoService.class); + reference.setUrl("dubbo://" + NetUtils.getLocalHost() + ":20880?" + DemoService.class.getName() + "?check=false"); + try { + reference.get(); + urls = reference.toUrls(); + assertNotNull(urls); + assertEquals(1, urls.size()); + assertEquals("classloader,monitor,accesslog,trace", urls.get(0).getParameter("reference.filter")); + } finally { + reference.destroy(); + } + } finally { + service.unexport(); + } + } + + @Test + public void testInitReference() throws Exception { + ClassPathXmlApplicationContext providerContext = new ClassPathXmlApplicationContext(ConfigTest.class.getPackage().getName().replace('.', '/') + "/demo-provider.xml"); + providerContext.start(); + try { + ClassPathXmlApplicationContext ctx = new ClassPathXmlApplicationContext(ConfigTest.class.getPackage().getName().replace('.', '/') + "/init-reference.xml"); + ctx.start(); + try { + DemoService demoService = (DemoService) ctx.getBean("demoService"); + assertEquals("say:world", demoService.sayName("world")); + } finally { + ctx.stop(); + ctx.close(); + } + } finally { + providerContext.stop(); + providerContext.close(); + } + } + + // DUBBO-571 methods key in provider's URLONE doesn't contain the methods from inherited super interface + @Test + public void test_noMethodInterface_methodsKeyHasValue() throws Exception { + ClassPathXmlApplicationContext ctx = new ClassPathXmlApplicationContext(ConfigTest.class.getPackage().getName().replace('.', '/') + "/demo-provider-no-methods-interface.xml"); + ctx.start(); + try { + ServiceBean bean = (ServiceBean) ctx.getBean("service"); + List urls = bean.getExportedUrls(); + assertEquals(1, urls.size()); + URL url = urls.get(0); + assertEquals("sayName,getBox", url.getParameter("methods")); + } finally { + ctx.stop(); + ctx.close(); + } + } + + // DUBBO-147 find all invoker instances which have been tried from RpcContext + @Test + public void test_RpcContext_getUrls() throws Exception { + ClassPathXmlApplicationContext providerContext = new ClassPathXmlApplicationContext( + ConfigTest.class.getPackage().getName().replace('.', '/') + "/demo-provider-long-waiting.xml"); + providerContext.start(); + + try { + ClassPathXmlApplicationContext ctx = new ClassPathXmlApplicationContext( + ConfigTest.class.getPackage().getName().replace('.', '/') + + "/init-reference-getUrls.xml"); + ctx.start(); + try { + DemoService demoService = (DemoService) ctx.getBean("demoService"); + try { + demoService.sayName("Haha"); + fail(); + } catch (RpcException expected) { + assertThat(expected.getMessage(), containsString("Tried 3 times")); + } + + assertEquals(3, RpcContext.getContext().getUrls().size()); + } finally { + ctx.stop(); + ctx.close(); + } + } finally { + providerContext.stop(); + providerContext.close(); + } + } + + // BUG: DUBBO-846 in version 2.0.9, config retry="false" on provider's method doesn't work + @Test + public void test_retrySettingFail() throws Exception { + ClassPathXmlApplicationContext providerContext = new ClassPathXmlApplicationContext( + ConfigTest.class.getPackage().getName().replace('.', '/') + "/demo-provider-long-waiting.xml"); + providerContext.start(); + + try { + ClassPathXmlApplicationContext ctx = new ClassPathXmlApplicationContext( + ConfigTest.class.getPackage().getName().replace('.', '/') + + "/init-reference-retry-false.xml"); + ctx.start(); + try { + DemoService demoService = (DemoService) ctx.getBean("demoService"); + try { + demoService.sayName("Haha"); + fail(); + } catch (RpcException expected) { + assertThat(expected.getMessage(), containsString("Tried 1 times")); + } + + assertEquals(1, RpcContext.getContext().getUrls().size()); + } finally { + ctx.stop(); + ctx.close(); + } + } finally { + providerContext.stop(); + providerContext.close(); + } + } + + // BuG: DUBBO-146 Provider doesn't have exception output, and consumer has timeout error when serialization fails + // for example, object transported on the wire doesn't implement Serializable + @Test + public void test_returnSerializationFail() throws Exception { + ClassPathXmlApplicationContext providerContext = new ClassPathXmlApplicationContext(ConfigTest.class.getPackage().getName().replace('.', '/') + "/demo-provider-UnserializableBox.xml"); + providerContext.start(); + try { + ClassPathXmlApplicationContext ctx = new ClassPathXmlApplicationContext(ConfigTest.class.getPackage().getName().replace('.', '/') + "/init-reference.xml"); + ctx.start(); + try { + DemoService demoService = (DemoService) ctx.getBean("demoService"); + try { + demoService.getBox(); + fail(); + } catch (RpcException expected) { + assertThat(expected.getMessage(), containsString("must implement java.io.Serializable")); + } + } finally { + ctx.stop(); + ctx.close(); + } + } finally { + providerContext.stop(); + providerContext.close(); + } + } + + @Test + public void testXmlOverrideProperties() throws Exception { + ClassPathXmlApplicationContext providerContext = new ClassPathXmlApplicationContext(ConfigTest.class.getPackage().getName().replace('.', '/') + "/xml-override-properties.xml"); + providerContext.start(); + try { + ApplicationConfig application = (ApplicationConfig) providerContext.getBean("application"); + assertEquals("demo-provider", application.getName()); + assertEquals("world", application.getOwner()); + + RegistryConfig registry = (RegistryConfig) providerContext.getBean("registry"); + assertEquals("N/A", registry.getAddress()); + + ProtocolConfig dubbo = (ProtocolConfig) providerContext.getBean("dubbo"); + assertEquals(20813, dubbo.getPort().intValue()); + + } finally { + providerContext.stop(); + providerContext.close(); + } + } + + @Test + public void testApiOverrideProperties() throws Exception { + ApplicationConfig application = new ApplicationConfig(); + application.setName("api-override-properties"); + + RegistryConfig registry = new RegistryConfig(); + registry.setAddress("N/A"); + + ProtocolConfig protocol = new ProtocolConfig(); + protocol.setName("dubbo"); + protocol.setPort(13123); + + ServiceConfig service = new ServiceConfig(); + service.setInterface(DemoService.class); + service.setRef(new DemoServiceImpl()); + service.setApplication(application); + service.setRegistry(registry); + service.setProtocol(protocol); + service.export(); + + try { + URL url = service.toUrls().get(0); + assertEquals("api-override-properties", url.getParameter("application")); + assertEquals("world", url.getParameter("owner")); + assertEquals(13123, url.getPort()); + + ReferenceConfig reference = new ReferenceConfig(); + reference.setApplication(new ApplicationConfig("consumer")); + reference.setRegistry(new RegistryConfig(RegistryConfig.NO_AVAILABLE)); + reference.setInterface(DemoService.class); + reference.setUrl("dubbo://127.0.0.1:13123"); + reference.get(); + try { + url = reference.toUrls().get(0); + assertEquals("2000", url.getParameter("timeout")); + } finally { + reference.destroy(); + } + } finally { + service.unexport(); + } + } + + @Test + public void testSystemPropertyOverrideProtocol() throws Exception { + System.setProperty("dubbo.protocol.port", "20812"); + ClassPathXmlApplicationContext providerContext = new ClassPathXmlApplicationContext(ConfigTest.class.getPackage().getName().replace('.', '/') + "/override-protocol.xml"); + providerContext.start(); + try { + ProtocolConfig dubbo = (ProtocolConfig) providerContext.getBean("dubbo"); + assertEquals(20812, dubbo.getPort().intValue()); + } finally { + System.setProperty("dubbo.protocol.port", ""); + providerContext.stop(); + providerContext.close(); + } + } + + @Test + public void testSystemPropertyOverrideMultiProtocol() throws Exception { + System.setProperty("dubbo.protocol.dubbo.port", "20814"); + System.setProperty("dubbo.protocol.rmi.port", "10914"); + ClassPathXmlApplicationContext providerContext = new ClassPathXmlApplicationContext(ConfigTest.class.getPackage().getName().replace('.', '/') + "/override-multi-protocol.xml"); + providerContext.start(); + try { + ProtocolConfig dubbo = (ProtocolConfig) providerContext.getBean("dubbo"); + assertEquals(20814, dubbo.getPort().intValue()); + ProtocolConfig rmi = (ProtocolConfig) providerContext.getBean("rmi"); + assertEquals(10914, rmi.getPort().intValue()); + } finally { + System.setProperty("dubbo.protocol.dubbo.port", ""); + System.setProperty("dubbo.protocol.rmi.port", ""); + providerContext.stop(); + providerContext.close(); + } + } + + @SuppressWarnings("unchecked") + @Test + public void testSystemPropertyOverrideXmlDefault() throws Exception { + System.setProperty("dubbo.application.name", "sysover"); + System.setProperty("dubbo.application.owner", "sysowner"); + System.setProperty("dubbo.registry.address", "N/A"); + System.setProperty("dubbo.protocol.name", "dubbo"); + System.setProperty("dubbo.protocol.port", "20819"); + ClassPathXmlApplicationContext providerContext = new ClassPathXmlApplicationContext(ConfigTest.class.getPackage().getName().replace('.', '/') + "/system-properties-override-default.xml"); + providerContext.start(); + try { + ServiceConfig service = (ServiceConfig) providerContext.getBean("demoServiceConfig"); + assertEquals("sysover", service.getApplication().getName()); + assertEquals("sysowner", service.getApplication().getOwner()); + assertEquals("N/A", service.getRegistry().getAddress()); + assertEquals("dubbo", service.getProtocol().getName()); + assertEquals(20819, service.getProtocol().getPort().intValue()); + } finally { + System.setProperty("dubbo.application.name", ""); + System.setProperty("dubbo.application.owner", ""); + System.setProperty("dubbo.registry.address", ""); + System.setProperty("dubbo.protocol.name", ""); + System.setProperty("dubbo.protocol.port", ""); + providerContext.stop(); + providerContext.close(); + } + } + + @SuppressWarnings("unchecked") + @Test + public void testSystemPropertyOverrideXml() throws Exception { + System.setProperty("dubbo.application.name", "sysover"); + System.setProperty("dubbo.application.owner", "sysowner"); + System.setProperty("dubbo.registry.address", "N/A"); + System.setProperty("dubbo.protocol.name", "dubbo"); + System.setProperty("dubbo.protocol.port", "20819"); + System.setProperty("dubbo.service.register", "false"); + ClassPathXmlApplicationContext providerContext = new ClassPathXmlApplicationContext(ConfigTest.class.getPackage().getName().replace('.', '/') + "/system-properties-override.xml"); + providerContext.start(); + try { + ServiceConfig service = (ServiceConfig) providerContext.getBean("demoServiceConfig"); + URL url = service.toUrls().get(0); + assertEquals("sysover", url.getParameter("application")); + assertEquals("sysowner", url.getParameter("owner")); + assertEquals("dubbo", url.getProtocol()); + assertEquals(20819, url.getPort()); + String register = url.getParameter("register"); + assertTrue(register != null && !"".equals(register)); + assertEquals(false, Boolean.valueOf(register)); + } finally { + System.setProperty("dubbo.application.name", ""); + System.setProperty("dubbo.application.owner", ""); + System.setProperty("dubbo.registry.address", ""); + System.setProperty("dubbo.protocol.name", ""); + System.setProperty("dubbo.protocol.port", ""); + System.setProperty("dubbo.service.register", ""); + providerContext.stop(); + providerContext.close(); + } + } + + @Test + public void testSystemPropertyOverrideReferenceConfig() throws Exception { + System.setProperty("dubbo.reference.retries", "5"); + + try { + ServiceConfig service = new ServiceConfig(); + service.setInterface(DemoService.class); + service.setRef(new DemoServiceImpl()); + service.setRegistry(new RegistryConfig(RegistryConfig.NO_AVAILABLE)); + ProtocolConfig protocolConfig = new ProtocolConfig("injvm"); + service.setProtocol(protocolConfig); + service.export(); + + ReferenceConfig reference = new ReferenceConfig(); + reference.setInterface(DemoService.class); + reference.setInjvm(true); + reference.setRetries(2); + reference.get(); + assertEquals(Integer.valueOf(5), reference.getRetries()); + } finally { + System.setProperty("dubbo.reference.retries", ""); + } + } + + @Test + public void testSystemPropertyOverrideApiDefault() throws Exception { + System.setProperty("dubbo.application.name", "sysover"); + System.setProperty("dubbo.application.owner", "sysowner"); + System.setProperty("dubbo.registry.address", "N/A"); + System.setProperty("dubbo.protocol.name", "dubbo"); + System.setProperty("dubbo.protocol.port", "20834"); + try { + ServiceConfig serviceConfig = new ServiceConfig(); + serviceConfig.setInterface(DemoService.class); + serviceConfig.setRef(new DemoServiceImpl()); + serviceConfig.export(); + try { + assertEquals("sysover", serviceConfig.getApplication().getName()); + assertEquals("sysowner", serviceConfig.getApplication().getOwner()); + assertEquals("N/A", serviceConfig.getRegistry().getAddress()); + assertEquals("dubbo", serviceConfig.getProtocol().getName()); + assertEquals(20834, serviceConfig.getProtocol().getPort().intValue()); + } finally { + serviceConfig.unexport(); + } + } finally { + System.setProperty("dubbo.application.name", ""); + System.setProperty("dubbo.application.owner", ""); + System.setProperty("dubbo.registry.address", ""); + System.setProperty("dubbo.protocol.name", ""); + System.setProperty("dubbo.protocol.port", ""); + } + } + + @Test + public void testSystemPropertyOverrideApi() throws Exception { + System.setProperty("dubbo.application.name", "sysover"); + System.setProperty("dubbo.application.owner", "sysowner"); + System.setProperty("dubbo.registry.address", "N/A"); + System.setProperty("dubbo.protocol.name", "dubbo"); + System.setProperty("dubbo.protocol.port", "20834"); + try { + ApplicationConfig application = new ApplicationConfig(); + application.setName("aaa"); + + RegistryConfig registry = new RegistryConfig(); + registry.setAddress("127.0.0.1"); + + ProtocolConfig protocol = new ProtocolConfig(); + protocol.setName("rmi"); + protocol.setPort(1099); + + ServiceConfig service = new ServiceConfig(); + service.setInterface(DemoService.class); + service.setRef(new DemoServiceImpl()); + service.setApplication(application); + service.setRegistry(registry); + service.setProtocol(protocol); + service.export(); + + try { + URL url = service.toUrls().get(0); + assertEquals("sysover", url.getParameter("application")); + assertEquals("sysowner", url.getParameter("owner")); + assertEquals("dubbo", url.getProtocol()); + assertEquals(20834, url.getPort()); + } finally { + service.unexport(); + } + } finally { + System.setProperty("dubbo.application.name", ""); + System.setProperty("dubbo.application.owner", ""); + System.setProperty("dubbo.registry.address", ""); + System.setProperty("dubbo.protocol.name", ""); + System.setProperty("dubbo.protocol.port", ""); + } + } + + @Test + public void testSystemPropertyOverrideProperties() throws Exception { + String portString = System.getProperty("dubbo.protocol.port"); + System.clearProperty("dubbo.protocol.port"); + try { + int port = 1234; + System.setProperty("dubbo.protocol.port", String.valueOf(port)); + ApplicationConfig application = new ApplicationConfig(); + application.setName("aaa"); + + RegistryConfig registry = new RegistryConfig(); + registry.setAddress("N/A"); + + ProtocolConfig protocol = new ProtocolConfig(); + protocol.setName("rmi"); + + ServiceConfig service = new ServiceConfig(); + service.setInterface(DemoService.class); + service.setRef(new DemoServiceImpl()); + service.setApplication(application); + service.setRegistry(registry); + service.setProtocol(protocol); + service.export(); + + try { + URL url = service.toUrls().get(0); + // from api + assertEquals("aaa", url.getParameter("application")); + // from dubbo.properties + assertEquals("world", url.getParameter("owner")); + // from system property + assertEquals(1234, url.getPort()); + } finally { + service.unexport(); + } + } finally { + if (portString != null) { + System.setProperty("dubbo.protocol.port", portString); + } + } + } + + @Test + @SuppressWarnings("unchecked") + public void testCustomizeParameter() throws Exception { + ClassPathXmlApplicationContext context = + new ClassPathXmlApplicationContext(ConfigTest.class.getPackage().getName().replace('.', '/') + "/customize-parameter.xml"); + context.start(); + ServiceBean serviceBean = (ServiceBean) context.getBean("demoServiceExport"); + URL url = (URL) serviceBean.toUrls().get(0); + assertEquals("protocol-paramA", url.getParameter("protocol.paramA")); + assertEquals("service-paramA", url.getParameter("service.paramA")); + } + + @Test + public void testPath() throws Exception { + ServiceConfig service = new ServiceConfig(); + service.setPath("a/b$c"); + try { + service.setPath("a?b"); + fail(); + } catch (IllegalStateException e) { + assertTrue(e.getMessage().contains("")); + } + } + + @Test + public void testAnnotation() { + SimpleRegistryService registryService = new SimpleRegistryService(); + Exporter exporter = SimpleRegistryExporter.export(4548, registryService); + try { + ClassPathXmlApplicationContext providerContext = new ClassPathXmlApplicationContext(ConfigTest.class.getPackage().getName().replace('.', '/') + "/annotation-provider.xml"); + providerContext.start(); + try { + ClassPathXmlApplicationContext consumerContext = new ClassPathXmlApplicationContext(ConfigTest.class.getPackage().getName().replace('.', '/') + "/annotation-consumer.xml"); + consumerContext.start(); + try { + AnnotationAction annotationAction = (AnnotationAction) consumerContext.getBean("annotationAction"); + String hello = annotationAction.doSayName("hello"); + assertEquals("annotation:hello", hello); + } finally { + consumerContext.stop(); + consumerContext.close(); + } + } finally { + providerContext.stop(); + providerContext.close(); + } + } finally { + exporter.unexport(); + } + } + + @Test + public void testDubboProtocolPortOverride() throws Exception { + String dubboPort = System.getProperty("dubbo.protocol.dubbo.port"); + int port = 55555; + System.setProperty("dubbo.protocol.dubbo.port", String.valueOf(port)); + ServiceConfig service = null; + try { + ApplicationConfig application = new ApplicationConfig(); + application.setName("dubbo-protocol-port-override"); + + RegistryConfig registry = new RegistryConfig(); + registry.setAddress("N/A"); + + ProtocolConfig protocol = new ProtocolConfig(); + + service = new ServiceConfig(); + service.setInterface(DemoService.class); + service.setRef(new DemoServiceImpl()); + service.setApplication(application); + service.setRegistry(registry); + service.setProtocol(protocol); + service.export(); + + Assert.assertEquals(port, service.getExportedUrls().get(0).getPort()); + } finally { + if (StringUtils.isNotEmpty(dubboPort)) { + System.setProperty("dubbo.protocol.dubbo.port", dubboPort); + } + if (service != null) { + service.unexport(); + } + } + } + + @Test + public void testProtocolRandomPort() throws Exception { + ServiceConfig demoService = null; + ServiceConfig helloService = null; + + ApplicationConfig application = new ApplicationConfig(); + application.setName("test-protocol-random-port"); + + RegistryConfig registry = new RegistryConfig(); + registry.setAddress("N/A"); + + ProtocolConfig protocol = new ProtocolConfig(); + protocol.setName("dubbo"); + protocol.setPort(-1); + + demoService = new ServiceConfig(); + demoService.setInterface(DemoService.class); + demoService.setRef(new DemoServiceImpl()); + demoService.setApplication(application); + demoService.setRegistry(registry); + demoService.setProtocol(protocol); + + helloService = new ServiceConfig(); + helloService.setInterface(HelloService.class); + helloService.setRef(new HelloServiceImpl()); + helloService.setApplication(application); + helloService.setRegistry(registry); + helloService.setProtocol(protocol); + + try { + demoService.export(); + helloService.export(); + + Assert.assertEquals(demoService.getExportedUrls().get(0).getPort(), + helloService.getExportedUrls().get(0).getPort()); + } finally { + unexportService(demoService); + unexportService(helloService); + } + } + + @Test + public void testReferGenericExport() throws Exception { + ApplicationConfig ac = new ApplicationConfig("test-refer-generic-export"); + RegistryConfig rc = new RegistryConfig(); + rc.setAddress(RegistryConfig.NO_AVAILABLE); + + ServiceConfig sc = new ServiceConfig(); + sc.setApplication(ac); + sc.setRegistry(rc); + sc.setInterface(DemoService.class.getName()); + sc.setRef(new GenericService() { + + public Object $invoke(String method, String[] parameterTypes, Object[] args) throws GenericException { + return null; + } + }); + + ReferenceConfig ref = new ReferenceConfig(); + ref.setApplication(ac); + ref.setRegistry(rc); + ref.setInterface(DemoService.class.getName()); + + try { + sc.export(); + ref.get(); + Assert.fail(); + } catch (Exception e) { + e.printStackTrace(); + } finally { + sc.unexport(); + ref.destroy(); + } + } + + @Test + public void testGenericServiceConfig() throws Exception { + ServiceConfig service = new ServiceConfig(); + service.setApplication(new ApplicationConfig("test")); + service.setRegistry(new RegistryConfig("mock://localhost")); + service.setInterface(DemoService.class.getName()); + service.setGeneric(Constants.GENERIC_SERIALIZATION_BEAN); + service.setRef(new GenericService() { + + public Object $invoke(String method, String[] parameterTypes, Object[] args) throws GenericException { + return null; + } + }); + try { + service.export(); + Collection collection = MockRegistryFactory.getCachedRegistry(); + MockRegistry registry = (MockRegistry) collection.iterator().next(); + URL url = registry.getRegistered().get(0); + Assert.assertEquals(Constants.GENERIC_SERIALIZATION_BEAN, url.getParameter(Constants.GENERIC_KEY)); + } finally { + MockRegistryFactory.cleanCachedRegistry(); + service.unexport(); + } + } + + @Test + public void testGenericServiceConfigThroughSpring() throws Exception { + ClassPathXmlApplicationContext ctx = new ClassPathXmlApplicationContext(ConfigTest.class.getPackage().getName().replace('.', '/') + "/generic-export.xml"); + try { + ctx.start(); + ServiceConfig serviceConfig = (ServiceConfig) ctx.getBean("dubboDemoService"); + URL url = (URL) serviceConfig.getExportedUrls().get(0); + Assert.assertEquals(Constants.GENERIC_SERIALIZATION_BEAN, url.getParameter(Constants.GENERIC_KEY)); + } finally { + ctx.destroy(); + } + } } \ No newline at end of file diff --git a/dubbo-config/dubbo-config-spring/src/test/java/org/apache/dubbo/config/spring/action/DemoActionByAnnotation.java b/dubbo-config/dubbo-config-spring/src/test/java/org/apache/dubbo/config/spring/action/DemoActionByAnnotation.java index f39ff2e6814..6f0ea410555 100644 --- a/dubbo-config/dubbo-config-spring/src/test/java/org/apache/dubbo/config/spring/action/DemoActionByAnnotation.java +++ b/dubbo-config/dubbo-config-spring/src/test/java/org/apache/dubbo/config/spring/action/DemoActionByAnnotation.java @@ -1,34 +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.config.spring.action; - -import org.apache.dubbo.config.spring.api.DemoService; -import org.springframework.beans.factory.annotation.Autowired; - -/** - * DemoAction - */ -public class DemoActionByAnnotation { - - @Autowired - private DemoService demoService; - - public DemoService getDemoService() { - return demoService; - } - +/* + * 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.spring.action; + +import org.apache.dubbo.config.spring.api.DemoService; + +import org.springframework.beans.factory.annotation.Autowired; + +/** + * DemoAction + */ +public class DemoActionByAnnotation { + + @Autowired + private DemoService demoService; + + public DemoService getDemoService() { + return demoService; + } + } \ No newline at end of file diff --git a/dubbo-config/dubbo-config-spring/src/test/java/org/apache/dubbo/config/spring/annotation/consumer/AnnotationAction.java b/dubbo-config/dubbo-config-spring/src/test/java/org/apache/dubbo/config/spring/annotation/consumer/AnnotationAction.java index be6844532b4..35d94fecf04 100644 --- a/dubbo-config/dubbo-config-spring/src/test/java/org/apache/dubbo/config/spring/annotation/consumer/AnnotationAction.java +++ b/dubbo-config/dubbo-config-spring/src/test/java/org/apache/dubbo/config/spring/annotation/consumer/AnnotationAction.java @@ -1,36 +1,37 @@ -/* - * 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.spring.annotation.consumer; - -import org.apache.dubbo.config.annotation.Reference; -import org.apache.dubbo.config.spring.api.DemoService; -import org.springframework.stereotype.Controller; - -/** - * AnnotationAction - */ -@Controller("annotationAction") -public class AnnotationAction { - - @Reference(version = "1.2") - private DemoService demoService; - - public String doSayName(String name) { - return demoService.sayName(name); - } - +/* + * 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.spring.annotation.consumer; + +import org.apache.dubbo.config.annotation.Reference; +import org.apache.dubbo.config.spring.api.DemoService; + +import org.springframework.stereotype.Controller; + +/** + * AnnotationAction + */ +@Controller("annotationAction") +public class AnnotationAction { + + @Reference(version = "1.2") + private DemoService demoService; + + public String doSayName(String name) { + return demoService.sayName(name); + } + } \ No newline at end of file diff --git a/dubbo-config/dubbo-config-spring/src/test/java/org/apache/dubbo/config/spring/beans/factory/annotation/AnnotationPropertyValuesAdapterTest.java b/dubbo-config/dubbo-config-spring/src/test/java/org/apache/dubbo/config/spring/beans/factory/annotation/AnnotationPropertyValuesAdapterTest.java index 66c7d026d3c..0baa7bbe450 100644 --- a/dubbo-config/dubbo-config-spring/src/test/java/org/apache/dubbo/config/spring/beans/factory/annotation/AnnotationPropertyValuesAdapterTest.java +++ b/dubbo-config/dubbo-config-spring/src/test/java/org/apache/dubbo/config/spring/beans/factory/annotation/AnnotationPropertyValuesAdapterTest.java @@ -21,8 +21,9 @@ import org.apache.dubbo.config.annotation.Reference; import org.apache.dubbo.config.spring.ReferenceBean; import org.apache.dubbo.config.spring.api.DemoService; -import org.junit.jupiter.api.Assertions; -import org.junit.jupiter.api.Test; + +import org.junit.Assert; +import org.junit.Test; import org.springframework.core.annotation.AnnotationUtils; import org.springframework.core.convert.converter.Converter; import org.springframework.core.convert.support.DefaultConversionService; @@ -88,61 +89,60 @@ public Map convert(String[] source) { // System.out.println(referenceBean); - Assertions.assertEquals(DemoService.class, referenceBean.getInterfaceClass()); - Assertions.assertEquals("org.apache.dubbo.config.spring.api.DemoService", referenceBean.getInterface()); - Assertions.assertEquals("1.0.0", referenceBean.getVersion()); - Assertions.assertEquals("group", referenceBean.getGroup()); - Assertions.assertEquals("dubbo://localhost:12345", referenceBean.getUrl()); - Assertions.assertEquals("client", referenceBean.getClient()); - Assertions.assertEquals(true, referenceBean.isGeneric()); - Assertions.assertEquals(true, referenceBean.isInjvm()); - Assertions.assertEquals(false, referenceBean.isCheck()); - Assertions.assertEquals(true, referenceBean.isInit()); - Assertions.assertEquals(true, referenceBean.getLazy()); - Assertions.assertEquals(true, referenceBean.getStubevent()); - Assertions.assertEquals("reconnect", referenceBean.getReconnect()); - Assertions.assertEquals(true, referenceBean.getSticky()); - - Assertions.assertEquals("javassist", referenceBean.getProxy()); - - Assertions.assertEquals("stub", referenceBean.getStub()); - Assertions.assertEquals("failover", referenceBean.getCluster()); - Assertions.assertEquals(Integer.valueOf(1), referenceBean.getConnections()); - Assertions.assertEquals(Integer.valueOf(1), referenceBean.getCallbacks()); - Assertions.assertEquals("onconnect", referenceBean.getOnconnect()); - Assertions.assertEquals("ondisconnect", referenceBean.getOndisconnect()); - Assertions.assertEquals("owner", referenceBean.getOwner()); - Assertions.assertEquals("layer", referenceBean.getLayer()); - Assertions.assertEquals(Integer.valueOf(1), referenceBean.getRetries()); - Assertions.assertEquals("random", referenceBean.getLoadbalance()); - Assertions.assertEquals(true, referenceBean.isAsync()); - Assertions.assertEquals(Integer.valueOf(1), referenceBean.getActives()); - Assertions.assertEquals(true, referenceBean.getSent()); - Assertions.assertEquals("mock", referenceBean.getMock()); - Assertions.assertEquals("validation", referenceBean.getValidation()); - Assertions.assertEquals(Integer.valueOf(2), referenceBean.getTimeout()); - Assertions.assertEquals("cache", referenceBean.getCache()); - Assertions.assertEquals("default,default", referenceBean.getFilter()); - Assertions.assertEquals("default,default", referenceBean.getListener()); - Assertions.assertEquals("protocol", referenceBean.getProtocol()); + Assert.assertEquals(DemoService.class, referenceBean.getInterfaceClass()); + Assert.assertEquals("org.apache.dubbo.config.spring.api.DemoService", referenceBean.getInterface()); + Assert.assertEquals("1.0.0", referenceBean.getVersion()); + Assert.assertEquals("group", referenceBean.getGroup()); + Assert.assertEquals("dubbo://localhost:12345", referenceBean.getUrl()); + Assert.assertEquals("client", referenceBean.getClient()); + Assert.assertEquals(true, referenceBean.isGeneric()); + Assert.assertEquals(true, referenceBean.isInjvm()); + Assert.assertEquals(false, referenceBean.isCheck()); + Assert.assertEquals(true, referenceBean.isInit()); + Assert.assertEquals(true, referenceBean.getLazy()); + Assert.assertEquals(true, referenceBean.getStubevent()); + Assert.assertEquals("reconnect", referenceBean.getReconnect()); + Assert.assertEquals(true, referenceBean.getSticky()); + + Assert.assertEquals("javassist", referenceBean.getProxy()); + + Assert.assertEquals("stub", referenceBean.getStub()); + Assert.assertEquals("failover", referenceBean.getCluster()); + Assert.assertEquals(Integer.valueOf(1), referenceBean.getConnections()); + Assert.assertEquals(Integer.valueOf(1), referenceBean.getCallbacks()); + Assert.assertEquals("onconnect", referenceBean.getOnconnect()); + Assert.assertEquals("ondisconnect", referenceBean.getOndisconnect()); + Assert.assertEquals("owner", referenceBean.getOwner()); + Assert.assertEquals("layer", referenceBean.getLayer()); + Assert.assertEquals(Integer.valueOf(1), referenceBean.getRetries()); + Assert.assertEquals("random", referenceBean.getLoadbalance()); + Assert.assertEquals(true, referenceBean.isAsync()); + Assert.assertEquals(Integer.valueOf(1), referenceBean.getActives()); + Assert.assertEquals(true, referenceBean.getSent()); + Assert.assertEquals("mock", referenceBean.getMock()); + Assert.assertEquals("validation", referenceBean.getValidation()); + Assert.assertEquals(Integer.valueOf(2), referenceBean.getTimeout()); + Assert.assertEquals("cache", referenceBean.getCache()); + Assert.assertEquals("default,default", referenceBean.getFilter()); + Assert.assertEquals("default,default", referenceBean.getListener()); Map data = new LinkedHashMap(); data.put("key1", "value1"); - Assertions.assertEquals(data, referenceBean.getParameters()); + Assert.assertEquals(data, referenceBean.getParameters()); // Bean compare - Assertions.assertEquals(null, referenceBean.getApplication()); - Assertions.assertEquals(null, referenceBean.getModule()); - Assertions.assertEquals(null, referenceBean.getConsumer()); - Assertions.assertEquals(null, referenceBean.getMonitor()); - Assertions.assertEquals(null, referenceBean.getRegistry()); + Assert.assertEquals(null, referenceBean.getApplication()); + Assert.assertEquals(null, referenceBean.getModule()); + Assert.assertEquals(null, referenceBean.getConsumer()); + Assert.assertEquals(null, referenceBean.getMonitor()); + Assert.assertEquals(null, referenceBean.getRegistry()); } private static class TestBean { @Reference( - interfaceClass = DemoService.class, interfaceName = "org.apache.dubbo.config.spring.api.DemoService", version = "${version}", group = "group", + interfaceClass = DemoService.class, interfaceName = "com.alibaba.dubbo.config.spring.api.DemoService", version = "${version}", group = "group", url = "${url} ", client = "client", generic = true, injvm = true, check = false, init = true, lazy = true, stubevent = true, reconnect = "reconnect", sticky = true, proxy = "javassist", stub = "stub", @@ -151,7 +151,7 @@ private static class TestBean { loadbalance = "random", async = true, actives = 1, sent = true, mock = "mock", validation = "validation", timeout = 2, cache = "cache", filter = {"default", "default"}, listener = {"default", "default"}, parameters = {"key1", "value1"}, application = "application", - module = "module", consumer = "consumer", monitor = "monitor", registry = {"registry1", "registry2"}, protocol = "protocol" + module = "module", consumer = "consumer", monitor = "monitor", registry = {"registry1", "registry2"} ) private DemoService demoService; diff --git a/dubbo-config/dubbo-config-spring/src/test/java/org/apache/dubbo/config/spring/beans/factory/annotation/ReferenceAnnotationBeanPostProcessorTest.java b/dubbo-config/dubbo-config-spring/src/test/java/org/apache/dubbo/config/spring/beans/factory/annotation/ReferenceAnnotationBeanPostProcessorTest.java index b21aefb5fc8..6f626784db3 100644 --- a/dubbo-config/dubbo-config-spring/src/test/java/org/apache/dubbo/config/spring/beans/factory/annotation/ReferenceAnnotationBeanPostProcessorTest.java +++ b/dubbo-config/dubbo-config-spring/src/test/java/org/apache/dubbo/config/spring/beans/factory/annotation/ReferenceAnnotationBeanPostProcessorTest.java @@ -19,78 +19,71 @@ import org.apache.dubbo.config.annotation.Reference; import org.apache.dubbo.config.spring.ReferenceBean; import org.apache.dubbo.config.spring.api.DemoService; -import org.apache.dubbo.config.spring.context.annotation.DubboComponentScan; -import org.junit.jupiter.api.AfterEach; -import org.junit.jupiter.api.Assertions; -import org.junit.jupiter.api.BeforeAll; -import org.junit.jupiter.api.BeforeEach; -import org.junit.jupiter.api.Test; +import org.junit.Assert; +import org.junit.Test; +import org.junit.runner.RunWith; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.InjectionMetadata; import org.springframework.context.ApplicationContext; import org.springframework.context.ConfigurableApplicationContext; -import org.springframework.context.annotation.AnnotationConfigApplicationContext; -import org.springframework.context.annotation.ImportResource; +import org.springframework.context.annotation.Bean; +import org.springframework.test.context.ContextConfiguration; +import org.springframework.test.context.TestPropertySource; +import org.springframework.test.context.junit4.SpringRunner; import java.util.Collection; import java.util.Map; import static org.apache.dubbo.config.spring.beans.factory.annotation.ReferenceAnnotationBeanPostProcessor.BEAN_NAME; -import static org.hamcrest.CoreMatchers.is; -import static org.hamcrest.CoreMatchers.not; -import static org.hamcrest.CoreMatchers.nullValue; -import static org.hamcrest.MatcherAssert.assertThat; /** * {@link ReferenceAnnotationBeanPostProcessor} Test * * @since 2.5.7 */ +@RunWith(SpringRunner.class) +@ContextConfiguration( + classes = { + ServiceAnnotationTestConfiguration.class, + ReferenceAnnotationBeanPostProcessorTest.class + }) +@TestPropertySource(properties = { + "packagesToScan = org.apache.dubbo.config.spring.context.annotation.provider", + "consumer.version = ${demo.service.version}", + "consumer.url = dubbo://127.0.0.1:12345", +}) public class ReferenceAnnotationBeanPostProcessorTest { - private ConfigurableApplicationContext providerApplicationContext; - - @BeforeAll - public static void prepare() { - System.setProperty("provider.version", "1.2"); - System.setProperty("package1", "org.apache.dubbo.config.spring.annotation.provider"); - System.setProperty("packagesToScan", "${package1}"); - System.setProperty("consumer.version", "1.2"); - System.setProperty("consumer.url", "dubbo://127.0.0.1:12345"); + @Bean + public TestBean testBean() { + return new TestBean(); } - @BeforeEach - public void init() { - // Starts Provider - providerApplicationContext = new AnnotationConfigApplicationContext(ServiceAnnotationBeanPostProcessorTest.TestConfiguration.class); + @Bean(BEAN_NAME) + public ReferenceAnnotationBeanPostProcessor referenceAnnotationBeanPostProcessor() { + return new ReferenceAnnotationBeanPostProcessor(); } - @AfterEach - public void destroy() { - // Shutdowns Provider - providerApplicationContext.close(); - } + @Autowired + private ConfigurableApplicationContext context; @Test public void test() throws Exception { - AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(TestBean.class); - TestBean testBean = context.getBean(TestBean.class); - Assertions.assertNotNull(testBean.getDemoServiceFromAncestor()); - Assertions.assertNotNull(testBean.getDemoServiceFromParent()); - Assertions.assertNotNull(testBean.getDemoService()); - - Assertions.assertEquals(testBean.getDemoServiceFromAncestor(), testBean.getDemoServiceFromParent()); - Assertions.assertEquals(testBean.getDemoService(), testBean.getDemoServiceFromParent()); - DemoService demoService = testBean.getDemoService(); - Assertions.assertEquals("annotation:Mercy", demoService.sayName("Mercy")); + Assert.assertEquals("Hello,Mercy", demoService.sayName("Mercy")); + + Assert.assertNotNull(testBean.getDemoServiceFromAncestor()); + Assert.assertNotNull(testBean.getDemoServiceFromParent()); + Assert.assertNotNull(testBean.getDemoService()); - context.close(); + Assert.assertEquals("Hello,Mercy", testBean.getDemoServiceFromAncestor().sayName("Mercy")); + Assert.assertEquals("Hello,Mercy", testBean.getDemoServiceFromParent().sayName("Mercy")); + Assert.assertEquals("Hello,Mercy", testBean.getDemoService().sayName("Mercy")); } @@ -100,35 +93,24 @@ public void test() throws Exception { @Test public void testGetReferenceBeans() { - AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(TestBean.class); - ReferenceAnnotationBeanPostProcessor beanPostProcessor = context.getBean(BEAN_NAME, ReferenceAnnotationBeanPostProcessor.class); Collection> referenceBeans = beanPostProcessor.getReferenceBeans(); - /** - * 1 -> demoService、demoServiceShouldBeSame - * 1 -> demoServiceShouldNotBeSame - * 1 -> demoServiceWithArray、demoServiceWithArrayShouldBeSame - */ - Assertions.assertEquals(3, referenceBeans.size()); + Assert.assertEquals(1, referenceBeans.size()); ReferenceBean referenceBean = referenceBeans.iterator().next(); TestBean testBean = context.getBean(TestBean.class); - Assertions.assertEquals(referenceBean.get(), testBean.getDemoServiceFromAncestor()); - Assertions.assertEquals(referenceBean.get(), testBean.getDemoServiceFromParent()); - Assertions.assertEquals(referenceBean.get(), testBean.getDemoService()); + Assert.assertNotNull(referenceBean.get()); } @Test public void testGetInjectedFieldReferenceBeanMap() { - AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(TestBean.class); - ReferenceAnnotationBeanPostProcessor beanPostProcessor = context.getBean(BEAN_NAME, ReferenceAnnotationBeanPostProcessor.class); @@ -136,22 +118,19 @@ public void testGetInjectedFieldReferenceBeanMap() { Map> referenceBeanMap = beanPostProcessor.getInjectedFieldReferenceBeanMap(); - /** - * contains 5 fields. - */ - Assertions.assertEquals(5, referenceBeanMap.size()); + Assert.assertEquals(1, referenceBeanMap.size()); for (Map.Entry> entry : referenceBeanMap.entrySet()) { InjectionMetadata.InjectedElement injectedElement = entry.getKey(); - Assertions.assertEquals("org.apache.dubbo.config.spring.beans.factory.annotation.ReferenceAnnotationBeanPostProcessor$ReferenceFieldElement", + Assert.assertEquals("org.apache.dubbo.config.spring.beans.factory.annotation.AnnotationInjectedBeanPostProcessor$AnnotatedFieldElement", injectedElement.getClass().getName()); ReferenceBean referenceBean = entry.getValue(); - Assertions.assertEquals("1.2", referenceBean.getVersion()); - Assertions.assertEquals("dubbo://127.0.0.1:12345", referenceBean.getUrl()); + Assert.assertEquals("2.5.7", referenceBean.getVersion()); + Assert.assertEquals("dubbo://127.0.0.1:12345", referenceBean.getUrl()); } @@ -160,8 +139,6 @@ public void testGetInjectedFieldReferenceBeanMap() { @Test public void testGetInjectedMethodReferenceBeanMap() { - AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(TestBean.class); - ReferenceAnnotationBeanPostProcessor beanPostProcessor = context.getBean(BEAN_NAME, ReferenceAnnotationBeanPostProcessor.class); @@ -169,85 +146,41 @@ public void testGetInjectedMethodReferenceBeanMap() { Map> referenceBeanMap = beanPostProcessor.getInjectedMethodReferenceBeanMap(); - Assertions.assertEquals(2, referenceBeanMap.size()); + Assert.assertEquals(2, referenceBeanMap.size()); for (Map.Entry> entry : referenceBeanMap.entrySet()) { InjectionMetadata.InjectedElement injectedElement = entry.getKey(); - Assertions.assertEquals("org.apache.dubbo.config.spring.beans.factory.annotation.ReferenceAnnotationBeanPostProcessor$ReferenceMethodElement", + Assert.assertEquals("org.apache.dubbo.config.spring.beans.factory.annotation.AnnotationInjectedBeanPostProcessor$AnnotatedMethodElement", injectedElement.getClass().getName()); ReferenceBean referenceBean = entry.getValue(); - Assertions.assertEquals("1.2", referenceBean.getVersion()); - Assertions.assertEquals("dubbo://127.0.0.1:12345", referenceBean.getUrl()); - - } - - } - - @Test - public void testModuleInfo() { - AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(TestBean.class); - - ReferenceAnnotationBeanPostProcessor beanPostProcessor = context.getBean(BEAN_NAME, - ReferenceAnnotationBeanPostProcessor.class); - + Assert.assertEquals("2.5.7", referenceBean.getVersion()); + Assert.assertEquals("dubbo://127.0.0.1:12345", referenceBean.getUrl()); - Map> referenceBeanMap = - beanPostProcessor.getInjectedMethodReferenceBeanMap(); - - for (Map.Entry> entry : referenceBeanMap.entrySet()) { - ReferenceBean referenceBean = entry.getValue(); - - assertThat(referenceBean.getModule().getName(), is("defaultModule")); - assertThat(referenceBean.getMonitor(), not(nullValue())); } - } - - @Test - public void testReferenceCache() throws Exception { - - AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(TestBean.class); - - TestBean testBean = context.getBean(TestBean.class); - - Assertions.assertNotNull(testBean.getDemoServiceFromAncestor()); - Assertions.assertNotNull(testBean.getDemoServiceFromParent()); - Assertions.assertNotNull(testBean.getDemoService()); - - Assertions.assertEquals(testBean.getDemoServiceFromAncestor(), testBean.getDemoServiceFromParent()); - Assertions.assertEquals(testBean.getDemoService(), testBean.getDemoServiceFromParent()); - - DemoService demoService = testBean.getDemoService(); - - Assertions.assertEquals(demoService, testBean.getDemoServiceShouldBeSame()); - Assertions.assertNotEquals(demoService, testBean.getDemoServiceShouldNotBeSame()); - - context.close(); } - @Test - public void testReferenceCacheWithArray() throws Exception { - - AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(TestBean.class); - - TestBean testBean = context.getBean(TestBean.class); - - Assertions.assertNotNull(testBean.getDemoServiceFromAncestor()); - Assertions.assertNotNull(testBean.getDemoServiceFromParent()); - Assertions.assertNotNull(testBean.getDemoService()); - - Assertions.assertEquals(testBean.getDemoServiceFromAncestor(), testBean.getDemoServiceFromParent()); - Assertions.assertEquals(testBean.getDemoService(), testBean.getDemoServiceFromParent()); - - Assertions.assertEquals(testBean.getDemoServiceWithArray(), testBean.getDemoServiceWithArrayShouldBeSame()); - - context.close(); - - } +// @Test +// public void testModuleInfo() { +// +// ReferenceAnnotationBeanPostProcessor beanPostProcessor = context.getBean(BEAN_NAME, +// ReferenceAnnotationBeanPostProcessor.class); +// +// +// Map> referenceBeanMap = +// beanPostProcessor.getInjectedMethodReferenceBeanMap(); +// +// for (Map.Entry> entry : referenceBeanMap.entrySet()) { +// ReferenceBean referenceBean = entry.getValue(); +// +// assertThat(referenceBean.getModule().getName(), is("defaultModule")); +// assertThat(referenceBean.getMonitor(), not(nullValue())); +// } +// } private static class AncestorBean { @@ -261,7 +194,7 @@ public DemoService getDemoServiceFromAncestor() { return demoServiceFromAncestor; } - @Reference(version = "1.2", url = "dubbo://127.0.0.1:12345") + @Reference(version = "2.5.7", url = "dubbo://127.0.0.1:12345") public void setDemoServiceFromAncestor(DemoService demoServiceFromAncestor) { this.demoServiceFromAncestor = demoServiceFromAncestor; } @@ -285,25 +218,10 @@ public DemoService getDemoServiceFromParent() { } - @ImportResource("META-INF/spring/dubbo-annotation-consumer.xml") - @DubboComponentScan(basePackageClasses = ReferenceAnnotationBeanPostProcessorTest.class) static class TestBean extends ParentBean { private DemoService demoService; - @Reference(version = "1.2", url = "dubbo://127.0.0.1:12345") - private DemoService demoServiceShouldBeSame; - - @Reference(version = "1.2", url = "dubbo://127.0.0.1:12345", async = true) - private DemoService demoServiceShouldNotBeSame; - - - @Reference(version = "1.2", url = "dubbo://127.0.0.1:12345", parameters = {"key1", "value1"}) - private DemoService demoServiceWithArray; - - @Reference(version = "1.2", url = "dubbo://127.0.0.1:12345", parameters = {"key1", "value1"}) - private DemoService demoServiceWithArrayShouldBeSame; - @Autowired private ApplicationContext applicationContext; @@ -311,26 +229,10 @@ public DemoService getDemoService() { return demoService; } - @Reference(version = "1.2", url = "dubbo://127.0.0.1:12345") + @Reference(version = "2.5.7", url = "dubbo://127.0.0.1:12345") public void setDemoService(DemoService demoService) { this.demoService = demoService; } - - public DemoService getDemoServiceShouldNotBeSame() { - return demoServiceShouldNotBeSame; - } - - public DemoService getDemoServiceShouldBeSame() { - return demoServiceShouldBeSame; - } - - public DemoService getDemoServiceWithArray() { - return demoServiceWithArray; - } - - public DemoService getDemoServiceWithArrayShouldBeSame() { - return demoServiceWithArrayShouldBeSame; - } } } \ No newline at end of file diff --git a/dubbo-config/dubbo-config-spring/src/test/java/org/apache/dubbo/config/spring/beans/factory/annotation/ReferenceBeanBuilderTest.java b/dubbo-config/dubbo-config-spring/src/test/java/org/apache/dubbo/config/spring/beans/factory/annotation/ReferenceBeanBuilderTest.java new file mode 100644 index 00000000000..27f6c9663ed --- /dev/null +++ b/dubbo-config/dubbo-config-spring/src/test/java/org/apache/dubbo/config/spring/beans/factory/annotation/ReferenceBeanBuilderTest.java @@ -0,0 +1,126 @@ +/* + * 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.spring.beans.factory.annotation; + + +import org.apache.dubbo.config.annotation.Reference; +import org.apache.dubbo.config.spring.ReferenceBean; + +import org.junit.Assert; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.context.ApplicationContext; +import org.springframework.test.context.ContextConfiguration; +import org.springframework.test.context.junit4.SpringJUnit4ClassRunner; + +import java.util.Collections; +import java.util.HashMap; +import java.util.Map; + +import static org.springframework.core.annotation.AnnotationUtils.findAnnotation; +import static org.springframework.util.ReflectionUtils.findField; + +/** + * {@link ReferenceBeanBuilder} Test + * + * @author Mercy + * @see ReferenceBeanBuilder + * @see Reference + * @since 2.6.4 + */ +@RunWith(SpringJUnit4ClassRunner.class) +@ContextConfiguration(classes = ReferenceBeanBuilderTest.class) +public class ReferenceBeanBuilderTest { + + @Reference( + interfaceClass = CharSequence.class, + interfaceName = "java.lang.CharSequence", + version = "1.0.0", group = "TEST_GROUP", url = "dubbo://localhost:12345", + client = "client", generic = true, injvm = true, + check = false, init = false, lazy = true, + stubevent = true, reconnect = "reconnect", sticky = true, + proxy = "javassist", stub = "java.lang.CharSequence", cluster = "failover", + connections = 3, callbacks = 1, onconnect = "onconnect", ondisconnect = "ondisconnect", + owner = "owner", layer = "layer", retries = 1, + loadbalance = "random", async = true, actives = 3, + sent = true, mock = "mock", validation = "validation", + timeout = 3, cache = "cache", filter = {"echo", "generic", "accesslog"}, + listener = {"deprecated"}, parameters = {"n1=v1 ", "n2 = v2 ", " n3 = v3 "}, + application = "application", + module = "module", consumer = "consumer", monitor = "monitor", registry = {"registry"} + ) + private static final Object TEST_FIELD = new Object(); + + @Autowired + private ApplicationContext context; + + @Test + public void testBuild() throws Exception { + Reference reference = findAnnotation(findField(getClass(), "TEST_FIELD"), Reference.class); + ReferenceBeanBuilder beanBuilder = ReferenceBeanBuilder.create(reference, context.getClassLoader(), context); + beanBuilder.interfaceClass(CharSequence.class); + ReferenceBean referenceBean = beanBuilder.build(); + Assert.assertEquals(CharSequence.class, referenceBean.getInterfaceClass()); + Assert.assertEquals("1.0.0", referenceBean.getVersion()); + Assert.assertEquals("TEST_GROUP", referenceBean.getGroup()); + Assert.assertEquals("dubbo://localhost:12345", referenceBean.getUrl()); + Assert.assertEquals("client", referenceBean.getClient()); + Assert.assertEquals(true, referenceBean.isGeneric()); + Assert.assertEquals(true, referenceBean.isInjvm()); + Assert.assertEquals(false, referenceBean.isCheck()); + Assert.assertEquals(null, referenceBean.isInit()); + Assert.assertEquals(true, referenceBean.getLazy()); + Assert.assertEquals(true, referenceBean.getStubevent()); + Assert.assertEquals("reconnect", referenceBean.getReconnect()); + Assert.assertEquals(true, referenceBean.getSticky()); + Assert.assertEquals("javassist", referenceBean.getProxy()); + Assert.assertEquals("java.lang.CharSequence", referenceBean.getStub()); + Assert.assertEquals("failover", referenceBean.getCluster()); + Assert.assertEquals(Integer.valueOf(3), referenceBean.getConnections()); + Assert.assertEquals(Integer.valueOf(1), referenceBean.getCallbacks()); + Assert.assertEquals("onconnect", referenceBean.getOnconnect()); + Assert.assertEquals("ondisconnect", referenceBean.getOndisconnect()); + Assert.assertEquals("owner", referenceBean.getOwner()); + Assert.assertEquals("layer", referenceBean.getLayer()); + Assert.assertEquals(Integer.valueOf(1), referenceBean.getRetries()); + Assert.assertEquals("random", referenceBean.getLoadbalance()); + Assert.assertEquals(true, referenceBean.isAsync()); + Assert.assertEquals(Integer.valueOf(3), referenceBean.getActives()); + Assert.assertEquals(true, referenceBean.getSent()); + Assert.assertEquals("mock", referenceBean.getMock()); + Assert.assertEquals("validation", referenceBean.getValidation()); + Assert.assertEquals(Integer.valueOf(3), referenceBean.getTimeout()); + Assert.assertEquals("cache", referenceBean.getCache()); + Assert.assertEquals("echo,generic,accesslog", referenceBean.getFilter()); + Assert.assertEquals("deprecated", referenceBean.getListener()); + + // parameters + Map parameters = new HashMap(); + parameters.put("n1", "v1"); + parameters.put("n2", "v2"); + parameters.put("n3", "v3"); + Assert.assertEquals(parameters, referenceBean.getParameters()); + + // Asserts Null fields + Assert.assertNull(referenceBean.getApplication()); + Assert.assertNull(referenceBean.getModule()); + Assert.assertNull(referenceBean.getConsumer()); + Assert.assertNull(referenceBean.getMonitor()); + Assert.assertEquals(Collections.emptyList(), referenceBean.getRegistries()); + } +} diff --git a/dubbo-config/dubbo-config-spring/src/test/java/org/apache/dubbo/config/spring/beans/factory/annotation/ServiceAnnotationBeanPostProcessorTest.java b/dubbo-config/dubbo-config-spring/src/test/java/org/apache/dubbo/config/spring/beans/factory/annotation/ServiceAnnotationBeanPostProcessorTest.java index 300d3dcac2b..22325d96ebf 100644 --- a/dubbo-config/dubbo-config-spring/src/test/java/org/apache/dubbo/config/spring/beans/factory/annotation/ServiceAnnotationBeanPostProcessorTest.java +++ b/dubbo-config/dubbo-config-spring/src/test/java/org/apache/dubbo/config/spring/beans/factory/annotation/ServiceAnnotationBeanPostProcessorTest.java @@ -19,20 +19,16 @@ import org.apache.dubbo.config.spring.ServiceBean; import org.apache.dubbo.config.spring.api.HelloService; -import org.junit.jupiter.api.Assertions; -import org.junit.jupiter.api.Disabled; -import org.junit.jupiter.api.Test; -import org.junit.jupiter.api.extension.ExtendWith; +import org.junit.Assert; +import org.junit.Test; +import org.junit.runner.RunWith; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Value; import org.springframework.beans.factory.config.ConfigurableListableBeanFactory; import org.springframework.context.annotation.Bean; -import org.springframework.context.annotation.ComponentScan; -import org.springframework.context.annotation.ImportResource; -import org.springframework.context.annotation.PropertySource; import org.springframework.test.context.ContextConfiguration; import org.springframework.test.context.TestPropertySource; -import org.springframework.test.context.junit.jupiter.SpringExtension; +import org.springframework.test.context.junit4.SpringRunner; import java.util.Map; @@ -41,60 +37,45 @@ * * @since 2.5.8 */ -@ExtendWith(SpringExtension.class) +@RunWith(SpringRunner.class) @ContextConfiguration( - classes = {ServiceAnnotationBeanPostProcessorTest.TestConfiguration.class}) + classes = { + ServiceAnnotationTestConfiguration.class, + ServiceAnnotationBeanPostProcessorTest.class + }) @TestPropertySource(properties = { - "package1 = org.apache.dubbo.config.spring.context.annotation", - "packagesToScan = ${package1}", - "provider.version = 1.2" + "provider.package = org.apache.dubbo.config.spring.context.annotation.provider", + "packagesToScan = ${provider.package}", }) public class ServiceAnnotationBeanPostProcessorTest { @Autowired private ConfigurableListableBeanFactory beanFactory; - @Disabled -// @Test + @Bean + public ServiceAnnotationBeanPostProcessor serviceAnnotationBeanPostProcessor2 + (@Value("${packagesToScan}") String... packagesToScan) { + return new ServiceAnnotationBeanPostProcessor(packagesToScan); + } + + @Test public void test() { Map helloServicesMap = beanFactory.getBeansOfType(HelloService.class); - Assertions.assertEquals(2, helloServicesMap.size()); + Assert.assertEquals(2, helloServicesMap.size()); Map serviceBeansMap = beanFactory.getBeansOfType(ServiceBean.class); - Assertions.assertEquals(3, serviceBeansMap.size()); + Assert.assertEquals(2, serviceBeansMap.size()); Map beanPostProcessorsMap = beanFactory.getBeansOfType(ServiceAnnotationBeanPostProcessor.class); - Assertions.assertEquals(4, beanPostProcessorsMap.size()); - - Assertions.assertTrue(beanPostProcessorsMap.containsKey("doubleServiceAnnotationBeanPostProcessor")); - Assertions.assertTrue(beanPostProcessorsMap.containsKey("emptyServiceAnnotationBeanPostProcessor")); - Assertions.assertTrue(beanPostProcessorsMap.containsKey("serviceAnnotationBeanPostProcessor")); - Assertions.assertTrue(beanPostProcessorsMap.containsKey("serviceAnnotationBeanPostProcessor2")); - - } - - @ImportResource("META-INF/spring/dubbo-annotation-provider.xml") - @PropertySource("META-INF/default.properties") - @ComponentScan("org.apache.dubbo.config.spring.context.annotation.provider") - public static class TestConfiguration { - - @Bean - public ServiceAnnotationBeanPostProcessor serviceAnnotationBeanPostProcessor - (@Value("${packagesToScan}") String... packagesToScan) { - return new ServiceAnnotationBeanPostProcessor(packagesToScan); - } - - @Bean - public ServiceAnnotationBeanPostProcessor serviceAnnotationBeanPostProcessor2 - (@Value("${packagesToScan}") String... packagesToScan) { - return new ServiceAnnotationBeanPostProcessor(packagesToScan); - } + Assert.assertEquals(2, beanPostProcessorsMap.size()); + Assert.assertTrue(beanPostProcessorsMap.containsKey("serviceAnnotationBeanPostProcessor")); + Assert.assertTrue(beanPostProcessorsMap.containsKey("serviceAnnotationBeanPostProcessor2")); } diff --git a/dubbo-config/dubbo-config-spring/src/test/java/org/apache/dubbo/config/spring/beans/factory/annotation/ServiceAnnotationTestConfiguration.java b/dubbo-config/dubbo-config-spring/src/test/java/org/apache/dubbo/config/spring/beans/factory/annotation/ServiceAnnotationTestConfiguration.java new file mode 100644 index 00000000000..7a206db7852 --- /dev/null +++ b/dubbo-config/dubbo-config-spring/src/test/java/org/apache/dubbo/config/spring/beans/factory/annotation/ServiceAnnotationTestConfiguration.java @@ -0,0 +1,116 @@ +/* + * 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.spring.beans.factory.annotation; + + +import org.apache.dubbo.config.ApplicationConfig; +import org.apache.dubbo.config.ProtocolConfig; +import org.apache.dubbo.config.RegistryConfig; +import org.apache.dubbo.config.annotation.Service; + +import org.springframework.beans.factory.annotation.Value; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Primary; +import org.springframework.context.annotation.PropertySource; +import org.springframework.transaction.PlatformTransactionManager; +import org.springframework.transaction.TransactionDefinition; +import org.springframework.transaction.TransactionException; +import org.springframework.transaction.TransactionStatus; + +/** + * {@link Service} Bean + * + * @since 2.6.5 + */ +@PropertySource("classpath:/META-INF/default.properties") +public class ServiceAnnotationTestConfiguration { + + /** + * Current application configuration, to replace XML config: + * + * <dubbo:application name="dubbo-demo-application"/> + * + * + * @return {@link ApplicationConfig} Bean + */ + @Bean("dubbo-demo-application") + public ApplicationConfig applicationConfig() { + ApplicationConfig applicationConfig = new ApplicationConfig(); + applicationConfig.setName("dubbo-demo-application"); + return applicationConfig; + } + + /** + * Current registry center configuration, to replace XML config: + * + * <dubbo:registry id="my-registry" address="N/A"/> + * + * + * @return {@link RegistryConfig} Bean + */ + @Bean("my-registry") + public RegistryConfig registryConfig() { + RegistryConfig registryConfig = new RegistryConfig(); + registryConfig.setAddress("N/A"); + return registryConfig; + } + + /** + * Current protocol configuration, to replace XML config: + * + * <dubbo:protocol name="dubbo" port="12345"/> + * + * + * @return {@link ProtocolConfig} Bean + */ + @Bean("dubbo") + public ProtocolConfig protocolConfig() { + ProtocolConfig protocolConfig = new ProtocolConfig(); + protocolConfig.setName("dubbo"); + protocolConfig.setPort(12345); + return protocolConfig; + } + + @Primary + @Bean + public PlatformTransactionManager platformTransactionManager() { + return new PlatformTransactionManager() { + + @Override + public TransactionStatus getTransaction(TransactionDefinition definition) throws TransactionException { + return null; + } + + @Override + public void commit(TransactionStatus status) throws TransactionException { + + } + + @Override + public void rollback(TransactionStatus status) throws TransactionException { + + } + }; + } + + @Bean + public ServiceAnnotationBeanPostProcessor serviceAnnotationBeanPostProcessor + (@Value("${packagesToScan}") String... packagesToScan) { + return new ServiceAnnotationBeanPostProcessor(packagesToScan); + } + +} \ No newline at end of file diff --git a/dubbo-config/dubbo-config-spring/src/test/java/org/apache/dubbo/config/spring/beans/factory/annotation/ServiceBeanNameBuilderTest.java b/dubbo-config/dubbo-config-spring/src/test/java/org/apache/dubbo/config/spring/beans/factory/annotation/ServiceBeanNameBuilderTest.java new file mode 100644 index 00000000000..b3616cd58a3 --- /dev/null +++ b/dubbo-config/dubbo-config-spring/src/test/java/org/apache/dubbo/config/spring/beans/factory/annotation/ServiceBeanNameBuilderTest.java @@ -0,0 +1,75 @@ +/* + * 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.spring.beans.factory.annotation; + + +import org.apache.dubbo.config.annotation.Reference; +import org.apache.dubbo.config.annotation.Service; +import org.apache.dubbo.config.spring.api.DemoService; + +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.Test; +import org.springframework.core.annotation.AnnotationUtils; +import org.springframework.mock.env.MockEnvironment; +import org.springframework.util.ReflectionUtils; + + +/** + * {@link ServiceBeanNameBuilder} Test + * + * @see ServiceBeanNameBuilder + * @since 2.6.5 + */ +@Service(interfaceClass = DemoService.class, group = ServiceBeanNameBuilderTest.GROUP, version = ServiceBeanNameBuilderTest.VERSION, + application = "application", module = "module", registry = {"1", "2", "3"}) +public class ServiceBeanNameBuilderTest { + + @Reference(interfaceClass = DemoService.class, group = "DUBBO", version = "1.0.0", + application = "application", module = "module", registry = {"1", "2", "3"}) + static final Class INTERFACE_CLASS = DemoService.class; + + static final String GROUP = "DUBBO"; + + static final String VERSION = "1.0.0"; + + static final String BEAN_NAME = "ServiceBean:org.apache.dubbo.config.spring.api.DemoService:1.0.0:DUBBO"; + + private MockEnvironment environment = new MockEnvironment(); + + @Test + public void testRequiredAttributes() { + ServiceBeanNameBuilder builder = ServiceBeanNameBuilder.create(INTERFACE_CLASS, environment); + Assertions.assertEquals("ServiceBean:org.apache.dubbo.config.spring.api.DemoService", builder.build()); + } + + @Test + public void testServiceAnnotation() { + Service service = AnnotationUtils.getAnnotation(ServiceBeanNameBuilderTest.class, Service.class); + ServiceBeanNameBuilder builder = ServiceBeanNameBuilder.create(service, INTERFACE_CLASS, environment); + Assertions.assertEquals(BEAN_NAME, + builder.build()); + } + + @Test + public void testReferenceAnnotation() { + Reference reference = AnnotationUtils.getAnnotation(ReflectionUtils.findField(ServiceBeanNameBuilderTest.class, "INTERFACE_CLASS"), Reference.class); + ServiceBeanNameBuilder builder = ServiceBeanNameBuilder.create(reference, INTERFACE_CLASS, environment); + Assertions.assertEquals(BEAN_NAME, + builder.build()); + } + +} diff --git a/dubbo-config/dubbo-config-spring/src/test/java/org/apache/dubbo/config/spring/beans/factory/config/YamlPropertySourceFactory.java b/dubbo-config/dubbo-config-spring/src/test/java/org/apache/dubbo/config/spring/beans/factory/config/YamlPropertySourceFactory.java new file mode 100644 index 00000000000..c9b44c94ad1 --- /dev/null +++ b/dubbo-config/dubbo-config-spring/src/test/java/org/apache/dubbo/config/spring/beans/factory/config/YamlPropertySourceFactory.java @@ -0,0 +1,76 @@ +/* + * 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.spring.beans.factory.config; + +import org.springframework.beans.factory.config.YamlProcessor; +import org.springframework.core.env.MapPropertySource; +import org.springframework.core.env.PropertySource; +import org.springframework.core.io.support.EncodedResource; +import org.springframework.core.io.support.PropertySourceFactory; +import org.yaml.snakeyaml.DumperOptions; +import org.yaml.snakeyaml.Yaml; +import org.yaml.snakeyaml.nodes.Tag; +import org.yaml.snakeyaml.representer.Representer; +import org.yaml.snakeyaml.resolver.Resolver; + +import java.io.IOException; +import java.util.LinkedHashMap; +import java.util.Map; +import java.util.Properties; +import java.util.regex.Pattern; + +/** + * YAML {@link PropertySourceFactory} implementation, some source code is copied Spring Boot + * org.springframework.boot.env.YamlPropertySourceLoader , see {@link #createYaml()} and {@link #process()} + * + * @since 2.6.5 + */ +public class YamlPropertySourceFactory extends YamlProcessor implements PropertySourceFactory { + + @Override + public PropertySource createPropertySource(String name, EncodedResource resource) throws IOException { + setResources(resource.getResource()); + return new MapPropertySource(name, process()); + } + + @Override + protected Yaml createYaml() { + return new Yaml(new StrictMapAppenderConstructor(), new Representer(), + new DumperOptions(), new Resolver() { + @Override + public void addImplicitResolver(Tag tag, Pattern regexp, + String first) { + if (tag == Tag.TIMESTAMP) { + return; + } + super.addImplicitResolver(tag, regexp, first); + } + }); + } + + public Map process() { + final Map result = new LinkedHashMap(); + process(new MatchCallback() { + @Override + public void process(Properties properties, Map map) { + result.putAll(getFlattenedMap(map)); + } + }); + return result; + } + +} diff --git a/dubbo-config/dubbo-config-spring/src/test/java/org/apache/dubbo/config/spring/beans/factory/config/YamlPropertySourceFactoryTest.java b/dubbo-config/dubbo-config-spring/src/test/java/org/apache/dubbo/config/spring/beans/factory/config/YamlPropertySourceFactoryTest.java new file mode 100644 index 00000000000..a9861d33c1b --- /dev/null +++ b/dubbo-config/dubbo-config-spring/src/test/java/org/apache/dubbo/config/spring/beans/factory/config/YamlPropertySourceFactoryTest.java @@ -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.config.spring.beans.factory.config; + +import org.junit.Assert; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.context.annotation.Configuration; +import org.springframework.context.annotation.PropertySource; +import org.springframework.core.env.Environment; +import org.springframework.test.context.ContextConfiguration; +import org.springframework.test.context.junit4.SpringRunner; + +/** + * {@link YamlPropertySourceFactory} Test + * + * @since 2.6.5 + */ +@RunWith(SpringRunner.class) +@PropertySource(name = "yaml-source", value = {"classpath:/META-INF/dubbo.yml"}, factory = YamlPropertySourceFactory.class) +@Configuration +@ContextConfiguration(classes = YamlPropertySourceFactoryTest.class) +public class YamlPropertySourceFactoryTest { + + @Autowired + private Environment environment; + + @Value("${dubbo.consumer.default}") + private Boolean isDefault; + + @Value("${dubbo.consumer.client}") + private String client; + + @Value("${dubbo.consumer.threadpool}") + private String threadPool; + + @Value("${dubbo.consumer.corethreads}") + private Integer coreThreads; + + @Value("${dubbo.consumer.threads}") + private Integer threads; + + @Value("${dubbo.consumer.queues}") + private Integer queues; + + @Test + public void testProperty() { + Assert.assertEquals(isDefault, environment.getProperty("dubbo.consumer.default", Boolean.class)); + Assert.assertEquals(client, environment.getProperty("dubbo.consumer.client", String.class)); + Assert.assertEquals(threadPool, environment.getProperty("dubbo.consumer.threadpool", String.class)); + Assert.assertEquals(coreThreads, environment.getProperty("dubbo.consumer.corethreads", Integer.class)); + Assert.assertEquals(threads, environment.getProperty("dubbo.consumer.threads", Integer.class)); + Assert.assertEquals(queues, environment.getProperty("dubbo.consumer.queues", Integer.class)); + } +} diff --git a/dubbo-config/dubbo-config-spring/src/test/java/org/apache/dubbo/config/spring/context/annotation/DubboComponentScanRegistrarTest.java b/dubbo-config/dubbo-config-spring/src/test/java/org/apache/dubbo/config/spring/context/annotation/DubboComponentScanRegistrarTest.java index e9d9e1806b0..a6d219ad803 100644 --- a/dubbo-config/dubbo-config-spring/src/test/java/org/apache/dubbo/config/spring/context/annotation/DubboComponentScanRegistrarTest.java +++ b/dubbo-config/dubbo-config-spring/src/test/java/org/apache/dubbo/config/spring/context/annotation/DubboComponentScanRegistrarTest.java @@ -16,11 +16,15 @@ */ package org.apache.dubbo.config.spring.context.annotation; +import org.apache.dubbo.config.context.ConfigManager; import org.apache.dubbo.config.spring.api.DemoService; import org.apache.dubbo.config.spring.context.annotation.consumer.ConsumerConfiguration; import org.apache.dubbo.config.spring.context.annotation.provider.DemoServiceImpl; import org.apache.dubbo.config.spring.context.annotation.provider.ProviderConfiguration; + +import org.junit.jupiter.api.AfterEach; import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; import org.springframework.aop.support.AopUtils; import org.springframework.context.annotation.AnnotationConfigApplicationContext; @@ -35,6 +39,16 @@ */ public class DubboComponentScanRegistrarTest { + @BeforeEach + public void setUp() { + ConfigManager.getInstance().clear(); + } + + @AfterEach + public void tearDown() { + ConfigManager.getInstance().clear(); + } + @Test public void test() { diff --git a/dubbo-config/dubbo-config-spring/src/test/java/org/apache/dubbo/config/spring/context/annotation/DubboConfigConfigurationTest.java b/dubbo-config/dubbo-config-spring/src/test/java/org/apache/dubbo/config/spring/context/annotation/DubboConfigConfigurationTest.java index 83a8245125d..a0e9b48c60a 100644 --- a/dubbo-config/dubbo-config-spring/src/test/java/org/apache/dubbo/config/spring/context/annotation/DubboConfigConfigurationTest.java +++ b/dubbo-config/dubbo-config-spring/src/test/java/org/apache/dubbo/config/spring/context/annotation/DubboConfigConfigurationTest.java @@ -20,10 +20,12 @@ import org.apache.dubbo.config.ModuleConfig; import org.apache.dubbo.config.ProtocolConfig; import org.apache.dubbo.config.RegistryConfig; + import org.junit.jupiter.api.AfterEach; import org.junit.jupiter.api.Assertions; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; + import org.springframework.context.annotation.AnnotationConfigApplicationContext; import org.springframework.core.io.support.ResourcePropertySource; diff --git a/dubbo-config/dubbo-config-spring/src/test/java/org/apache/dubbo/config/spring/context/annotation/EnableDubboConfigTest.java b/dubbo-config/dubbo-config-spring/src/test/java/org/apache/dubbo/config/spring/context/annotation/EnableDubboConfigTest.java index 12a538dbb6e..5f52a3e0ec0 100644 --- a/dubbo-config/dubbo-config-spring/src/test/java/org/apache/dubbo/config/spring/context/annotation/EnableDubboConfigTest.java +++ b/dubbo-config/dubbo-config-spring/src/test/java/org/apache/dubbo/config/spring/context/annotation/EnableDubboConfigTest.java @@ -23,8 +23,10 @@ import org.apache.dubbo.config.ProtocolConfig; import org.apache.dubbo.config.ProviderConfig; import org.apache.dubbo.config.RegistryConfig; + import org.junit.jupiter.api.Assertions; import org.junit.jupiter.api.Test; + import org.springframework.context.annotation.AnnotationConfigApplicationContext; import org.springframework.context.annotation.PropertySource; diff --git a/dubbo-config/dubbo-config-spring/src/test/java/org/apache/dubbo/config/spring/context/annotation/EnableDubboTest.java b/dubbo-config/dubbo-config-spring/src/test/java/org/apache/dubbo/config/spring/context/annotation/EnableDubboTest.java index e2409941a40..b61198949c0 100644 --- a/dubbo-config/dubbo-config-spring/src/test/java/org/apache/dubbo/config/spring/context/annotation/EnableDubboTest.java +++ b/dubbo-config/dubbo-config-spring/src/test/java/org/apache/dubbo/config/spring/context/annotation/EnableDubboTest.java @@ -16,12 +16,15 @@ */ package org.apache.dubbo.config.spring.context.annotation; -import org.apache.dubbo.config.ApplicationConfig; import org.apache.dubbo.config.RegistryConfig; +import org.apache.dubbo.config.context.ConfigManager; import org.apache.dubbo.config.spring.api.DemoService; import org.apache.dubbo.config.spring.context.annotation.consumer.test.TestConsumerConfiguration; import org.apache.dubbo.config.spring.context.annotation.provider.DemoServiceImpl; + +import org.junit.jupiter.api.AfterEach; import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; import org.springframework.aop.support.AopUtils; import org.springframework.context.annotation.AnnotationConfigApplicationContext; @@ -45,16 +48,28 @@ */ public class EnableDubboTest { - @Test - public void test() { + private AnnotationConfigApplicationContext context; - AnnotationConfigApplicationContext providerContext = new AnnotationConfigApplicationContext(); + @BeforeEach + public void setUp() { + ConfigManager.getInstance().clear(); + context = new AnnotationConfigApplicationContext(); + } - providerContext.register(TestProviderConfiguration.class); + @AfterEach + public void tearDown() { + ConfigManager.getInstance().clear(); + context.close(); + } - providerContext.refresh(); + @Test + public void testProvider() { - DemoService demoService = providerContext.getBean(DemoService.class); + context.register(TestProviderConfiguration.class); + + context.refresh(); + + DemoService demoService = context.getBean(DemoService.class); String value = demoService.sayName("Mercy"); @@ -68,21 +83,24 @@ public void test() { // Test @Transactional is present or not Assertions.assertNotNull(findAnnotation(beanClass, Transactional.class)); - AnnotationConfigApplicationContext consumerContext = new AnnotationConfigApplicationContext(); + } + + @Test + public void testConsumer() { - consumerContext.register(TestConsumerConfiguration.class); + context.register(TestProviderConfiguration.class, TestConsumerConfiguration.class); - consumerContext.refresh(); + context.refresh(); - TestConsumerConfiguration consumerConfiguration = consumerContext.getBean(TestConsumerConfiguration.class); + TestConsumerConfiguration consumerConfiguration = context.getBean(TestConsumerConfiguration.class); - demoService = consumerConfiguration.getDemoService(); + DemoService demoService = consumerConfiguration.getDemoService(); - value = demoService.sayName("Mercy"); + String value = demoService.sayName("Mercy"); Assertions.assertEquals("Hello,Mercy", value); - TestConsumerConfiguration.Child child = consumerContext.getBean(TestConsumerConfiguration.Child.class); + TestConsumerConfiguration.Child child = context.getBean(TestConsumerConfiguration.Child.class); // From Child @@ -114,28 +132,17 @@ public void test() { Assertions.assertEquals("Hello,Mercy", value); - // Test dubbo-annotation-consumer2 bean presentation - - ApplicationConfig applicationConfig = consumerContext.getBean("dubbo-annotation-consumer2", ApplicationConfig.class); - - // Test multiple binding - Assertions.assertEquals("dubbo-consumer2", applicationConfig.getName()); - - // Test dubbo-annotation-consumer2 bean presentation - RegistryConfig registryConfig = consumerContext.getBean("my-registry2", RegistryConfig.class); + // Test my-registry2 bean presentation + RegistryConfig registryConfig = context.getBean("my-registry2", RegistryConfig.class); // Test multiple binding Assertions.assertEquals("N/A", registryConfig.getAddress()); - providerContext.close(); - consumerContext.close(); - - } @EnableDubbo(scanBasePackages = "org.apache.dubbo.config.spring.context.annotation.provider") @ComponentScan(basePackages = "org.apache.dubbo.config.spring.context.annotation.provider") - @PropertySource("META-INF/dubbb-provider.properties") + @PropertySource("classpath:/META-INF/dubbo-provider.properties") @EnableTransactionManagement public static class TestProviderConfiguration { diff --git a/dubbo-config/dubbo-config-spring/src/test/java/org/apache/dubbo/config/spring/context/annotation/consumer/ConsumerConfiguration.java b/dubbo-config/dubbo-config-spring/src/test/java/org/apache/dubbo/config/spring/context/annotation/consumer/ConsumerConfiguration.java index 4fb941fd8ce..c12d4d3bab1 100644 --- a/dubbo-config/dubbo-config-spring/src/test/java/org/apache/dubbo/config/spring/context/annotation/consumer/ConsumerConfiguration.java +++ b/dubbo-config/dubbo-config-spring/src/test/java/org/apache/dubbo/config/spring/context/annotation/consumer/ConsumerConfiguration.java @@ -21,6 +21,7 @@ import org.apache.dubbo.config.annotation.Reference; import org.apache.dubbo.config.spring.api.DemoService; import org.apache.dubbo.config.spring.context.annotation.DubboComponentScan; + import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.context.annotation.PropertySource; @@ -35,15 +36,15 @@ public class ConsumerConfiguration { /** * Current application configuration, to replace XML config: * - * <dubbo:application name="dubbo-annotation-consumer"/> + * <dubbo:application name="dubbo-demo-application"/> * * * @return {@link ApplicationConfig} Bean */ - @Bean("dubbo-annotation-consumer") + @Bean("dubbo-demo-application") public ApplicationConfig applicationConfig() { ApplicationConfig applicationConfig = new ApplicationConfig(); - applicationConfig.setName("dubbo-annotation-consumer"); + applicationConfig.setName("dubbo-demo-application"); return applicationConfig; } diff --git a/dubbo-config/dubbo-config-spring/src/test/java/org/apache/dubbo/config/spring/context/annotation/consumer/test/TestConsumerConfiguration.java b/dubbo-config/dubbo-config-spring/src/test/java/org/apache/dubbo/config/spring/context/annotation/consumer/test/TestConsumerConfiguration.java index 866964d4fdc..231754501f8 100644 --- a/dubbo-config/dubbo-config-spring/src/test/java/org/apache/dubbo/config/spring/context/annotation/consumer/test/TestConsumerConfiguration.java +++ b/dubbo-config/dubbo-config-spring/src/test/java/org/apache/dubbo/config/spring/context/annotation/consumer/test/TestConsumerConfiguration.java @@ -19,6 +19,7 @@ import org.apache.dubbo.config.annotation.Reference; import org.apache.dubbo.config.spring.api.DemoService; import org.apache.dubbo.config.spring.context.annotation.EnableDubbo; + import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.PropertySource; import org.springframework.transaction.annotation.EnableTransactionManagement; @@ -29,11 +30,11 @@ * @since 2.5.7 */ @EnableDubbo(scanBasePackageClasses = TestConsumerConfiguration.class, multipleConfig = true) -@PropertySource("META-INF/dubbb-consumer.properties") +@PropertySource("classpath:/META-INF/dubbb-consumer.properties") @EnableTransactionManagement public class TestConsumerConfiguration { - @Reference(version = "2.5.7", url = "dubbo://127.0.0.1:12345", application = "dubbo-annotation-consumer") + @Reference(version = "2.5.7", url = "dubbo://127.0.0.1:12345", application = "dubbo-demo-application") private DemoService demoService; public DemoService getDemoService() { @@ -52,7 +53,7 @@ public TestConsumerConfiguration.Child c() { public static abstract class Ancestor { - @Reference(version = "2.5.7", url = "dubbo://127.0.0.1:12345", application = "dubbo-annotation-consumer") + @Reference(version = "2.5.7", url = "dubbo://127.0.0.1:12345", application = "dubbo-demo-application") private DemoService demoServiceFromAncestor; public DemoService getDemoServiceFromAncestor() { @@ -72,7 +73,7 @@ public DemoService getDemoServiceFromParent() { return demoServiceFromParent; } - @Reference(version = "2.5.7", url = "dubbo://127.0.0.1:12345", application = "dubbo-annotation-consumer") + @Reference(version = "2.5.7", url = "dubbo://127.0.0.1:12345", application = "dubbo-demo-application") public void setDemoServiceFromParent(DemoService demoServiceFromParent) { this.demoServiceFromParent = demoServiceFromParent; } @@ -81,7 +82,7 @@ public void setDemoServiceFromParent(DemoService demoServiceFromParent) { public static class Child extends TestConsumerConfiguration.Parent { - @Reference(version = "2.5.7", url = "dubbo://127.0.0.1:12345", application = "dubbo-annotation-consumer") + @Reference(version = "2.5.7", url = "dubbo://127.0.0.1:12345", application = "dubbo-demo-application") private DemoService demoServiceFromChild; public DemoService getDemoServiceFromChild() { diff --git a/dubbo-config/dubbo-config-spring/src/test/java/org/apache/dubbo/config/spring/context/annotation/provider/DefaultHelloService.java b/dubbo-config/dubbo-config-spring/src/test/java/org/apache/dubbo/config/spring/context/annotation/provider/DefaultHelloService.java index bb5c7fd4c17..f7923644095 100644 --- a/dubbo-config/dubbo-config-spring/src/test/java/org/apache/dubbo/config/spring/context/annotation/provider/DefaultHelloService.java +++ b/dubbo-config/dubbo-config-spring/src/test/java/org/apache/dubbo/config/spring/context/annotation/provider/DefaultHelloService.java @@ -17,6 +17,7 @@ package org.apache.dubbo.config.spring.context.annotation.provider; import org.apache.dubbo.config.spring.api.HelloService; + import org.springframework.stereotype.Service; /** diff --git a/dubbo-config/dubbo-config-spring/src/test/java/org/apache/dubbo/config/spring/context/annotation/provider/DemoServiceImpl.java b/dubbo-config/dubbo-config-spring/src/test/java/org/apache/dubbo/config/spring/context/annotation/provider/DemoServiceImpl.java index 1b21369f0f7..eb12225588f 100644 --- a/dubbo-config/dubbo-config-spring/src/test/java/org/apache/dubbo/config/spring/context/annotation/provider/DemoServiceImpl.java +++ b/dubbo-config/dubbo-config-spring/src/test/java/org/apache/dubbo/config/spring/context/annotation/provider/DemoServiceImpl.java @@ -18,6 +18,7 @@ import org.apache.dubbo.config.spring.api.Box; import org.apache.dubbo.config.spring.api.DemoService; + import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; diff --git a/dubbo-config/dubbo-config-spring/src/test/java/org/apache/dubbo/config/spring/context/annotation/provider/ProviderConfiguration.java b/dubbo-config/dubbo-config-spring/src/test/java/org/apache/dubbo/config/spring/context/annotation/provider/ProviderConfiguration.java index 0bafd9dac60..d168af8bc2b 100644 --- a/dubbo-config/dubbo-config-spring/src/test/java/org/apache/dubbo/config/spring/context/annotation/provider/ProviderConfiguration.java +++ b/dubbo-config/dubbo-config-spring/src/test/java/org/apache/dubbo/config/spring/context/annotation/provider/ProviderConfiguration.java @@ -20,6 +20,7 @@ import org.apache.dubbo.config.ProtocolConfig; import org.apache.dubbo.config.RegistryConfig; import org.apache.dubbo.config.spring.context.annotation.DubboComponentScan; + import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Primary; import org.springframework.context.annotation.PropertySource; @@ -30,22 +31,22 @@ import org.springframework.transaction.annotation.EnableTransactionManagement; @DubboComponentScan(basePackages = "org.apache.dubbo.config.spring.context.annotation.provider") -@PropertySource("META-INF/default.properties") +@PropertySource("classpath:/META-INF/default.properties") @EnableTransactionManagement public class ProviderConfiguration { /** * Current application configuration, to replace XML config: * - * <dubbo:application name="dubbo-annotation-provider"/> + * <dubbo:application name="dubbo-demo-application"/> * * * @return {@link ApplicationConfig} Bean */ - @Bean("dubbo-annotation-provider") + @Bean("dubbo-demo-application") public ApplicationConfig applicationConfig() { ApplicationConfig applicationConfig = new ApplicationConfig(); - applicationConfig.setName("dubbo-annotation-provider"); + applicationConfig.setName("dubbo-demo-application"); return applicationConfig; } diff --git a/dubbo-config/dubbo-config-spring/src/test/java/org/apache/dubbo/config/spring/context/context/annotation/DubboComponentScanRegistrarTest.java b/dubbo-config/dubbo-config-spring/src/test/java/org/apache/dubbo/config/spring/context/context/annotation/DubboComponentScanRegistrarTest.java new file mode 100644 index 00000000000..5d28adfd4a2 --- /dev/null +++ b/dubbo-config/dubbo-config-spring/src/test/java/org/apache/dubbo/config/spring/context/context/annotation/DubboComponentScanRegistrarTest.java @@ -0,0 +1,116 @@ +/* + * 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.spring.context.context.annotation; + +import org.apache.dubbo.config.spring.api.DemoService; +import org.apache.dubbo.config.spring.context.annotation.DubboComponentScanRegistrar; +import org.apache.dubbo.config.spring.context.annotation.consumer.ConsumerConfiguration; +import org.apache.dubbo.config.spring.context.annotation.provider.DemoServiceImpl; +import org.apache.dubbo.config.spring.context.annotation.provider.ProviderConfiguration; + +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.Test; +import org.springframework.aop.support.AopUtils; +import org.springframework.context.annotation.AnnotationConfigApplicationContext; +import org.springframework.transaction.annotation.Transactional; + +import static org.springframework.core.annotation.AnnotationUtils.findAnnotation; + +/** + * {@link DubboComponentScanRegistrar} Test + * + * @since 2.5.8 + */ +public class DubboComponentScanRegistrarTest { + + @Test + public void test() { + + AnnotationConfigApplicationContext providerContext = new AnnotationConfigApplicationContext(); + + providerContext.register(ProviderConfiguration.class); + + providerContext.refresh(); + + DemoService demoService = providerContext.getBean(DemoService.class); + + String value = demoService.sayName("Mercy"); + + Assertions.assertEquals("Hello,Mercy", value); + + Class beanClass = AopUtils.getTargetClass(demoService); + + // DemoServiceImpl with @Transactional + Assertions.assertEquals(DemoServiceImpl.class, beanClass); + + // Test @Transactional is present or not + Assertions.assertNotNull(findAnnotation(beanClass, Transactional.class)); + + AnnotationConfigApplicationContext consumerContext = new AnnotationConfigApplicationContext(); + + consumerContext.register(ConsumerConfiguration.class); + + consumerContext.refresh(); + + ConsumerConfiguration consumerConfiguration = consumerContext.getBean(ConsumerConfiguration.class); + + demoService = consumerConfiguration.getDemoService(); + + value = demoService.sayName("Mercy"); + + Assertions.assertEquals("Hello,Mercy", value); + + ConsumerConfiguration.Child child = consumerContext.getBean(ConsumerConfiguration.Child.class); + + // From Child + + demoService = child.getDemoServiceFromChild(); + + Assertions.assertNotNull(demoService); + + value = demoService.sayName("Mercy"); + + Assertions.assertEquals("Hello,Mercy", value); + + // From Parent + + demoService = child.getDemoServiceFromParent(); + + Assertions.assertNotNull(demoService); + + value = demoService.sayName("Mercy"); + + Assertions.assertEquals("Hello,Mercy", value); + + // From Ancestor + + demoService = child.getDemoServiceFromAncestor(); + + Assertions.assertNotNull(demoService); + + value = demoService.sayName("Mercy"); + + Assertions.assertEquals("Hello,Mercy", value); + + providerContext.close(); + consumerContext.close(); + + + } + + +} diff --git a/dubbo-config/dubbo-config-spring/src/test/java/org/apache/dubbo/config/spring/context/context/annotation/DubboConfigBindingRegistrarTest.java b/dubbo-config/dubbo-config-spring/src/test/java/org/apache/dubbo/config/spring/context/context/annotation/DubboConfigBindingRegistrarTest.java new file mode 100644 index 00000000000..48c06d4b47d --- /dev/null +++ b/dubbo-config/dubbo-config-spring/src/test/java/org/apache/dubbo/config/spring/context/context/annotation/DubboConfigBindingRegistrarTest.java @@ -0,0 +1,88 @@ +/* + * 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.spring.context.context.annotation; + +import org.apache.dubbo.config.ApplicationConfig; +import org.apache.dubbo.config.spring.context.annotation.DubboConfigBindingRegistrar; +import org.apache.dubbo.config.spring.context.annotation.EnableDubboConfigBinding; + +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.Test; +import org.springframework.context.annotation.AnnotationConfigApplicationContext; +import org.springframework.context.annotation.PropertySource; + +/** + * {@link DubboConfigBindingRegistrar} + * + * @since 2.5.8 + */ +public class DubboConfigBindingRegistrarTest { + + @Test + public void testRegisterBeanDefinitionsForSingle() { + + AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(); + + context.register(TestApplicationConfig.class); + + context.refresh(); + + ApplicationConfig applicationConfig = context.getBean("applicationBean", ApplicationConfig.class); + + Assertions.assertEquals("dubbo-demo-application", applicationConfig.getName()); + + + } + + @Test + public void testRegisterBeanDefinitionsForMultiple() { + + AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(); + + context.register(TestMultipleApplicationConfig.class); + + context.refresh(); + + ApplicationConfig applicationConfig = context.getBean("applicationBean", ApplicationConfig.class); + + Assertions.assertEquals("dubbo-demo-application", applicationConfig.getName()); + + applicationConfig = context.getBean("applicationBean2", ApplicationConfig.class); + + Assertions.assertEquals("dubbo-demo-application2", applicationConfig.getName()); + + applicationConfig = context.getBean("applicationBean3", ApplicationConfig.class); + + Assertions.assertEquals("dubbo-demo-application3", applicationConfig.getName()); + + + } + + @EnableDubboConfigBinding(prefix = "${application.prefixes}", type = ApplicationConfig.class, multiple = true) + @PropertySource("META-INF/config.properties") + private static class TestMultipleApplicationConfig { + + } + + @EnableDubboConfigBinding(prefix = "${application.prefix}", type = ApplicationConfig.class) + @PropertySource("META-INF/config.properties") + private static class TestApplicationConfig { + + } + + +} diff --git a/dubbo-config/dubbo-config-spring/src/test/java/org/apache/dubbo/config/spring/context/context/annotation/DubboConfigBindingsRegistrarTest.java b/dubbo-config/dubbo-config-spring/src/test/java/org/apache/dubbo/config/spring/context/context/annotation/DubboConfigBindingsRegistrarTest.java new file mode 100644 index 00000000000..f09782913d3 --- /dev/null +++ b/dubbo-config/dubbo-config-spring/src/test/java/org/apache/dubbo/config/spring/context/context/annotation/DubboConfigBindingsRegistrarTest.java @@ -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.spring.context.context.annotation; + +import org.apache.dubbo.config.ApplicationConfig; +import org.apache.dubbo.config.spring.context.annotation.DubboConfigBindingsRegistrar; +import org.apache.dubbo.config.spring.context.annotation.EnableDubboConfigBinding; +import org.apache.dubbo.config.spring.context.annotation.EnableDubboConfigBindings; + +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.Test; +import org.springframework.context.annotation.AnnotationConfigApplicationContext; +import org.springframework.context.annotation.PropertySource; + +/** + * {@link DubboConfigBindingsRegistrar} Test + * + * @since DubboConfigBindingsRegistrar + */ +public class DubboConfigBindingsRegistrarTest { + + @Test + public void test() { + + AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(); + + context.register(TestConfig.class); + + context.refresh(); + + ApplicationConfig applicationConfig = context.getBean("applicationBean", ApplicationConfig.class); + + Assertions.assertEquals("dubbo-demo-application", applicationConfig.getName()); + + Assertions.assertEquals(2, context.getBeansOfType(ApplicationConfig.class).size()); + + } + + + @EnableDubboConfigBindings({ + @EnableDubboConfigBinding(prefix = "${application.prefix}", type = ApplicationConfig.class), + @EnableDubboConfigBinding(prefix = "dubbo.applications.applicationBean", type = ApplicationConfig.class) + }) + @PropertySource("META-INF/config.properties") + private static class TestConfig { + + } + +} diff --git a/dubbo-config/dubbo-config-spring/src/test/java/org/apache/dubbo/config/spring/context/context/annotation/DubboConfigConfigurationTest.java b/dubbo-config/dubbo-config-spring/src/test/java/org/apache/dubbo/config/spring/context/context/annotation/DubboConfigConfigurationTest.java new file mode 100644 index 00000000000..d4f28aae301 --- /dev/null +++ b/dubbo-config/dubbo-config-spring/src/test/java/org/apache/dubbo/config/spring/context/context/annotation/DubboConfigConfigurationTest.java @@ -0,0 +1,99 @@ +/* + * 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.spring.context.context.annotation; + +import org.apache.dubbo.config.ApplicationConfig; +import org.apache.dubbo.config.ModuleConfig; +import org.apache.dubbo.config.ProtocolConfig; +import org.apache.dubbo.config.RegistryConfig; +import org.apache.dubbo.config.spring.context.annotation.DubboConfigConfiguration; + +import org.junit.jupiter.api.AfterEach; +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.springframework.context.annotation.AnnotationConfigApplicationContext; +import org.springframework.core.io.support.ResourcePropertySource; + +import java.io.IOException; + +/** + * {@link DubboConfigConfiguration} Test + * + * @since 2.5.8 + */ +public class DubboConfigConfigurationTest { + + private AnnotationConfigApplicationContext context; + + @BeforeEach + public void before() throws IOException { + + context = new AnnotationConfigApplicationContext(); + ResourcePropertySource propertySource = new ResourcePropertySource("META-INF/config.properties"); + context.getEnvironment().getPropertySources().addFirst(propertySource); + + } + + @AfterEach + public void after() { + context.close(); + } + + @Test + public void testSingle() throws IOException { + + context.register(DubboConfigConfiguration.Single.class); + context.refresh(); + + // application + ApplicationConfig applicationConfig = context.getBean("applicationBean", ApplicationConfig.class); + Assertions.assertEquals("dubbo-demo-application", applicationConfig.getName()); + + // module + ModuleConfig moduleConfig = context.getBean("moduleBean", ModuleConfig.class); + Assertions.assertEquals("dubbo-demo-module", moduleConfig.getName()); + + // registry + RegistryConfig registryConfig = context.getBean(RegistryConfig.class); + Assertions.assertEquals("zookeeper://192.168.99.100:32770", registryConfig.getAddress()); + + // protocol + ProtocolConfig protocolConfig = context.getBean(ProtocolConfig.class); + Assertions.assertEquals("dubbo", protocolConfig.getName()); + Assertions.assertEquals(Integer.valueOf(20880), protocolConfig.getPort()); + } + + @Test + public void testMultiple() { + + context.register(DubboConfigConfiguration.Multiple.class); + context.refresh(); + + // application + ApplicationConfig applicationConfig = context.getBean("applicationBean", ApplicationConfig.class); + Assertions.assertEquals("dubbo-demo-application", applicationConfig.getName()); + + ApplicationConfig applicationBean2 = context.getBean("applicationBean2", ApplicationConfig.class); + Assertions.assertEquals("dubbo-demo-application2", applicationBean2.getName()); + + ApplicationConfig applicationBean3 = context.getBean("applicationBean3", ApplicationConfig.class); + Assertions.assertEquals("dubbo-demo-application3", applicationBean3.getName()); + + } + +} diff --git a/dubbo-config/dubbo-config-spring/src/test/java/org/apache/dubbo/config/spring/context/context/annotation/EnableDubboConfigTest.java b/dubbo-config/dubbo-config-spring/src/test/java/org/apache/dubbo/config/spring/context/context/annotation/EnableDubboConfigTest.java new file mode 100644 index 00000000000..fba874332b3 --- /dev/null +++ b/dubbo-config/dubbo-config-spring/src/test/java/org/apache/dubbo/config/spring/context/context/annotation/EnableDubboConfigTest.java @@ -0,0 +1,109 @@ +/* + * 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.spring.context.context.annotation; + +import org.apache.dubbo.config.ApplicationConfig; +import org.apache.dubbo.config.ConsumerConfig; +import org.apache.dubbo.config.ModuleConfig; +import org.apache.dubbo.config.MonitorConfig; +import org.apache.dubbo.config.ProtocolConfig; +import org.apache.dubbo.config.ProviderConfig; +import org.apache.dubbo.config.RegistryConfig; +import org.apache.dubbo.config.spring.context.annotation.EnableDubboConfig; + +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.Test; +import org.springframework.context.annotation.AnnotationConfigApplicationContext; +import org.springframework.context.annotation.PropertySource; + +/** + * {@link EnableDubboConfig} Test + * + * @since 2.5.8 + */ +public class EnableDubboConfigTest { + + @Test + public void testSingle() { + + AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(); + context.register(TestConfig.class); + context.refresh(); + + // application + ApplicationConfig applicationConfig = context.getBean("applicationBean", ApplicationConfig.class); + Assertions.assertEquals("dubbo-demo-application", applicationConfig.getName()); + + // module + ModuleConfig moduleConfig = context.getBean("moduleBean", ModuleConfig.class); + Assertions.assertEquals("dubbo-demo-module", moduleConfig.getName()); + + // registry + RegistryConfig registryConfig = context.getBean(RegistryConfig.class); + Assertions.assertEquals("zookeeper://192.168.99.100:32770", registryConfig.getAddress()); + + // protocol + ProtocolConfig protocolConfig = context.getBean(ProtocolConfig.class); + Assertions.assertEquals("dubbo", protocolConfig.getName()); + Assertions.assertEquals(Integer.valueOf(20880), protocolConfig.getPort()); + + // monitor + MonitorConfig monitorConfig = context.getBean(MonitorConfig.class); + Assertions.assertEquals("zookeeper://127.0.0.1:32770", monitorConfig.getAddress()); + + // provider + ProviderConfig providerConfig = context.getBean(ProviderConfig.class); + Assertions.assertEquals("127.0.0.1", providerConfig.getHost()); + + + // consumer + ConsumerConfig consumerConfig = context.getBean(ConsumerConfig.class); + Assertions.assertEquals("netty", consumerConfig.getClient()); + + } + + @Test + public void testMultiple() { + + AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(); + context.register(TestMultipleConfig.class); + context.refresh(); + + // application + ApplicationConfig applicationConfig = context.getBean("applicationBean", ApplicationConfig.class); + Assertions.assertEquals("dubbo-demo-application", applicationConfig.getName()); + + ApplicationConfig applicationBean2 = context.getBean("applicationBean2", ApplicationConfig.class); + Assertions.assertEquals("dubbo-demo-application2", applicationBean2.getName()); + + ApplicationConfig applicationBean3 = context.getBean("applicationBean3", ApplicationConfig.class); + Assertions.assertEquals("dubbo-demo-application3", applicationBean3.getName()); + + } + + @EnableDubboConfig(multiple = true) + @PropertySource("META-INF/config.properties") + private static class TestMultipleConfig { + + } + + @EnableDubboConfig + @PropertySource("META-INF/config.properties") + private static class TestConfig { + + } +} diff --git a/dubbo-config/dubbo-config-spring/src/test/java/org/apache/dubbo/config/spring/context/context/annotation/EnableDubboTest.java b/dubbo-config/dubbo-config-spring/src/test/java/org/apache/dubbo/config/spring/context/context/annotation/EnableDubboTest.java new file mode 100644 index 00000000000..1366a35d252 --- /dev/null +++ b/dubbo-config/dubbo-config-spring/src/test/java/org/apache/dubbo/config/spring/context/context/annotation/EnableDubboTest.java @@ -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.config.spring.context.context.annotation; + +import org.apache.dubbo.config.RegistryConfig; +import org.apache.dubbo.config.spring.api.DemoService; +import org.apache.dubbo.config.spring.context.annotation.EnableDubbo; +import org.apache.dubbo.config.spring.context.annotation.consumer.test.TestConsumerConfiguration; +import org.apache.dubbo.config.spring.context.annotation.provider.DemoServiceImpl; + +import org.junit.Assert; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.springframework.aop.support.AopUtils; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.context.ApplicationContext; +import org.springframework.context.annotation.AnnotationConfigApplicationContext; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.ComponentScan; +import org.springframework.context.annotation.Primary; +import org.springframework.context.annotation.PropertySource; +import org.springframework.test.context.ContextConfiguration; +import org.springframework.test.context.TestPropertySource; +import org.springframework.test.context.junit4.SpringJUnit4ClassRunner; +import org.springframework.transaction.PlatformTransactionManager; +import org.springframework.transaction.TransactionDefinition; +import org.springframework.transaction.TransactionException; +import org.springframework.transaction.TransactionStatus; +import org.springframework.transaction.annotation.EnableTransactionManagement; +import org.springframework.transaction.annotation.Transactional; + +import static org.springframework.core.annotation.AnnotationUtils.findAnnotation; + +/** + * {@link EnableDubbo} Test + * + * @since 2.5.8 + */ +@RunWith(SpringJUnit4ClassRunner.class) +@ContextConfiguration(classes = {EnableDubboTest.class}) +@TestPropertySource(locations = "classpath:/META-INF/dubbb-provider.properties", + properties = "demo.service.version = 2.5.7") +@EnableDubbo(scanBasePackages = "org.apache.dubbo.config.spring.context.annotation.provider") +@ComponentScan(basePackages = "org.apache.dubbo.config.spring.context.annotation.provider") +@EnableTransactionManagement +public class EnableDubboTest { + + @Autowired + private ApplicationContext providerContext; + + @Test + public void test() { + + DemoService demoService = providerContext.getBean(DemoService.class); + + String value = demoService.sayName("Mercy"); + + Assert.assertEquals("Hello,Mercy", value); + + Class beanClass = AopUtils.getTargetClass(demoService); + + // DemoServiceImpl with @Transactional + Assert.assertEquals(DemoServiceImpl.class, beanClass); + + // Test @Transactional is present or not + Assert.assertNotNull(findAnnotation(beanClass, Transactional.class)); + + AnnotationConfigApplicationContext consumerContext = new AnnotationConfigApplicationContext(TestConsumerConfiguration.class); + + TestConsumerConfiguration consumerConfiguration = consumerContext.getBean(TestConsumerConfiguration.class); + + demoService = consumerConfiguration.getDemoService(); + + value = demoService.sayName("Mercy"); + + Assert.assertEquals("Hello,Mercy", value); + + TestConsumerConfiguration.Child child = consumerContext.getBean(TestConsumerConfiguration.Child.class); + + // From Child + + demoService = child.getDemoServiceFromChild(); + + Assert.assertNotNull(demoService); + + value = demoService.sayName("Mercy"); + + Assert.assertEquals("Hello,Mercy", value); + + // From Parent + + demoService = child.getDemoServiceFromParent(); + + Assert.assertNotNull(demoService); + + value = demoService.sayName("Mercy"); + + Assert.assertEquals("Hello,Mercy", value); + + // From Ancestor + + demoService = child.getDemoServiceFromAncestor(); + + Assert.assertNotNull(demoService); + + value = demoService.sayName("Mercy"); + + Assert.assertEquals("Hello,Mercy", value); + + // Test my-registry2 bean presentation + RegistryConfig registryConfig = consumerContext.getBean("my-registry2", RegistryConfig.class); + + // Test multiple binding + Assert.assertEquals("N/A", registryConfig.getAddress()); + + } + + @EnableDubbo(scanBasePackages = "org.apache.dubbo.config.spring.context.annotation.provider") + @ComponentScan(basePackages = "org.apache.dubbo.config.spring.context.annotation.provider") + @PropertySource("classpath:/META-INF/dubbb-provider.properties") + @EnableTransactionManagement + public static class TestProviderConfiguration { + + @Primary + @Bean + public PlatformTransactionManager platformTransactionManager() { + return new PlatformTransactionManager() { + + @Override + public TransactionStatus getTransaction(TransactionDefinition definition) throws TransactionException { + return null; + } + + @Override + public void commit(TransactionStatus status) throws TransactionException { + + } + + @Override + public void rollback(TransactionStatus status) throws TransactionException { + + } + }; + } + } + + +} diff --git a/dubbo-config/dubbo-config-spring/src/test/java/org/apache/dubbo/config/spring/context/context/annotation/consumer/ConsumerConfiguration.java b/dubbo-config/dubbo-config-spring/src/test/java/org/apache/dubbo/config/spring/context/context/annotation/consumer/ConsumerConfiguration.java new file mode 100644 index 00000000000..04866986197 --- /dev/null +++ b/dubbo-config/dubbo-config-spring/src/test/java/org/apache/dubbo/config/spring/context/context/annotation/consumer/ConsumerConfiguration.java @@ -0,0 +1,126 @@ +/* + * 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.spring.context.context.annotation.consumer; + +import org.apache.dubbo.config.ApplicationConfig; +import org.apache.dubbo.config.RegistryConfig; +import org.apache.dubbo.config.annotation.Reference; +import org.apache.dubbo.config.spring.api.DemoService; +import org.apache.dubbo.config.spring.context.annotation.DubboComponentScan; + +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.context.annotation.PropertySource; + +@Configuration("consumerConfiguration") +@DubboComponentScan( + basePackageClasses = ConsumerConfiguration.class +) +@PropertySource("META-INF/default.properties") +public class ConsumerConfiguration { + + /** + * Current application configuration, to replace XML config: + * + * <dubbo:application name="dubbo-demo-application"/> + * + * + * @return {@link ApplicationConfig} Bean + */ + @Bean("dubbo-demo-application") + public ApplicationConfig applicationConfig() { + ApplicationConfig applicationConfig = new ApplicationConfig(); + applicationConfig.setName("dubbo-demo-application"); + return applicationConfig; + } + + /** + * Current registry center configuration, to replace XML config: + * + * <dubbo:registry address="N/A"/> + * + * + * @return {@link RegistryConfig} Bean + */ + @Bean + public RegistryConfig registryConfig() { + RegistryConfig registryConfig = new RegistryConfig(); + registryConfig.setAddress("N/A"); + return registryConfig; + } + + @Reference(version = "2.5.7", url = "dubbo://127.0.0.1:12345") + private DemoService demoService; + + public DemoService getDemoService() { + return demoService; + } + + public void setDemoService(DemoService demoService) { + this.demoService = demoService; + } + + + @Bean + public Child c() { + return new Child(); + } + + public static abstract class Ancestor { + + @Reference(version = "2.5.7", url = "dubbo://127.0.0.1:12345") + private DemoService demoServiceFromAncestor; + + public DemoService getDemoServiceFromAncestor() { + return demoServiceFromAncestor; + } + + public void setDemoServiceFromAncestor(DemoService demoServiceFromAncestor) { + this.demoServiceFromAncestor = demoServiceFromAncestor; + } + } + + public static abstract class Parent extends Ancestor { + + private DemoService demoServiceFromParent; + + public DemoService getDemoServiceFromParent() { + return demoServiceFromParent; + } + + @Reference(version = "2.5.7", url = "dubbo://127.0.0.1:12345") + public void setDemoServiceFromParent(DemoService demoServiceFromParent) { + this.demoServiceFromParent = demoServiceFromParent; + } + + } + + public static class Child extends Parent { + + @Reference(version = "2.5.7", url = "dubbo://127.0.0.1:12345") + private DemoService demoServiceFromChild; + + public DemoService getDemoServiceFromChild() { + return demoServiceFromChild; + } + + public void setDemoServiceFromChild(DemoService demoServiceFromChild) { + this.demoServiceFromChild = demoServiceFromChild; + } + } + +} diff --git a/dubbo-config/dubbo-config-spring/src/test/java/org/apache/dubbo/config/spring/context/context/annotation/consumer/test/TestConsumerConfiguration.java b/dubbo-config/dubbo-config-spring/src/test/java/org/apache/dubbo/config/spring/context/context/annotation/consumer/test/TestConsumerConfiguration.java new file mode 100644 index 00000000000..dc41c614cd8 --- /dev/null +++ b/dubbo-config/dubbo-config-spring/src/test/java/org/apache/dubbo/config/spring/context/context/annotation/consumer/test/TestConsumerConfiguration.java @@ -0,0 +1,96 @@ +/* + * 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.spring.context.context.annotation.consumer.test; + +import org.apache.dubbo.config.annotation.Reference; +import org.apache.dubbo.config.spring.api.DemoService; +import org.apache.dubbo.config.spring.context.annotation.EnableDubbo; + +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.PropertySource; +import org.springframework.transaction.annotation.EnableTransactionManagement; + +/** + * Test Consumer Configuration + * + * @since 2.5.7 + */ +@EnableDubbo(scanBasePackageClasses = TestConsumerConfiguration.class, multipleConfig = true) +@PropertySource("META-INF/dubbb-consumer.properties") +@EnableTransactionManagement +public class TestConsumerConfiguration { + + @Reference(version = "2.5.7", url = "dubbo://127.0.0.1:12345", application = "dubbo-demo-application") + private DemoService demoService; + + public DemoService getDemoService() { + return demoService; + } + + public void setDemoService(DemoService demoService) { + this.demoService = demoService; + } + + + @Bean + public TestConsumerConfiguration.Child c() { + return new TestConsumerConfiguration.Child(); + } + + public static abstract class Ancestor { + + @Reference(version = "2.5.7", url = "dubbo://127.0.0.1:12345", application = "dubbo-demo-application") + private DemoService demoServiceFromAncestor; + + public DemoService getDemoServiceFromAncestor() { + return demoServiceFromAncestor; + } + + public void setDemoServiceFromAncestor(DemoService demoServiceFromAncestor) { + this.demoServiceFromAncestor = demoServiceFromAncestor; + } + } + + public static abstract class Parent extends TestConsumerConfiguration.Ancestor { + + private DemoService demoServiceFromParent; + + public DemoService getDemoServiceFromParent() { + return demoServiceFromParent; + } + + @Reference(version = "2.5.7", url = "dubbo://127.0.0.1:12345", application = "dubbo-demo-application") + public void setDemoServiceFromParent(DemoService demoServiceFromParent) { + this.demoServiceFromParent = demoServiceFromParent; + } + + } + + public static class Child extends TestConsumerConfiguration.Parent { + + @Reference(version = "2.5.7", url = "dubbo://127.0.0.1:12345", application = "dubbo-demo-application") + private DemoService demoServiceFromChild; + + public DemoService getDemoServiceFromChild() { + return demoServiceFromChild; + } + + public void setDemoServiceFromChild(DemoService demoServiceFromChild) { + this.demoServiceFromChild = demoServiceFromChild; + } + } +} diff --git a/dubbo-config/dubbo-config-spring/src/main/java/org/apache/dubbo/config/spring/convert/converter/StringArrayToStringConverter.java b/dubbo-config/dubbo-config-spring/src/test/java/org/apache/dubbo/config/spring/context/context/annotation/provider/DefaultHelloService.java similarity index 59% rename from dubbo-config/dubbo-config-spring/src/main/java/org/apache/dubbo/config/spring/convert/converter/StringArrayToStringConverter.java rename to dubbo-config/dubbo-config-spring/src/test/java/org/apache/dubbo/config/spring/context/context/annotation/provider/DefaultHelloService.java index 7cd6e7124aa..b484d26a931 100644 --- a/dubbo-config/dubbo-config-spring/src/main/java/org/apache/dubbo/config/spring/convert/converter/StringArrayToStringConverter.java +++ b/dubbo-config/dubbo-config-spring/src/test/java/org/apache/dubbo/config/spring/context/context/annotation/provider/DefaultHelloService.java @@ -14,24 +14,25 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.apache.dubbo.config.spring.convert.converter; +package org.apache.dubbo.config.spring.context.context.annotation.provider; -import org.springframework.core.convert.converter.Converter; -import org.springframework.util.ObjectUtils; -import org.springframework.util.StringUtils; +import org.apache.dubbo.config.spring.api.HelloService; +import org.springframework.stereotype.Service; /** - * String[] to String {@ConditionalGenericConverter} + * Default {@link HelloService} annotation with Spring's {@link Service} + * and Dubbo's {@link org.apache.dubbo.config.annotation.Service} * - * @see StringUtils#arrayToCommaDelimitedString(Object[]) - * @since 2.5.11 + * @since TODO */ -public class StringArrayToStringConverter implements Converter { +@Service +@org.apache.dubbo.config.annotation.Service +public class DefaultHelloService implements HelloService { @Override - public String convert(String[] source) { - return ObjectUtils.isEmpty(source) ? null : StringUtils.arrayToCommaDelimitedString(source); + public String sayHello(String name) { + return "Greeting, " + name; } } diff --git a/dubbo-config/dubbo-config-spring/src/test/java/org/apache/dubbo/config/spring/context/context/annotation/provider/DemoServiceImpl.java b/dubbo-config/dubbo-config-spring/src/test/java/org/apache/dubbo/config/spring/context/context/annotation/provider/DemoServiceImpl.java new file mode 100644 index 00000000000..155bd2a5539 --- /dev/null +++ b/dubbo-config/dubbo-config-spring/src/test/java/org/apache/dubbo/config/spring/context/context/annotation/provider/DemoServiceImpl.java @@ -0,0 +1,55 @@ +/* + * 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.spring.context.context.annotation.provider; + +import org.apache.dubbo.config.spring.api.Box; +import org.apache.dubbo.config.spring.api.DemoService; + +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; + + +/** + * {@link DemoService} Service implementation + * + * @since 2.5.8 + */ +@org.apache.dubbo.config.annotation.Service( + version = "${demo.service.version}", + application = "${demo.service.application}", + protocol = "${demo.service.protocol}", + registry = "${demo.service.registry}" +) +@Service +@Transactional +public class DemoServiceImpl implements DemoService { + + @Override + public String sayName(String name) { + return "Hello," + name; + } + + @Override + public Box getBox() { + return new Box() { + @Override + public String getName() { + return "MyBox"; + } + }; + } +} diff --git a/dubbo-config/dubbo-config-spring/src/test/java/org/apache/dubbo/config/spring/convert/converter/StringArrayToStringConverterTest.java b/dubbo-config/dubbo-config-spring/src/test/java/org/apache/dubbo/config/spring/context/context/annotation/provider/HelloServiceImpl.java similarity index 55% rename from dubbo-config/dubbo-config-spring/src/test/java/org/apache/dubbo/config/spring/convert/converter/StringArrayToStringConverterTest.java rename to dubbo-config/dubbo-config-spring/src/test/java/org/apache/dubbo/config/spring/context/context/annotation/provider/HelloServiceImpl.java index 33c1388dacc..10b00a8f5b3 100644 --- a/dubbo-config/dubbo-config-spring/src/test/java/org/apache/dubbo/config/spring/convert/converter/StringArrayToStringConverterTest.java +++ b/dubbo-config/dubbo-config-spring/src/test/java/org/apache/dubbo/config/spring/context/context/annotation/provider/HelloServiceImpl.java @@ -14,33 +14,21 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.apache.dubbo.config.spring.convert.converter; +package org.apache.dubbo.config.spring.context.context.annotation.provider; -import org.junit.jupiter.api.Assertions; -import org.junit.jupiter.api.Test; +import org.apache.dubbo.config.annotation.Service; +import org.apache.dubbo.config.spring.api.HelloService; /** - * {@link StringArrayToStringConverter} Test + * {@link HelloService} Implementation just annotating Dubbo's {@link Service} + * + * @since 2.5.9 */ -public class StringArrayToStringConverterTest { - - @Test - public void testConvert() { - - StringArrayToStringConverter converter = new StringArrayToStringConverter(); - - String value = converter.convert(new String[]{"Hello", "World"}); - - Assertions.assertEquals("Hello,World", value); - - value = converter.convert(new String[]{}); - - Assertions.assertNull(value); - - value = converter.convert(null); - - Assertions.assertNull(value); +@Service(interfaceName = "org.apache.dubbo.config.spring.api.HelloService") +public class HelloServiceImpl implements HelloService { + @Override + public String sayHello(String name) { + return "Hello, " + name; } - } diff --git a/dubbo-config/dubbo-config-spring/src/test/java/org/apache/dubbo/config/spring/context/context/annotation/provider/ProviderConfiguration.java b/dubbo-config/dubbo-config-spring/src/test/java/org/apache/dubbo/config/spring/context/context/annotation/provider/ProviderConfiguration.java new file mode 100644 index 00000000000..c77322848d6 --- /dev/null +++ b/dubbo-config/dubbo-config-spring/src/test/java/org/apache/dubbo/config/spring/context/context/annotation/provider/ProviderConfiguration.java @@ -0,0 +1,107 @@ +/* + * 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.spring.context.context.annotation.provider; + +import org.apache.dubbo.config.ApplicationConfig; +import org.apache.dubbo.config.ProtocolConfig; +import org.apache.dubbo.config.RegistryConfig; +import org.apache.dubbo.config.spring.context.annotation.DubboComponentScan; + +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Primary; +import org.springframework.context.annotation.PropertySource; +import org.springframework.transaction.PlatformTransactionManager; +import org.springframework.transaction.TransactionDefinition; +import org.springframework.transaction.TransactionException; +import org.springframework.transaction.TransactionStatus; +import org.springframework.transaction.annotation.EnableTransactionManagement; + +@DubboComponentScan(basePackages = "org.apache.dubbo.config.spring.context.annotation.provider") +@PropertySource("META-INF/default.properties") +@EnableTransactionManagement +public class ProviderConfiguration { + + /** + * Current application configuration, to replace XML config: + * + * <dubbo:application name="dubbo-demo-application"/> + * + * + * @return {@link ApplicationConfig} Bean + */ + @Bean("dubbo-demo-application") + public ApplicationConfig applicationConfig() { + ApplicationConfig applicationConfig = new ApplicationConfig(); + applicationConfig.setName("dubbo-demo-application"); + return applicationConfig; + } + + /** + * Current registry center configuration, to replace XML config: + * + * <dubbo:registry id="my-registry" address="N/A"/> + * + * + * @return {@link RegistryConfig} Bean + */ + @Bean("my-registry") + public RegistryConfig registryConfig() { + RegistryConfig registryConfig = new RegistryConfig(); + registryConfig.setAddress("N/A"); + return registryConfig; + } + + /** + * Current protocol configuration, to replace XML config: + * + * <dubbo:protocol name="dubbo" port="12345"/> + * + * + * @return {@link ProtocolConfig} Bean + */ + @Bean("dubbo") + public ProtocolConfig protocolConfig() { + ProtocolConfig protocolConfig = new ProtocolConfig(); + protocolConfig.setName("dubbo"); + protocolConfig.setPort(12345); + return protocolConfig; + } + + @Primary + @Bean + public PlatformTransactionManager platformTransactionManager() { + return new PlatformTransactionManager() { + + @Override + public TransactionStatus getTransaction(TransactionDefinition definition) throws TransactionException { + return null; + } + + @Override + public void commit(TransactionStatus status) throws TransactionException { + + } + + @Override + public void rollback(TransactionStatus status) throws TransactionException { + + } + }; + } + +} + diff --git a/dubbo-config/dubbo-config-spring/src/test/java/org/apache/dubbo/config/spring/context/context/properties/DefaultDubboConfigBinderTest.java b/dubbo-config/dubbo-config-spring/src/test/java/org/apache/dubbo/config/spring/context/context/properties/DefaultDubboConfigBinderTest.java new file mode 100644 index 00000000000..1caddb0b31b --- /dev/null +++ b/dubbo-config/dubbo-config-spring/src/test/java/org/apache/dubbo/config/spring/context/context/properties/DefaultDubboConfigBinderTest.java @@ -0,0 +1,94 @@ +/* + * 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.spring.context.context.properties; + + +import org.apache.dubbo.config.ApplicationConfig; +import org.apache.dubbo.config.ConsumerConfig; +import org.apache.dubbo.config.ProtocolConfig; +import org.apache.dubbo.config.RegistryConfig; +import org.apache.dubbo.config.spring.beans.factory.config.YamlPropertySourceFactory; +import org.apache.dubbo.config.spring.context.properties.DefaultDubboConfigBinder; +import org.apache.dubbo.config.spring.context.properties.DubboConfigBinder; + +import org.junit.Assert; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.context.annotation.Configuration; +import org.springframework.context.annotation.PropertySource; +import org.springframework.test.context.ContextConfiguration; +import org.springframework.test.context.TestPropertySource; +import org.springframework.test.context.junit4.SpringRunner; + +@RunWith(SpringRunner.class) +@TestPropertySource(locations = "classpath:/dubbo.properties") +@PropertySource(name = "yaml-source", value = {"classpath:/META-INF/dubbo.yml"}, factory = YamlPropertySourceFactory.class) +@Configuration +@ContextConfiguration(classes = {DefaultDubboConfigBinder.class, DefaultDubboConfigBinderTest.class}) +public class DefaultDubboConfigBinderTest { + + @Autowired + private DubboConfigBinder dubboConfigBinder; + + @Value("${dubbo.consumer.default}") + private Boolean isDefault; + + @Value("${dubbo.consumer.client}") + private String client; + + @Value("${dubbo.consumer.threadpool}") + private String threadPool; + + @Value("${dubbo.consumer.corethreads}") + private Integer coreThreads; + + @Value("${dubbo.consumer.threads}") + private Integer threads; + + @Value("${dubbo.consumer.queues}") + private Integer queues; + + @Test + public void testBinder() { + + ApplicationConfig applicationConfig = new ApplicationConfig(); + dubboConfigBinder.bind("dubbo.application", applicationConfig); + Assert.assertEquals("hello", applicationConfig.getName()); + Assert.assertEquals("world", applicationConfig.getOwner()); + + RegistryConfig registryConfig = new RegistryConfig(); + dubboConfigBinder.bind("dubbo.registry", registryConfig); + Assert.assertEquals("10.20.153.17", registryConfig.getAddress()); + + ProtocolConfig protocolConfig = new ProtocolConfig(); + dubboConfigBinder.bind("dubbo.protocol", protocolConfig); + Assert.assertEquals(Integer.valueOf(20881), protocolConfig.getPort()); + + ConsumerConfig consumerConfig = new ConsumerConfig(); + dubboConfigBinder.bind("dubbo.consumer", consumerConfig); + + Assert.assertEquals(isDefault, consumerConfig.isDefault()); + Assert.assertEquals(client, consumerConfig.getClient()); + Assert.assertEquals(threadPool, consumerConfig.getThreadpool()); + Assert.assertEquals(coreThreads, consumerConfig.getCorethreads()); + Assert.assertEquals(threads, consumerConfig.getThreads()); + Assert.assertEquals(queues, consumerConfig.getQueues()); + } +} + diff --git a/dubbo-config/dubbo-config-spring/src/test/java/org/apache/dubbo/config/spring/context/properties/DefaultDubboConfigBinderTest.java b/dubbo-config/dubbo-config-spring/src/test/java/org/apache/dubbo/config/spring/context/properties/DefaultDubboConfigBinderTest.java index 6629ac609cd..030fbc8bf9d 100644 --- a/dubbo-config/dubbo-config-spring/src/test/java/org/apache/dubbo/config/spring/context/properties/DefaultDubboConfigBinderTest.java +++ b/dubbo-config/dubbo-config-spring/src/test/java/org/apache/dubbo/config/spring/context/properties/DefaultDubboConfigBinderTest.java @@ -21,16 +21,15 @@ import org.apache.dubbo.config.ProtocolConfig; import org.apache.dubbo.config.RegistryConfig; +import org.junit.Test; import org.junit.jupiter.api.Assertions; -import org.junit.jupiter.api.Disabled; -import org.junit.jupiter.api.Test; -import org.junit.jupiter.api.extension.ExtendWith; +import org.junit.runner.RunWith; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.test.context.ContextConfiguration; import org.springframework.test.context.TestPropertySource; -import org.springframework.test.context.junit.jupiter.SpringExtension; +import org.springframework.test.context.junit4.SpringJUnit4ClassRunner; -@ExtendWith(SpringExtension.class) +@RunWith(SpringJUnit4ClassRunner.class) @TestPropertySource(locations = "classpath:/dubbo.properties") @ContextConfiguration(classes = DefaultDubboConfigBinder.class) public class DefaultDubboConfigBinderTest { @@ -38,8 +37,7 @@ public class DefaultDubboConfigBinderTest { @Autowired private DubboConfigBinder dubboConfigBinder; - @Disabled -// @Test + @Test public void testBinder() { ApplicationConfig applicationConfig = new ApplicationConfig(); diff --git a/dubbo-config/dubbo-config-spring/src/test/java/org/apache/dubbo/config/spring/extension/SpringExtensionFactoryTest.java b/dubbo-config/dubbo-config-spring/src/test/java/org/apache/dubbo/config/spring/extension/SpringExtensionFactoryTest.java index da27b01cda2..0ae08e3a038 100644 --- a/dubbo-config/dubbo-config-spring/src/test/java/org/apache/dubbo/config/spring/extension/SpringExtensionFactoryTest.java +++ b/dubbo-config/dubbo-config-spring/src/test/java/org/apache/dubbo/config/spring/extension/SpringExtensionFactoryTest.java @@ -20,8 +20,8 @@ import org.apache.dubbo.config.spring.api.HelloService; import org.apache.dubbo.config.spring.impl.DemoServiceImpl; import org.apache.dubbo.config.spring.impl.HelloServiceImpl; - import org.apache.dubbo.rpc.Protocol; + import org.junit.jupiter.api.AfterEach; import org.junit.jupiter.api.Assertions; import org.junit.jupiter.api.BeforeEach; diff --git a/dubbo-config/dubbo-config-spring/src/test/java/org/apache/dubbo/config/spring/schema/DubboNamespaceHandlerTest.java b/dubbo-config/dubbo-config-spring/src/test/java/org/apache/dubbo/config/spring/schema/DubboNamespaceHandlerTest.java index 4a41651ade3..d0ec9ea9487 100644 --- a/dubbo-config/dubbo-config-spring/src/test/java/org/apache/dubbo/config/spring/schema/DubboNamespaceHandlerTest.java +++ b/dubbo-config/dubbo-config-spring/src/test/java/org/apache/dubbo/config/spring/schema/DubboNamespaceHandlerTest.java @@ -21,17 +21,19 @@ import org.apache.dubbo.config.MonitorConfig; import org.apache.dubbo.config.ProtocolConfig; import org.apache.dubbo.config.ProviderConfig; +import org.apache.dubbo.config.context.ConfigManager; import org.apache.dubbo.config.spring.ConfigTest; import org.apache.dubbo.config.spring.ServiceBean; import org.apache.dubbo.config.spring.api.DemoService; import org.apache.dubbo.config.spring.impl.DemoServiceImpl; +import org.junit.jupiter.api.AfterEach; import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; import org.springframework.beans.factory.BeanCreationException; import org.springframework.context.support.ClassPathXmlApplicationContext; -import java.io.IOException; import java.util.Map; import static org.hamcrest.CoreMatchers.is; @@ -40,6 +42,16 @@ import static org.hamcrest.MatcherAssert.assertThat; public class DubboNamespaceHandlerTest { + @BeforeEach + public void setUp() { + ConfigManager.getInstance().clear(); + } + + @AfterEach + public void tearDown() { + ConfigManager.getInstance().clear(); + } + @Test public void testProviderXml() { ClassPathXmlApplicationContext ctx = new ClassPathXmlApplicationContext(ConfigTest.class.getPackage().getName().replace('.', '/') + "/demo-provider.xml"); @@ -99,7 +111,7 @@ public void testCustomParameter() { @Test public void testDelayFixedTime() { - ClassPathXmlApplicationContext ctx = new ClassPathXmlApplicationContext(ConfigTest.class.getPackage().getName().replace('.', '/') + "/delay-fixed-time.xml"); + ClassPathXmlApplicationContext ctx = new ClassPathXmlApplicationContext("classpath:/" + ConfigTest.class.getPackage().getName().replace('.', '/') + "/delay-fixed-time.xml"); ctx.start(); assertThat(ctx.getBean(ServiceBean.class).getDelay(), is(300)); diff --git a/dubbo-config/dubbo-config-spring/src/test/java/org/apache/dubbo/config/spring/status/SpringStatusCheckerTest.java b/dubbo-config/dubbo-config-spring/src/test/java/org/apache/dubbo/config/spring/status/SpringStatusCheckerTest.java index 8d11c66a586..f3be445103c 100644 --- a/dubbo-config/dubbo-config-spring/src/test/java/org/apache/dubbo/config/spring/status/SpringStatusCheckerTest.java +++ b/dubbo-config/dubbo-config-spring/src/test/java/org/apache/dubbo/config/spring/status/SpringStatusCheckerTest.java @@ -19,9 +19,11 @@ import org.apache.dubbo.common.status.Status; import org.apache.dubbo.config.spring.ServiceBean; import org.apache.dubbo.config.spring.extension.SpringExtensionFactory; + import org.junit.jupiter.api.AfterEach; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; + import org.mockito.Mock; import org.mockito.Mockito; import org.springframework.context.ApplicationContext; diff --git a/dubbo-config/dubbo-config-spring/src/test/java/org/apache/dubbo/config/spring/util/PropertySourcesUtilsTest.java b/dubbo-config/dubbo-config-spring/src/test/java/org/apache/dubbo/config/spring/util/PropertySourcesUtilsTest.java index 1e099a49f70..9e8c29f963a 100644 --- a/dubbo-config/dubbo-config-spring/src/test/java/org/apache/dubbo/config/spring/util/PropertySourcesUtilsTest.java +++ b/dubbo-config/dubbo-config-spring/src/test/java/org/apache/dubbo/config/spring/util/PropertySourcesUtilsTest.java @@ -39,26 +39,30 @@ public void testGetSubProperties() { MutablePropertySources propertySources = new MutablePropertySources(); Map source = new HashMap(); + Map source2 = new HashMap(); - MapPropertySource propertySource = new MapPropertySource("test", source); + MapPropertySource propertySource = new MapPropertySource("propertySource", source); + MapPropertySource propertySource2 = new MapPropertySource("propertySource2", source2); - propertySources.addFirst(propertySource); + propertySources.addLast(propertySource); + propertySources.addLast(propertySource2); - String KEY_PREFIX = "user"; - String KEY_NAME = "name"; - String KEY_AGE = "age"; - Map result = PropertySourcesUtils.getSubProperties(propertySources, KEY_PREFIX); + Map result = PropertySourcesUtils.getSubProperties(propertySources, "user"); Assertions.assertEquals(Collections.emptyMap(), result); - source.put(KEY_PREFIX + "." + KEY_NAME, "Mercy"); - source.put(KEY_PREFIX + "." + KEY_AGE, 31); + source.put("age", "31"); + source.put("user.name", "Mercy"); + source.put("user.age", "${age}"); + + source2.put("user.name", "mercyblitz"); + source2.put("user.age", "32"); Map expected = new HashMap(); - expected.put(KEY_NAME, "Mercy"); - expected.put(KEY_AGE, "31"); + expected.put("name", "Mercy"); + expected.put("age", "31"); - result = PropertySourcesUtils.getSubProperties(propertySources, KEY_PREFIX); + result = PropertySourcesUtils.getSubProperties(propertySources, "user"); Assertions.assertEquals(expected, result); result = PropertySourcesUtils.getSubProperties(propertySources, ""); @@ -69,15 +73,6 @@ public void testGetSubProperties() { Assertions.assertEquals(Collections.emptyMap(), result); - source.put(KEY_PREFIX + ".app.name", "${info.name}"); - source.put("info.name", "Hello app"); - - result = PropertySourcesUtils.getSubProperties(propertySources, KEY_PREFIX); - - String appName = result.get("app.name"); - - Assertions.assertEquals("Hello app", appName); - } -} +} \ No newline at end of file diff --git a/dubbo-config/dubbo-config-spring/src/test/resources/META-INF/default.properties b/dubbo-config/dubbo-config-spring/src/test/resources/META-INF/default.properties index f867bf81633..101030bba99 100644 --- a/dubbo-config/dubbo-config-spring/src/test/resources/META-INF/default.properties +++ b/dubbo-config/dubbo-config-spring/src/test/resources/META-INF/default.properties @@ -1,4 +1,4 @@ demo.service.version = 2.5.7 -demo.service.application = dubbo-annotation-provider +demo.service.application = dubbo-demo-application demo.service.protocol = dubbo demo.service.registry = my-registry diff --git a/dubbo-config/dubbo-config-spring/src/test/resources/META-INF/dubbb-consumer.properties b/dubbo-config/dubbo-config-spring/src/test/resources/META-INF/dubbb-consumer.properties index ef6a32a11bf..4583323bbd7 100644 --- a/dubbo-config/dubbo-config-spring/src/test/resources/META-INF/dubbb-consumer.properties +++ b/dubbo-config/dubbo-config-spring/src/test/resources/META-INF/dubbb-consumer.properties @@ -1,12 +1,11 @@ # Dubbo Consumer Properties as an alternative for # Spring XML Bean definition : META-INF/spring/dubbo-annotation-consumer.xml -demo.service.application = dubbo-annotation-consumer +demo.service.application = dubbo-demo-application demo.service.registry = my-registry ## Dubbo configs binding properties -### -dubbo.applications.dubbo-annotation-consumer.name = Dubbo Consumer -dubbo.applications.dubbo-annotation-consumer2.name = dubbo-consumer2 +### +dubbo.applications.dubbo-demo-application.name = dubbo-demo-application ### dubbo.registries.my-registry.address = N/A diff --git a/dubbo-config/dubbo-config-spring/src/test/resources/META-INF/dubbb-provider.properties b/dubbo-config/dubbo-config-spring/src/test/resources/META-INF/dubbb-provider.properties index 6318375fb3e..f2e20c4df97 100644 --- a/dubbo-config/dubbo-config-spring/src/test/resources/META-INF/dubbb-provider.properties +++ b/dubbo-config/dubbo-config-spring/src/test/resources/META-INF/dubbb-provider.properties @@ -3,7 +3,7 @@ ## Service Providers' Placeholders for org.apache.dubbo.config.spring.context.annotation.provider.DemoServiceImpl -demo.service.application = dubbo-annotation-provider +demo.service.application = dubbo-demo-application demo.service.protocol = dubbo demo.service.registry = my-registry @@ -11,8 +11,8 @@ demo.service.registry = my-registry ## Dubbo configs binding properties ### -dubbo.application.id = dubbo-annotation-provider -dubbo.application.name = Dubbo Provider +dubbo.application.id = dubbo-demo-application +dubbo.application.name = dubbo-demo-application ### dubbo.registry.id = my-registry diff --git a/dubbo-config/dubbo-config-spring/src/test/resources/META-INF/dubbo-consumer.properties b/dubbo-config/dubbo-config-spring/src/test/resources/META-INF/dubbo-consumer.properties new file mode 100644 index 00000000000..094b709165e --- /dev/null +++ b/dubbo-config/dubbo-config-spring/src/test/resources/META-INF/dubbo-consumer.properties @@ -0,0 +1,13 @@ +# Dubbo Consumer Properties as an alternative for +# Spring XML Bean definition : META-INF/spring/dubbo-annotation-consumer.xml +demo.service.application = dubbo-annotation-test +demo.service.registry = my-registry + +## Dubbo configs binding properties +### +# In this UT, the provider will be responsible of loading ApplicationConfig. +dubbo.applications.dubbo-demo-application.name = dubbo-demo-application + +### +dubbo.registries.my-registry.address = N/A +dubbo.registries.my-registry2.address = N/A \ No newline at end of file diff --git a/dubbo-config/dubbo-config-spring/src/test/resources/META-INF/dubbo-provider.properties b/dubbo-config/dubbo-config-spring/src/test/resources/META-INF/dubbo-provider.properties new file mode 100644 index 00000000000..b676caa9fd7 --- /dev/null +++ b/dubbo-config/dubbo-config-spring/src/test/resources/META-INF/dubbo-provider.properties @@ -0,0 +1,24 @@ +# Dubbo Provider Properties as an alternative for +# Spring XML Bean definition : META-INF/spring/dubbo-annotation-provider.xml + +## Service Providers' Placeholders for org.apache.dubbo.config.spring.context.annotation.provider.DemoServiceImpl + +demo.service.application = dubbo-demo-application +demo.service.protocol = dubbo +demo.service.registry = my-registry + + +## Dubbo configs binding properties + +### +dubbo.application.id = dubbo-demo-application +dubbo.application.name = dubbo-demo-application + +### +dubbo.registry.id = my-registry +dubbo.registry.address = N/A + +### +dubbo.protocol.id = dubbo +dubbo.protocol.name = dubbo +dubbo.protocol.port = 12345 \ No newline at end of file diff --git a/dubbo-config/dubbo-config-spring/src/test/resources/META-INF/dubbo.yml b/dubbo-config/dubbo-config-spring/src/test/resources/META-INF/dubbo.yml new file mode 100644 index 00000000000..ed0f0ddbc4c --- /dev/null +++ b/dubbo-config/dubbo-config-spring/src/test/resources/META-INF/dubbo.yml @@ -0,0 +1,8 @@ +dubbo: + consumer: + default: false + client: netty + threadpool: cached + corethreads: 1 + threads: 10 + queues: 99 \ No newline at end of file diff --git a/dubbo-config/dubbo-config-spring/src/test/resources/META-INF/spring/dubbo-annotation-consumer.xml b/dubbo-config/dubbo-config-spring/src/test/resources/META-INF/spring/dubbo-annotation-consumer.xml index f69cc74ca7d..ff3ea637e7e 100644 --- a/dubbo-config/dubbo-config-spring/src/test/resources/META-INF/spring/dubbo-annotation-consumer.xml +++ b/dubbo-config/dubbo-config-spring/src/test/resources/META-INF/spring/dubbo-annotation-consumer.xml @@ -22,7 +22,7 @@ http://dubbo.apache.org/schema/dubbo http://dubbo.apache.org/schema/dubbo/dubbo.xsd"> - + diff --git a/dubbo-config/dubbo-config-spring/src/test/resources/META-INF/spring/dubbo-annotation-provider.xml b/dubbo-config/dubbo-config-spring/src/test/resources/META-INF/spring/dubbo-annotation-provider.xml index 2de22f72fa7..2ac842572c3 100644 --- a/dubbo-config/dubbo-config-spring/src/test/resources/META-INF/spring/dubbo-annotation-provider.xml +++ b/dubbo-config/dubbo-config-spring/src/test/resources/META-INF/spring/dubbo-annotation-provider.xml @@ -22,7 +22,7 @@ "> - + diff --git a/dubbo-config/dubbo-config-spring/src/test/resources/META-INF/spring/dubbo-consumer.xml b/dubbo-config/dubbo-config-spring/src/test/resources/META-INF/spring/dubbo-consumer.xml index 278f018942b..871a35ae71d 100644 --- a/dubbo-config/dubbo-config-spring/src/test/resources/META-INF/spring/dubbo-consumer.xml +++ b/dubbo-config/dubbo-config-spring/src/test/resources/META-INF/spring/dubbo-consumer.xml @@ -22,7 +22,7 @@ http://dubbo.apache.org/schema/dubbo http://dubbo.apache.org/schema/dubbo/dubbo.xsd"> - + diff --git a/dubbo-config/dubbo-config-spring/src/test/resources/META-INF/spring/dubbo-provider.xml b/dubbo-config/dubbo-config-spring/src/test/resources/META-INF/spring/dubbo-provider.xml index dad39b9d736..f7064cd1703 100644 --- a/dubbo-config/dubbo-config-spring/src/test/resources/META-INF/spring/dubbo-provider.xml +++ b/dubbo-config/dubbo-config-spring/src/test/resources/META-INF/spring/dubbo-provider.xml @@ -22,7 +22,7 @@ "> - + diff --git a/dubbo-config/pom.xml b/dubbo-config/pom.xml index 9a75eea5cdd..d1f16c146de 100644 --- a/dubbo-config/pom.xml +++ b/dubbo-config/pom.xml @@ -19,7 +19,7 @@ org.apache.dubbo dubbo-parent - 2.7.0-SNAPSHOT + 2.7.1-SNAPSHOT dubbo-config pom diff --git a/dubbo-configcenter/dubbo-configcenter-api/pom.xml b/dubbo-configcenter/dubbo-configcenter-api/pom.xml index 68b51ff7dd0..7f2715e5b66 100644 --- a/dubbo-configcenter/dubbo-configcenter-api/pom.xml +++ b/dubbo-configcenter/dubbo-configcenter-api/pom.xml @@ -14,13 +14,12 @@ See the License for the specific language governing permissions and limitations under the License. --> - + 4.0.0 org.apache.dubbo dubbo-configcenter - 2.7.0-SNAPSHOT + 2.7.1-SNAPSHOT dubbo-configcenter-api jar diff --git a/dubbo-configcenter/dubbo-configcenter-api/src/main/java/org/apache/dubbo/configcenter/ConfigChangeEvent.java b/dubbo-configcenter/dubbo-configcenter-api/src/main/java/org/apache/dubbo/configcenter/ConfigChangeEvent.java index 950227595a6..4a2190a4796 100644 --- a/dubbo-configcenter/dubbo-configcenter-api/src/main/java/org/apache/dubbo/configcenter/ConfigChangeEvent.java +++ b/dubbo-configcenter/dubbo-configcenter-api/src/main/java/org/apache/dubbo/configcenter/ConfigChangeEvent.java @@ -17,15 +17,15 @@ package org.apache.dubbo.configcenter; /** - * Config change event. + * Config change event, immutable. * * @see ConfigChangeType */ public class ConfigChangeEvent { - private String key; + private final String key; - private String value; - private ConfigChangeType changeType; + private final String value; + private final ConfigChangeType changeType; public ConfigChangeEvent(String key, String value) { this(key, value, ConfigChangeType.MODIFIED); @@ -41,23 +41,12 @@ public String getKey() { return key; } - public void setKey(String key) { - this.key = key; - } - public String getValue() { return value; } - public void setValue(String value) { - this.value = value; - } - public ConfigChangeType getChangeType() { return changeType; } - public void setChangeType(ConfigChangeType changeType) { - this.changeType = changeType; - } -} +} \ No newline at end of file diff --git a/dubbo-configcenter/dubbo-configcenter-api/src/main/resources/META-INF/dubbo/org.apache.dubbo.configcenter.DynamicConfigurationFactory b/dubbo-configcenter/dubbo-configcenter-api/src/main/resources/META-INF/dubbo/internal/org.apache.dubbo.configcenter.DynamicConfigurationFactory similarity index 100% rename from dubbo-configcenter/dubbo-configcenter-api/src/main/resources/META-INF/dubbo/org.apache.dubbo.configcenter.DynamicConfigurationFactory rename to dubbo-configcenter/dubbo-configcenter-api/src/main/resources/META-INF/dubbo/internal/org.apache.dubbo.configcenter.DynamicConfigurationFactory diff --git a/dubbo-configcenter/dubbo-configcenter-apollo/pom.xml b/dubbo-configcenter/dubbo-configcenter-apollo/pom.xml index 18a9fbe870b..040b0eb33a2 100644 --- a/dubbo-configcenter/dubbo-configcenter-apollo/pom.xml +++ b/dubbo-configcenter/dubbo-configcenter-apollo/pom.xml @@ -14,13 +14,12 @@ See the License for the specific language governing permissions and limitations under the License. --> - + 4.0.0 org.apache.dubbo dubbo-configcenter - 2.7.0-SNAPSHOT + 2.7.1-SNAPSHOT dubbo-configcenter-apollo jar diff --git a/dubbo-configcenter/dubbo-configcenter-apollo/src/main/java/org/apache/dubbo/configcenter/support/apollo/ApolloDynamicConfiguration.java b/dubbo-configcenter/dubbo-configcenter-apollo/src/main/java/org/apache/dubbo/configcenter/support/apollo/ApolloDynamicConfiguration.java index c73dcd75f90..ebce3031d73 100644 --- a/dubbo-configcenter/dubbo-configcenter-apollo/src/main/java/org/apache/dubbo/configcenter/support/apollo/ApolloDynamicConfiguration.java +++ b/dubbo-configcenter/dubbo-configcenter-apollo/src/main/java/org/apache/dubbo/configcenter/support/apollo/ApolloDynamicConfiguration.java @@ -33,10 +33,13 @@ import com.ctrip.framework.apollo.enums.PropertyChangeType; import com.ctrip.framework.apollo.model.ConfigChange; +import java.util.Arrays; +import java.util.Collections; import java.util.Set; import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.ConcurrentMap; import java.util.concurrent.CopyOnWriteArraySet; +import java.util.stream.Collectors; /** * Apollo implementation, https://github.com/ctripcorp/apollo @@ -46,6 +49,7 @@ public class ApolloDynamicConfiguration implements DynamicConfiguration { private static final String APOLLO_ENV_KEY = "env"; private static final String APOLLO_ADDR_KEY = "apollo.meta"; private static final String APOLLO_CLUSTER_KEY = "apollo.cluster"; + private static final String APOLLO_PROTOCOL_PREFIX = "http://"; private URL url; private Config dubboConfig; @@ -55,12 +59,12 @@ public class ApolloDynamicConfiguration implements DynamicConfiguration { this.url = url; // Instead of using Dubbo's configuration, I would suggest use the original configuration method Apollo provides. String configEnv = url.getParameter(APOLLO_ENV_KEY); - String configAddr = url.getBackupAddress(); + String configAddr = getAddressWithProtocolPrefix(url); String configCluster = url.getParameter(Constants.CONFIG_CLUSTER_KEY); if (configEnv != null) { System.setProperty(APOLLO_ENV_KEY, configEnv); } - if (StringUtils.isEmpty(configEnv) && !Constants.ANYHOST_VALUE.equals(configAddr)) { + if (StringUtils.isEmpty(System.getProperty(APOLLO_ENV_KEY)) && !Constants.ANYHOST_VALUE.equals(configAddr)) { System.setProperty(APOLLO_ADDR_KEY, configAddr); } if (configCluster != null) { @@ -82,6 +86,21 @@ public class ApolloDynamicConfiguration implements DynamicConfiguration { } } + private String getAddressWithProtocolPrefix (URL url) { + String address = url.getBackupAddress(); + if (StringUtils.isNotEmpty(address)) { + address = Arrays.stream(Constants.COMMA_SPLIT_PATTERN.split(address)) + .map(addr -> { + if (addr.startsWith(APOLLO_PROTOCOL_PREFIX)) { + return addr; + } + return APOLLO_PROTOCOL_PREFIX + addr; + }) + .collect(Collectors.joining(",")); + } + return address; + } + /** * Since all governance rules will lay under dubbo group, this method now always uses the default dubboConfig and * ignores the group parameter. @@ -90,7 +109,7 @@ public class ApolloDynamicConfiguration implements DynamicConfiguration { public void addListener(String key, String group, ConfigurationListener listener) { ApolloListener apolloListener = listeners.computeIfAbsent(group + key, k -> createTargetListener(key, group)); apolloListener.addListener(listener); - dubboConfig.addChangeListener(apolloListener); + dubboConfig.addChangeListener(apolloListener, Collections.singleton(key)); } @Override @@ -112,11 +131,8 @@ public void removeListener(String key, String group, ConfigurationListener liste @Override public String getConfig(String key, String group, long timeout) throws IllegalStateException { if (StringUtils.isNotEmpty(group) && !url.getParameter(Constants.CONFIG_GROUP_KEY, DEFAULT_GROUP).equals(group)) { - Config config = ConfigService.getConfig(group); - if (config != null) { - return config.getProperty(key, null); - } - return null; + Config config = ConfigService.getAppConfig(); + return config.getProperty(key, null); } return dubboConfig.getProperty(key, null); } @@ -160,11 +176,8 @@ public void onChange(com.ctrip.framework.apollo.model.ConfigChangeEvent changeEv return; } - listeners.forEach(listener -> { - ConfigChangeEvent event = new ConfigChangeEvent(key, change.getNewValue(), getChangeType(change)); - listener.process(event); - } - ); + ConfigChangeEvent event = new ConfigChangeEvent(key, change.getNewValue(), getChangeType(change)); + listeners.forEach(listener -> listener.process(event)); } } diff --git a/dubbo-configcenter/dubbo-configcenter-zookeeper/pom.xml b/dubbo-configcenter/dubbo-configcenter-zookeeper/pom.xml index 9b5717cf7b7..bb9e1ad5d45 100644 --- a/dubbo-configcenter/dubbo-configcenter-zookeeper/pom.xml +++ b/dubbo-configcenter/dubbo-configcenter-zookeeper/pom.xml @@ -14,13 +14,12 @@ See the License for the specific language governing permissions and limitations under the License. --> - + 4.0.0 org.apache.dubbo dubbo-configcenter - 2.7.0-SNAPSHOT + 2.7.1-SNAPSHOT dubbo-configcenter-zookeeper jar diff --git a/dubbo-configcenter/dubbo-configcenter-zookeeper/src/main/java/org/apache/dubbo/configcenter/support/zookeeper/CacheListener.java b/dubbo-configcenter/dubbo-configcenter-zookeeper/src/main/java/org/apache/dubbo/configcenter/support/zookeeper/CacheListener.java index d08fe8f1b5a..a1e1f083523 100644 --- a/dubbo-configcenter/dubbo-configcenter-zookeeper/src/main/java/org/apache/dubbo/configcenter/support/zookeeper/CacheListener.java +++ b/dubbo-configcenter/dubbo-configcenter-zookeeper/src/main/java/org/apache/dubbo/configcenter/support/zookeeper/CacheListener.java @@ -65,7 +65,7 @@ public void childEvent(CuratorFramework aClient, TreeCacheEvent event) throws Ex // TODO We limit the notification of config changes to a specific path level, for example // /dubbo/config/service/configurators, other config changes not in this level will not get notified, // say /dubbo/config/dubbo.properties - if (data.getPath().split("/").length == 5) { + if (data.getPath().split("/").length >= 5) { byte[] value = data.getData(); String key = pathToKey(data.getPath()); ConfigChangeType changeType; diff --git a/dubbo-configcenter/dubbo-configcenter-zookeeper/src/main/java/org/apache/dubbo/configcenter/support/zookeeper/ZookeeperDynamicConfiguration.java b/dubbo-configcenter/dubbo-configcenter-zookeeper/src/main/java/org/apache/dubbo/configcenter/support/zookeeper/ZookeeperDynamicConfiguration.java index 13cb9111f4d..7a106f86dec 100644 --- a/dubbo-configcenter/dubbo-configcenter-zookeeper/src/main/java/org/apache/dubbo/configcenter/support/zookeeper/ZookeeperDynamicConfiguration.java +++ b/dubbo-configcenter/dubbo-configcenter-zookeeper/src/main/java/org/apache/dubbo/configcenter/support/zookeeper/ZookeeperDynamicConfiguration.java @@ -122,13 +122,18 @@ public void removeListener(String key, String group, ConfigurationListener liste @Override public String getConfig(String key, String group, long timeout) throws IllegalStateException { - // when group is not null, we are getting startup configs from Config Center - // for example, group=dubbo, key=dubbo.properties + /** + * when group is not null, we are getting startup configs from Config Center, for example: + * group=dubbo, key=dubbo.properties + */ if (StringUtils.isNotEmpty(group)) { key = group + "/" + key; } - // when group is null, we are fetching governance rules. - // for example, key=org.apache.dubbo.DemoService.configurators + /** + * when group is null, we are fetching governance rules, for example: + * 1. key=org.apache.dubbo.DemoService.configurators + * 2. key = org.apache.dubbo.DemoService.condition-router + */ else { int i = key.lastIndexOf("."); key = key.substring(0, i) + "/" + key.substring(i + 1); diff --git a/dubbo-configcenter/pom.xml b/dubbo-configcenter/pom.xml index e969c044b02..6512dc4fd57 100644 --- a/dubbo-configcenter/pom.xml +++ b/dubbo-configcenter/pom.xml @@ -14,13 +14,12 @@ See the License for the specific language governing permissions and limitations under the License. --> - + 4.0.0 org.apache.dubbo dubbo-parent - 2.7.0-SNAPSHOT + 2.7.1-SNAPSHOT dubbo-configcenter pom diff --git a/dubbo-container/dubbo-container-api/pom.xml b/dubbo-container/dubbo-container-api/pom.xml index 13efee6964b..2c1e9100af5 100644 --- a/dubbo-container/dubbo-container-api/pom.xml +++ b/dubbo-container/dubbo-container-api/pom.xml @@ -19,7 +19,7 @@ org.apache.dubbo dubbo-container - 2.7.0-SNAPSHOT + 2.7.1-SNAPSHOT dubbo-container-api jar @@ -51,4 +51,4 @@ - \ No newline at end of file + diff --git a/dubbo-container/dubbo-container-api/src/main/resources/META-INF/assembly/bin/start.sh b/dubbo-container/dubbo-container-api/src/main/resources/META-INF/assembly/bin/start.sh index 595b7695d44..56e39143f0c 100755 --- a/dubbo-container/dubbo-container-api/src/main/resources/META-INF/assembly/bin/start.sh +++ b/dubbo-container/dubbo-container-api/src/main/resources/META-INF/assembly/bin/start.sh @@ -90,7 +90,7 @@ while [ $COUNT -lt 1 ]; do sleep 1 if [ -n "$SERVER_PORT" ]; then if [ "$SERVER_PROTOCOL" == "dubbo" ]; then - COUNT=`echo status | nc -i 1 $SERVER_HOST $SERVER_PORT | grep -c OK` + COUNT=`(sleep 1; echo -e '\n'; sleep 1; echo status; sleep 1)| telnet $SERVER_HOST $SERVER_PORT | grep -c OK` else COUNT=`netstat -an | grep $SERVER_PORT | wc -l` fi diff --git a/dubbo-container/dubbo-container-log4j/pom.xml b/dubbo-container/dubbo-container-log4j/pom.xml index 91814b3a9dd..be5a1733a36 100644 --- a/dubbo-container/dubbo-container-log4j/pom.xml +++ b/dubbo-container/dubbo-container-log4j/pom.xml @@ -19,7 +19,7 @@ org.apache.dubbo dubbo-container - 2.7.0-SNAPSHOT + 2.7.1-SNAPSHOT dubbo-container-log4j jar diff --git a/dubbo-container/dubbo-container-logback/pom.xml b/dubbo-container/dubbo-container-logback/pom.xml index 6227931bc74..9a1aa47eda2 100644 --- a/dubbo-container/dubbo-container-logback/pom.xml +++ b/dubbo-container/dubbo-container-logback/pom.xml @@ -19,7 +19,7 @@ org.apache.dubbo dubbo-container - 2.7.0-SNAPSHOT + 2.7.1-SNAPSHOT dubbo-container-logback jar diff --git a/dubbo-container/dubbo-container-spring/pom.xml b/dubbo-container/dubbo-container-spring/pom.xml index 987b2c9d2e6..83298634f27 100644 --- a/dubbo-container/dubbo-container-spring/pom.xml +++ b/dubbo-container/dubbo-container-spring/pom.xml @@ -1,42 +1,42 @@ - - - 4.0.0 - - org.apache.dubbo - dubbo-container - 2.7.0-SNAPSHOT - - dubbo-container-spring - jar - ${project.artifactId} - The spring container module of dubbo project - - false - - - - org.apache.dubbo - dubbo-container-api - ${project.parent.version} - - - org.springframework - spring-context - - - + + + 4.0.0 + + org.apache.dubbo + dubbo-container + 2.7.1-SNAPSHOT + + dubbo-container-spring + jar + ${project.artifactId} + The spring container module of dubbo project + + false + + + + org.apache.dubbo + dubbo-container-api + ${project.parent.version} + + + org.springframework + spring-context + + + diff --git a/dubbo-container/pom.xml b/dubbo-container/pom.xml index 753a0cdfa6c..932899488ec 100644 --- a/dubbo-container/pom.xml +++ b/dubbo-container/pom.xml @@ -19,7 +19,7 @@ org.apache.dubbo dubbo-parent - 2.7.0-SNAPSHOT + 2.7.1-SNAPSHOT dubbo-container pom diff --git a/dubbo-demo/dubbo-demo-annotation/dubbo-demo-annotation-consumer/pom.xml b/dubbo-demo/dubbo-demo-annotation/dubbo-demo-annotation-consumer/pom.xml index 1162f374a38..58e260ed592 100644 --- a/dubbo-demo/dubbo-demo-annotation/dubbo-demo-annotation-consumer/pom.xml +++ b/dubbo-demo/dubbo-demo-annotation/dubbo-demo-annotation-consumer/pom.xml @@ -18,13 +18,11 @@ ~ under the License. --> - + dubbo-demo-annotation org.apache.dubbo - 2.7.0-SNAPSHOT + 2.7.1-SNAPSHOT 4.0.0 diff --git a/dubbo-demo/dubbo-demo-annotation/dubbo-demo-annotation-provider/pom.xml b/dubbo-demo/dubbo-demo-annotation/dubbo-demo-annotation-provider/pom.xml index d53c34564d7..bf6bc8fd9df 100644 --- a/dubbo-demo/dubbo-demo-annotation/dubbo-demo-annotation-provider/pom.xml +++ b/dubbo-demo/dubbo-demo-annotation/dubbo-demo-annotation-provider/pom.xml @@ -18,13 +18,11 @@ ~ under the License. --> - + dubbo-demo-annotation org.apache.dubbo - 2.7.0-SNAPSHOT + 2.7.1-SNAPSHOT 4.0.0 diff --git a/dubbo-demo/dubbo-demo-annotation/pom.xml b/dubbo-demo/dubbo-demo-annotation/pom.xml index abaabf3d282..f94870dc563 100644 --- a/dubbo-demo/dubbo-demo-annotation/pom.xml +++ b/dubbo-demo/dubbo-demo-annotation/pom.xml @@ -18,13 +18,11 @@ ~ under the License. --> - + dubbo-demo org.apache.dubbo - 2.7.0-SNAPSHOT + 2.7.1-SNAPSHOT 4.0.0 pom diff --git a/dubbo-demo/dubbo-demo-api/dubbo-demo-api-consumer/pom.xml b/dubbo-demo/dubbo-demo-api/dubbo-demo-api-consumer/pom.xml index f6ab74e5f09..947537667b5 100644 --- a/dubbo-demo/dubbo-demo-api/dubbo-demo-api-consumer/pom.xml +++ b/dubbo-demo/dubbo-demo-api/dubbo-demo-api-consumer/pom.xml @@ -18,13 +18,11 @@ ~ under the License. --> - + dubbo-demo-api org.apache.dubbo - 2.7.0-SNAPSHOT + 2.7.1-SNAPSHOT 4.0.0 diff --git a/dubbo-demo/dubbo-demo-api/dubbo-demo-api-provider/pom.xml b/dubbo-demo/dubbo-demo-api/dubbo-demo-api-provider/pom.xml index 2bcf47b0ea0..d2dd9af1c85 100644 --- a/dubbo-demo/dubbo-demo-api/dubbo-demo-api-provider/pom.xml +++ b/dubbo-demo/dubbo-demo-api/dubbo-demo-api-provider/pom.xml @@ -18,13 +18,11 @@ ~ under the License. --> - + dubbo-demo-api org.apache.dubbo - 2.7.0-SNAPSHOT + 2.7.1-SNAPSHOT 4.0.0 diff --git a/dubbo-demo/dubbo-demo-api/dubbo-demo-api-provider/src/main/java/org/apache/dubbo/demo/provider/DemoServiceImpl.java b/dubbo-demo/dubbo-demo-api/dubbo-demo-api-provider/src/main/java/org/apache/dubbo/demo/provider/DemoServiceImpl.java index d0d315c9b4e..5e2ef2350d2 100644 --- a/dubbo-demo/dubbo-demo-api/dubbo-demo-api-provider/src/main/java/org/apache/dubbo/demo/provider/DemoServiceImpl.java +++ b/dubbo-demo/dubbo-demo-api/dubbo-demo-api-provider/src/main/java/org/apache/dubbo/demo/provider/DemoServiceImpl.java @@ -1,34 +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.demo.provider; - -import org.apache.dubbo.demo.DemoService; -import org.apache.dubbo.rpc.RpcContext; - -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -public class DemoServiceImpl implements DemoService { - private static final Logger logger = LoggerFactory.getLogger(DemoServiceImpl.class); - - @Override - public String sayHello(String name) { - logger.info("Hello " + name + ", request from consumer: " + RpcContext.getContext().getRemoteAddress()); - return "Hello " + name + ", response from provider: " + RpcContext.getContext().getLocalAddress(); - } - -} +/* + * 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.demo.provider; + +import org.apache.dubbo.demo.DemoService; +import org.apache.dubbo.rpc.RpcContext; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +public class DemoServiceImpl implements DemoService { + private static final Logger logger = LoggerFactory.getLogger(DemoServiceImpl.class); + + @Override + public String sayHello(String name) { + logger.info("Hello " + name + ", request from consumer: " + RpcContext.getContext().getRemoteAddress()); + return "Hello " + name + ", response from provider: " + RpcContext.getContext().getLocalAddress(); + } + +} diff --git a/dubbo-demo/dubbo-demo-api/pom.xml b/dubbo-demo/dubbo-demo-api/pom.xml index 325b62bc116..b9088fc4d37 100644 --- a/dubbo-demo/dubbo-demo-api/pom.xml +++ b/dubbo-demo/dubbo-demo-api/pom.xml @@ -18,13 +18,11 @@ ~ under the License. --> - + dubbo-demo org.apache.dubbo - 2.7.0-SNAPSHOT + 2.7.1-SNAPSHOT 4.0.0 pom diff --git a/dubbo-demo/dubbo-demo-interface/pom.xml b/dubbo-demo/dubbo-demo-interface/pom.xml index d84b594d3b9..f6376c91578 100644 --- a/dubbo-demo/dubbo-demo-interface/pom.xml +++ b/dubbo-demo/dubbo-demo-interface/pom.xml @@ -19,7 +19,7 @@ org.apache.dubbo dubbo-demo - 2.7.0-SNAPSHOT + 2.7.1-SNAPSHOT dubbo-demo-interface jar diff --git a/dubbo-demo/dubbo-demo-xml/dubbo-demo-xml-consumer/pom.xml b/dubbo-demo/dubbo-demo-xml/dubbo-demo-xml-consumer/pom.xml index f2bcda4bbac..84874591535 100644 --- a/dubbo-demo/dubbo-demo-xml/dubbo-demo-xml-consumer/pom.xml +++ b/dubbo-demo/dubbo-demo-xml/dubbo-demo-xml-consumer/pom.xml @@ -19,7 +19,7 @@ org.apache.dubbo dubbo-demo-xml - 2.7.0-SNAPSHOT + 2.7.1-SNAPSHOT dubbo-demo-xml-consumer jar diff --git a/dubbo-demo/dubbo-demo-xml/dubbo-demo-xml-provider/pom.xml b/dubbo-demo/dubbo-demo-xml/dubbo-demo-xml-provider/pom.xml index 99faa90e6fc..fbd0f041497 100644 --- a/dubbo-demo/dubbo-demo-xml/dubbo-demo-xml-provider/pom.xml +++ b/dubbo-demo/dubbo-demo-xml/dubbo-demo-xml-provider/pom.xml @@ -19,7 +19,7 @@ org.apache.dubbo dubbo-demo-xml - 2.7.0-SNAPSHOT + 2.7.1-SNAPSHOT dubbo-demo-xml-provider jar diff --git a/dubbo-demo/dubbo-demo-xml/pom.xml b/dubbo-demo/dubbo-demo-xml/pom.xml index d61536254c1..fbbcae942b8 100644 --- a/dubbo-demo/dubbo-demo-xml/pom.xml +++ b/dubbo-demo/dubbo-demo-xml/pom.xml @@ -18,13 +18,11 @@ ~ under the License. --> - + dubbo-demo org.apache.dubbo - 2.7.0-SNAPSHOT + 2.7.1-SNAPSHOT 4.0.0 pom diff --git a/dubbo-demo/pom.xml b/dubbo-demo/pom.xml index 9e506066b58..77d59aebcdd 100644 --- a/dubbo-demo/pom.xml +++ b/dubbo-demo/pom.xml @@ -19,7 +19,7 @@ org.apache.dubbo dubbo-parent - 2.7.0-SNAPSHOT + 2.7.1-SNAPSHOT dubbo-demo pom diff --git a/dubbo-dependencies-bom/pom.xml b/dubbo-dependencies-bom/pom.xml index 939492bd8e0..77ca3b904d7 100644 --- a/dubbo-dependencies-bom/pom.xml +++ b/dubbo-dependencies-bom/pom.xml @@ -6,11 +6,12 @@ org.apache apache 19 + org.apache.dubbo dubbo-dependencies-bom - 2.7.0-SNAPSHOT + 2.7.1-SNAPSHOT pom dubbo-dependencies-bom @@ -120,6 +121,8 @@ 1.2.0 3.2.3 1.5.19 + 4.3.16.RELEASE + 2.8.5 @@ -457,6 +460,13 @@ ${embedded_redis_version} test + + org.springframework + spring-test + ${spring_test_version} + test + + com.google.code.gson gson diff --git a/dubbo-distribution/pom.xml b/dubbo-distribution/pom.xml index c5c6f0a2af6..b018cec4e50 100644 --- a/dubbo-distribution/pom.xml +++ b/dubbo-distribution/pom.xml @@ -19,7 +19,7 @@ org.apache.dubbo dubbo-parent - 2.7.0-SNAPSHOT + 2.7.1-SNAPSHOT dubbo-distribution pom @@ -260,7 +260,7 @@ release - dubbo-incubating-${project.version} + apache-dubbo-incubating-${project.version} maven-assembly-plugin diff --git a/dubbo-distribution/src/assembly/source-release.xml b/dubbo-distribution/src/assembly/source-release.xml index bd85f58b119..434377bdd3a 100644 --- a/dubbo-distribution/src/assembly/source-release.xml +++ b/dubbo-distribution/src/assembly/source-release.xml @@ -46,6 +46,10 @@ **/*.log release.properties **/*.xml.* + **/*.patch + **/.mvn/** + **/*.jar + **/mvnw* diff --git a/dubbo-filter/dubbo-filter-cache/pom.xml b/dubbo-filter/dubbo-filter-cache/pom.xml index 43f72b36ef5..bec6067478d 100644 --- a/dubbo-filter/dubbo-filter-cache/pom.xml +++ b/dubbo-filter/dubbo-filter-cache/pom.xml @@ -1,48 +1,48 @@ - - - 4.0.0 - - org.apache.dubbo - dubbo-filter - 2.7.0-SNAPSHOT - - dubbo-filter-cache - jar - ${project.artifactId} - The cache module of dubbo project - - false - - - - org.apache.dubbo - dubbo-rpc-api - ${project.parent.version} - - - javax.cache - cache-api - - - com.hazelcast - hazelcast - test - ${hazelcast_version} - - + + + 4.0.0 + + org.apache.dubbo + dubbo-filter + 2.7.1-SNAPSHOT + + dubbo-filter-cache + jar + ${project.artifactId} + The cache module of dubbo project + + false + + + + org.apache.dubbo + dubbo-rpc-api + ${project.parent.version} + + + javax.cache + cache-api + + + com.hazelcast + hazelcast + test + ${hazelcast_version} + + \ No newline at end of file diff --git a/dubbo-filter/dubbo-filter-validation/pom.xml b/dubbo-filter/dubbo-filter-validation/pom.xml index 9cebd4b805e..9ce481061d2 100644 --- a/dubbo-filter/dubbo-filter-validation/pom.xml +++ b/dubbo-filter/dubbo-filter-validation/pom.xml @@ -1,72 +1,72 @@ - - - 4.0.0 - - org.apache.dubbo - dubbo-filter - 2.7.0-SNAPSHOT - - dubbo-filter-validation - jar - ${project.artifactId} - The validation module of dubbo project - - false - - - - org.apache.dubbo - dubbo-rpc-api - ${project.parent.version} - - - javax.validation - validation-api - - - org.hibernate - hibernate-validator - test - ${hibernate_validator_version} - - - javax.el - javax.el-api - test - ${el_api_version} - - - javax.xml.bind - jaxb-api - test - ${jaxb_api_version} - - - com.sun.xml.bind - jaxb-impl - test - ${jaxb_api_version} - - - com.sun.xml.bind - jaxb-core - test - ${jaxb_api_version} - - + + + 4.0.0 + + org.apache.dubbo + dubbo-filter + 2.7.1-SNAPSHOT + + dubbo-filter-validation + jar + ${project.artifactId} + The validation module of dubbo project + + false + + + + org.apache.dubbo + dubbo-rpc-api + ${project.parent.version} + + + javax.validation + validation-api + + + org.hibernate + hibernate-validator + test + ${hibernate_validator_version} + + + javax.el + javax.el-api + test + ${el_api_version} + + + javax.xml.bind + jaxb-api + test + ${jaxb_api_version} + + + com.sun.xml.bind + jaxb-impl + test + ${jaxb_api_version} + + + com.sun.xml.bind + jaxb-core + test + ${jaxb_api_version} + + \ No newline at end of file diff --git a/dubbo-filter/pom.xml b/dubbo-filter/pom.xml index 7b204977106..f9851412296 100644 --- a/dubbo-filter/pom.xml +++ b/dubbo-filter/pom.xml @@ -19,7 +19,7 @@ org.apache.dubbo dubbo-parent - 2.7.0-SNAPSHOT + 2.7.1-SNAPSHOT dubbo-filter pom diff --git a/dubbo-metadata-report/dubbo-metadata-definition/pom.xml b/dubbo-metadata-report/dubbo-metadata-definition/pom.xml index 8311b28c4a0..09dc860fb60 100644 --- a/dubbo-metadata-report/dubbo-metadata-definition/pom.xml +++ b/dubbo-metadata-report/dubbo-metadata-definition/pom.xml @@ -14,13 +14,11 @@ See the License for the specific language governing permissions and limitations under the License. --> - + dubbo-metadata-report org.apache.dubbo - 2.7.0-SNAPSHOT + 2.7.1-SNAPSHOT 4.0.0 diff --git a/dubbo-metadata-report/dubbo-metadata-definition/src/main/java/org/apache/dubbo/metadata/definition/TypeDefinitionBuilder.java b/dubbo-metadata-report/dubbo-metadata-definition/src/main/java/org/apache/dubbo/metadata/definition/TypeDefinitionBuilder.java index 797d9f8a0e5..53e8c88b8f3 100755 --- a/dubbo-metadata-report/dubbo-metadata-definition/src/main/java/org/apache/dubbo/metadata/definition/TypeDefinitionBuilder.java +++ b/dubbo-metadata-report/dubbo-metadata-definition/src/main/java/org/apache/dubbo/metadata/definition/TypeDefinitionBuilder.java @@ -26,6 +26,7 @@ import java.lang.reflect.Type; import java.util.ArrayList; +import java.util.Arrays; import java.util.HashMap; import java.util.List; import java.util.Map; @@ -35,20 +36,16 @@ */ public class TypeDefinitionBuilder { - private static final ThreadLocal> builders; + private static final TypeBuilder ARRAY_BUILDER = new ArrayTypeBuilder(); + private static final TypeBuilder COLLECTION_BUILDER = new CollectionTypeBuilder(); + private static final TypeBuilder MAP_BUILDER = new MapTypeBuilder(); + private static final TypeBuilder ENUM_BUILDER = new EnumTypeBuilder(); - static { - builders = new ThreadLocal>(); - builders.set(new ArrayList()); - builders.get().add(new ArrayTypeBuilder()); - builders.get().add(new CollectionTypeBuilder()); - builders.get().add(new MapTypeBuilder()); - builders.get().add(new EnumTypeBuilder()); - } + private static final List BUILDERS = Arrays.asList(ARRAY_BUILDER, COLLECTION_BUILDER, MAP_BUILDER, ENUM_BUILDER); public static TypeDefinition build(Type type, Class clazz, Map, TypeDefinition> typeCache) { TypeBuilder builder = getGenericTypeBuilder(type, clazz); - TypeDefinition td = null; + TypeDefinition td; if (builder != null) { td = builder.build(type, clazz, typeCache); } else { @@ -58,7 +55,7 @@ public static TypeDefinition build(Type type, Class clazz, Map, Type } private static TypeBuilder getGenericTypeBuilder(Type type, Class clazz) { - for (TypeBuilder builder : builders.get()) { + for (TypeBuilder builder : BUILDERS) { if (builder.accept(type, clazz)) { return builder; } @@ -66,14 +63,14 @@ private static TypeBuilder getGenericTypeBuilder(Type type, Class clazz) { return null; } - private Map, TypeDefinition> typeCache = new HashMap, TypeDefinition>(); + private Map, TypeDefinition> typeCache = new HashMap<>(); public TypeDefinition build(Type type, Class clazz) { return build(type, clazz, typeCache); } public List getTypeDefinitions() { - return new ArrayList(typeCache.values()); + return new ArrayList<>(typeCache.values()); } } diff --git a/dubbo-metadata-report/dubbo-metadata-definition/src/main/java/org/apache/dubbo/metadata/definition/builder/ArrayTypeBuilder.java b/dubbo-metadata-report/dubbo-metadata-definition/src/main/java/org/apache/dubbo/metadata/definition/builder/ArrayTypeBuilder.java index ce53c708682..9ad61cefb26 100755 --- a/dubbo-metadata-report/dubbo-metadata-definition/src/main/java/org/apache/dubbo/metadata/definition/builder/ArrayTypeBuilder.java +++ b/dubbo-metadata-report/dubbo-metadata-definition/src/main/java/org/apache/dubbo/metadata/definition/builder/ArrayTypeBuilder.java @@ -32,12 +32,7 @@ public boolean accept(Type type, Class clazz) { if (clazz == null) { return false; } - - if (clazz.isArray()) { - return true; - } - - return false; + return clazz.isArray(); } @Override @@ -47,8 +42,7 @@ public TypeDefinition build(Type type, Class clazz, Map, TypeDefinit TypeDefinitionBuilder.build(componentType, componentType, typeCache); final String canonicalName = clazz.getCanonicalName(); - TypeDefinition td = new TypeDefinition(canonicalName); - return td; + return new TypeDefinition(canonicalName); } } diff --git a/dubbo-metadata-report/dubbo-metadata-definition/src/main/java/org/apache/dubbo/metadata/definition/builder/CollectionTypeBuilder.java b/dubbo-metadata-report/dubbo-metadata-definition/src/main/java/org/apache/dubbo/metadata/definition/builder/CollectionTypeBuilder.java index 14c3b4ba68c..24b1c868a1b 100755 --- a/dubbo-metadata-report/dubbo-metadata-definition/src/main/java/org/apache/dubbo/metadata/definition/builder/CollectionTypeBuilder.java +++ b/dubbo-metadata-report/dubbo-metadata-definition/src/main/java/org/apache/dubbo/metadata/definition/builder/CollectionTypeBuilder.java @@ -28,20 +28,14 @@ /** * 2015/1/27. */ -public class -CollectionTypeBuilder implements TypeBuilder { +public class CollectionTypeBuilder implements TypeBuilder { @Override public boolean accept(Type type, Class clazz) { if (clazz == null) { return false; } - - if (Collection.class.isAssignableFrom(clazz)) { - return true; - } - - return false; + return Collection.class.isAssignableFrom(clazz); } @Override @@ -72,8 +66,7 @@ public TypeDefinition build(Type type, Class clazz, Map, TypeDefinit } } - TypeDefinition td = new TypeDefinition(type.toString()); - return td; + return new TypeDefinition(type.toString()); } } diff --git a/dubbo-metadata-report/dubbo-metadata-definition/src/main/java/org/apache/dubbo/metadata/definition/builder/EnumTypeBuilder.java b/dubbo-metadata-report/dubbo-metadata-definition/src/main/java/org/apache/dubbo/metadata/definition/builder/EnumTypeBuilder.java index cca8c9ca81d..d0dea96302c 100755 --- a/dubbo-metadata-report/dubbo-metadata-definition/src/main/java/org/apache/dubbo/metadata/definition/builder/EnumTypeBuilder.java +++ b/dubbo-metadata-report/dubbo-metadata-definition/src/main/java/org/apache/dubbo/metadata/definition/builder/EnumTypeBuilder.java @@ -32,12 +32,7 @@ public boolean accept(Type type, Class clazz) { if (clazz == null) { return false; } - - if (clazz.isEnum()) { - return true; - } - - return false; + return clazz.isEnum(); } @Override diff --git a/dubbo-metadata-report/dubbo-metadata-definition/src/main/java/org/apache/dubbo/metadata/definition/builder/MapTypeBuilder.java b/dubbo-metadata-report/dubbo-metadata-definition/src/main/java/org/apache/dubbo/metadata/definition/builder/MapTypeBuilder.java index 4c7cf93c866..bf2b22209cd 100755 --- a/dubbo-metadata-report/dubbo-metadata-definition/src/main/java/org/apache/dubbo/metadata/definition/builder/MapTypeBuilder.java +++ b/dubbo-metadata-report/dubbo-metadata-definition/src/main/java/org/apache/dubbo/metadata/definition/builder/MapTypeBuilder.java @@ -34,12 +34,7 @@ public boolean accept(Type type, Class clazz) { if (clazz == null) { return false; } - - if (Map.class.isAssignableFrom(clazz)) { - return true; - } - - return false; + return Map.class.isAssignableFrom(clazz); } @Override diff --git a/dubbo-metadata-report/dubbo-metadata-definition/src/test/java/org/apache/dubbo/metadata/definition/service/ComplexObject.java b/dubbo-metadata-report/dubbo-metadata-definition/src/test/java/org/apache/dubbo/metadata/definition/service/ComplexObject.java index 60a467a75b2..2859a13be8c 100644 --- a/dubbo-metadata-report/dubbo-metadata-definition/src/test/java/org/apache/dubbo/metadata/definition/service/ComplexObject.java +++ b/dubbo-metadata-report/dubbo-metadata-definition/src/test/java/org/apache/dubbo/metadata/definition/service/ComplexObject.java @@ -225,7 +225,7 @@ public String getInnerA2() { return innerA2; } - public void setInnerA2(String innerA) { + public void setInnerA2(String innerA2) { this.innerA2 = innerA2; } @@ -233,7 +233,7 @@ public int getInnerB2() { return innerB2; } - public void setInnerB2(int innerB) { + public void setInnerB2(int innerB2) { this.innerB2 = innerB2; } diff --git a/dubbo-metadata-report/dubbo-metadata-report-api/pom.xml b/dubbo-metadata-report/dubbo-metadata-report-api/pom.xml index 34970027a84..6244d0407f8 100644 --- a/dubbo-metadata-report/dubbo-metadata-report-api/pom.xml +++ b/dubbo-metadata-report/dubbo-metadata-report-api/pom.xml @@ -14,13 +14,11 @@ See the License for the specific language governing permissions and limitations under the License. --> - + dubbo-metadata-report org.apache.dubbo - 2.7.0-SNAPSHOT + 2.7.1-SNAPSHOT 4.0.0 @@ -68,14 +66,5 @@ com.google.code.gson gson - - org.apache.dubbo - dubbo-metadata-definition - ${project.parent.version} - - - com.google.code.gson - gson - diff --git a/dubbo-metadata-report/dubbo-metadata-report-api/src/main/java/org/apache/dubbo/metadata/identifier/MetadataIdentifier.java b/dubbo-metadata-report/dubbo-metadata-report-api/src/main/java/org/apache/dubbo/metadata/identifier/MetadataIdentifier.java index 81c3d45bad8..fca21bfbc99 100644 --- a/dubbo-metadata-report/dubbo-metadata-report-api/src/main/java/org/apache/dubbo/metadata/identifier/MetadataIdentifier.java +++ b/dubbo-metadata-report/dubbo-metadata-report-api/src/main/java/org/apache/dubbo/metadata/identifier/MetadataIdentifier.java @@ -66,8 +66,8 @@ private String getFilePathKey() { return getFilePathKey(DEFAULT_PATH_TAG); } - public String getFilePathKey(String pathTag) { - return toServicePath() + Constants.PATH_SEPARATOR + pathTag + Constants.PATH_SEPARATOR + (version == null ? "" : (version + Constants.PATH_SEPARATOR)) + private String getFilePathKey(String pathTag) { + return pathTag + Constants.PATH_SEPARATOR + toServicePath() + Constants.PATH_SEPARATOR + (version == null ? "" : (version + Constants.PATH_SEPARATOR)) + (group == null ? "" : (group + Constants.PATH_SEPARATOR)) + side + Constants.PATH_SEPARATOR + getApplication(); } diff --git a/dubbo-metadata-report/dubbo-metadata-report-api/src/main/java/org/apache/dubbo/metadata/integration/MetadataReportService.java b/dubbo-metadata-report/dubbo-metadata-report-api/src/main/java/org/apache/dubbo/metadata/integration/MetadataReportService.java index d0dfa733770..c457950f2f8 100644 --- a/dubbo-metadata-report/dubbo-metadata-report-api/src/main/java/org/apache/dubbo/metadata/integration/MetadataReportService.java +++ b/dubbo-metadata-report/dubbo-metadata-report-api/src/main/java/org/apache/dubbo/metadata/integration/MetadataReportService.java @@ -38,7 +38,7 @@ public class MetadataReportService { protected final Logger logger = LoggerFactory.getLogger(getClass()); - private static MetadataReportService metadataReportService; + private static volatile MetadataReportService metadataReportService; private static Object lock = new Object(); private MetadataReportFactory metadataReportFactory = ExtensionLoader.getExtensionLoader(MetadataReportFactory.class).getAdaptiveExtension(); diff --git a/dubbo-metadata-report/dubbo-metadata-report-api/src/main/java/org/apache/dubbo/metadata/support/AbstractMetadataReport.java b/dubbo-metadata-report/dubbo-metadata-report-api/src/main/java/org/apache/dubbo/metadata/support/AbstractMetadataReport.java index 09e6e0bb318..f6bcad77ade 100644 --- a/dubbo-metadata-report/dubbo-metadata-report-api/src/main/java/org/apache/dubbo/metadata/support/AbstractMetadataReport.java +++ b/dubbo-metadata-report/dubbo-metadata-report-api/src/main/java/org/apache/dubbo/metadata/support/AbstractMetadataReport.java @@ -134,27 +134,23 @@ private void doSaveProperties(long version) { if (!lockfile.exists()) { lockfile.createNewFile(); } - RandomAccessFile raf = new RandomAccessFile(lockfile, "rw"); - try { - try (FileChannel channel = raf.getChannel()) { - FileLock lock = channel.tryLock(); - if (lock == null) { - throw new IOException("Can not lock the metadataReport cache file " + file.getAbsolutePath() + ", ignore and retry later, maybe multi java process use the file, please config: dubbo.metadata.file=xxx.properties"); + try (RandomAccessFile raf = new RandomAccessFile(lockfile, "rw"); + FileChannel channel = raf.getChannel()) { + FileLock lock = channel.tryLock(); + if (lock == null) { + throw new IOException("Can not lock the metadataReport cache file " + file.getAbsolutePath() + ", ignore and retry later, maybe multi java process use the file, please config: dubbo.metadata.file=xxx.properties"); + } + // Save + try { + if (!file.exists()) { + file.createNewFile(); } - // Save - try { - if (!file.exists()) { - file.createNewFile(); - } - try (FileOutputStream outputFile = new FileOutputStream(file)) { - properties.store(outputFile, "Dubbo metadataReport Cache"); - } - } finally { - lock.release(); + try (FileOutputStream outputFile = new FileOutputStream(file)) { + properties.store(outputFile, "Dubbo metadataReport Cache"); } + } finally { + lock.release(); } - } finally { - raf.close(); } } catch (Throwable e) { if (version < lastCacheChanged.get()) { @@ -168,23 +164,13 @@ private void doSaveProperties(long version) { void loadProperties() { if (file != null && file.exists()) { - InputStream in = null; - try { - in = new FileInputStream(file); + try (InputStream in = new FileInputStream(file)) { properties.load(in); if (logger.isInfoEnabled()) { logger.info("Load service store file " + file + ", data: " + properties); } } catch (Throwable e) { logger.warn("Failed to load service store file " + file, e); - } finally { - if (in != null) { - try { - in.close(); - } catch (IOException e) { - logger.warn(e.getMessage(), e); - } - } } } } @@ -332,6 +318,7 @@ private boolean doHandleMetadataCollection(Map metad * not private. just for unittest. */ void publishAll() { + logger.info("start to publish all metadata."); this.doHandleMetadataCollection(allMetadataReports); } @@ -356,7 +343,7 @@ class MetadataReportRetry { protected final Logger logger = LoggerFactory.getLogger(getClass()); final ScheduledExecutorService retryExecutor = Executors.newScheduledThreadPool(0, new NamedThreadFactory("DubboRegistryFailedRetryTimer", true)); - ScheduledFuture retryScheduledFuture; + volatile ScheduledFuture retryScheduledFuture; AtomicInteger retryCounter = new AtomicInteger(0); // retry task schedule period long retryPeriod; diff --git a/dubbo-metadata-report/dubbo-metadata-report-api/src/main/java/org/apache/dubbo/metadata/support/AbstractMetadataReportFactory.java b/dubbo-metadata-report/dubbo-metadata-report-api/src/main/java/org/apache/dubbo/metadata/support/AbstractMetadataReportFactory.java index 392350ccd79..f3ce5d68c92 100644 --- a/dubbo-metadata-report/dubbo-metadata-report-api/src/main/java/org/apache/dubbo/metadata/support/AbstractMetadataReportFactory.java +++ b/dubbo-metadata-report/dubbo-metadata-report-api/src/main/java/org/apache/dubbo/metadata/support/AbstractMetadataReportFactory.java @@ -38,7 +38,6 @@ public abstract class AbstractMetadataReportFactory implements MetadataReportFac @Override public MetadataReport getMetadataReport(URL url) { url = url.setPath(MetadataReport.class.getName()) - .addParameter(Constants.INTERFACE_KEY, MetadataReport.class.getName()) .removeParameters(Constants.EXPORT_KEY, Constants.REFER_KEY); String key = url.toServiceString(); // Lock the registry access process to ensure a single instance of the registry diff --git a/dubbo-metadata-report/dubbo-metadata-report-api/src/test/java/org/apache/dubbo/metadata/identifier/MetadataIdentifierTest.java b/dubbo-metadata-report/dubbo-metadata-report-api/src/test/java/org/apache/dubbo/metadata/identifier/MetadataIdentifierTest.java new file mode 100644 index 00000000000..40fab45c4c8 --- /dev/null +++ b/dubbo-metadata-report/dubbo-metadata-report-api/src/test/java/org/apache/dubbo/metadata/identifier/MetadataIdentifierTest.java @@ -0,0 +1,43 @@ +/* + * 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.metadata.identifier; + +import org.apache.dubbo.common.Constants; + +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.Test; + +/** + * 2019/1/7 + */ +public class MetadataIdentifierTest { + + @Test + public void testGetUniqueKey() { + String interfaceName = "org.apache.dubbo.metadata.integration.InterfaceNameTestService"; + String version = "1.0.0.zk.md"; + String group = null; + String application = "vic.zk.md"; + MetadataIdentifier providerMetadataIdentifier = new MetadataIdentifier(interfaceName, version, group, Constants.PROVIDER_SIDE, application); + System.out.println(providerMetadataIdentifier.getUniqueKey(MetadataIdentifier.KeyTypeEnum.PATH)); + Assertions.assertEquals(providerMetadataIdentifier.getUniqueKey(MetadataIdentifier.KeyTypeEnum.PATH), "metadata" + Constants.PATH_SEPARATOR + interfaceName + Constants.PATH_SEPARATOR + (version == null ? "" : (version + Constants.PATH_SEPARATOR)) + + (group == null ? "" : (group + Constants.PATH_SEPARATOR)) + Constants.PROVIDER_SIDE + Constants.PATH_SEPARATOR + application); + System.out.println(providerMetadataIdentifier.getUniqueKey(MetadataIdentifier.KeyTypeEnum.UNIQUE_KEY)); + Assertions.assertEquals(providerMetadataIdentifier.getUniqueKey(MetadataIdentifier.KeyTypeEnum.UNIQUE_KEY), + interfaceName + MetadataIdentifier.SEPARATOR + (version == null ? "" : version + MetadataIdentifier.SEPARATOR) + (group == null ? "" : group + MetadataIdentifier.SEPARATOR) + Constants.PROVIDER_SIDE + MetadataIdentifier.SEPARATOR + application); + } +} diff --git a/dubbo-metadata-report/dubbo-metadata-report-api/src/test/java/org/apache/dubbo/metadata/integration/MetadataReportServiceTest.java b/dubbo-metadata-report/dubbo-metadata-report-api/src/test/java/org/apache/dubbo/metadata/integration/MetadataReportServiceTest.java index 88f1bee68bc..b0e24b53b00 100644 --- a/dubbo-metadata-report/dubbo-metadata-report-api/src/test/java/org/apache/dubbo/metadata/integration/MetadataReportServiceTest.java +++ b/dubbo-metadata-report/dubbo-metadata-report-api/src/test/java/org/apache/dubbo/metadata/integration/MetadataReportServiceTest.java @@ -40,13 +40,7 @@ public class MetadataReportServiceTest { @BeforeEach public void before() { - - metadataReportService1 = MetadataReportService.instance(new Supplier() { - @Override - public URL get() { - return url; - } - }); + metadataReportService1 = MetadataReportService.instance(() -> url); } @Test diff --git a/dubbo-metadata-report/dubbo-metadata-report-api/src/test/java/org/apache/dubbo/metadata/store/test/JTestMetadataReport4Test.java b/dubbo-metadata-report/dubbo-metadata-report-api/src/test/java/org/apache/dubbo/metadata/store/test/JTestMetadataReport4Test.java index 294fbbbc00d..76778cee339 100644 --- a/dubbo-metadata-report/dubbo-metadata-report-api/src/test/java/org/apache/dubbo/metadata/store/test/JTestMetadataReport4Test.java +++ b/dubbo-metadata-report/dubbo-metadata-report-api/src/test/java/org/apache/dubbo/metadata/store/test/JTestMetadataReport4Test.java @@ -22,7 +22,6 @@ import org.apache.dubbo.common.logger.LoggerFactory; import org.apache.dubbo.metadata.identifier.MetadataIdentifier; import org.apache.dubbo.metadata.support.AbstractMetadataReport; -import org.apache.dubbo.remoting.zookeeper.ZookeeperTransporter; import java.util.Map; import java.util.concurrent.ConcurrentHashMap; @@ -35,7 +34,7 @@ public class JTestMetadataReport4Test extends AbstractMetadataReport { private final static Logger logger = LoggerFactory.getLogger(JTestMetadataReport4Test.class); - public JTestMetadataReport4Test(URL url, ZookeeperTransporter zookeeperTransporter) { + public JTestMetadataReport4Test(URL url) { super(url); } diff --git a/dubbo-metadata-report/dubbo-metadata-report-api/src/test/java/org/apache/dubbo/metadata/store/test/JTestMetadataReportFactory4Test.java b/dubbo-metadata-report/dubbo-metadata-report-api/src/test/java/org/apache/dubbo/metadata/store/test/JTestMetadataReportFactory4Test.java index 0dd842a52ad..4e50a073fe1 100644 --- a/dubbo-metadata-report/dubbo-metadata-report-api/src/test/java/org/apache/dubbo/metadata/store/test/JTestMetadataReportFactory4Test.java +++ b/dubbo-metadata-report/dubbo-metadata-report-api/src/test/java/org/apache/dubbo/metadata/store/test/JTestMetadataReportFactory4Test.java @@ -19,22 +19,15 @@ import org.apache.dubbo.common.URL; import org.apache.dubbo.metadata.store.MetadataReport; import org.apache.dubbo.metadata.support.AbstractMetadataReportFactory; -import org.apache.dubbo.remoting.zookeeper.ZookeeperTransporter; /** * ZookeeperRegistryFactory. */ public class JTestMetadataReportFactory4Test extends AbstractMetadataReportFactory { - private ZookeeperTransporter zookeeperTransporter; - - public void setZookeeperTransporter(ZookeeperTransporter zookeeperTransporter) { - this.zookeeperTransporter = zookeeperTransporter; - } - @Override public MetadataReport createMetadataReport(URL url) { - return new JTestMetadataReport4Test(url, zookeeperTransporter); + return new JTestMetadataReport4Test(url); } } diff --git a/dubbo-metadata-report/dubbo-metadata-report-redis/pom.xml b/dubbo-metadata-report/dubbo-metadata-report-redis/pom.xml index ecdf91fc513..6f5d418e28f 100644 --- a/dubbo-metadata-report/dubbo-metadata-report-redis/pom.xml +++ b/dubbo-metadata-report/dubbo-metadata-report-redis/pom.xml @@ -14,13 +14,11 @@ See the License for the specific language governing permissions and limitations under the License. --> - + dubbo-metadata-report org.apache.dubbo - 2.7.0-SNAPSHOT + 2.7.1-SNAPSHOT 4.0.0 diff --git a/dubbo-metadata-report/dubbo-metadata-report-zookeeper/pom.xml b/dubbo-metadata-report/dubbo-metadata-report-zookeeper/pom.xml index f069d06be42..4f7feb1b22b 100644 --- a/dubbo-metadata-report/dubbo-metadata-report-zookeeper/pom.xml +++ b/dubbo-metadata-report/dubbo-metadata-report-zookeeper/pom.xml @@ -14,13 +14,11 @@ See the License for the specific language governing permissions and limitations under the License. --> - + dubbo-metadata-report org.apache.dubbo - 2.7.0-SNAPSHOT + 2.7.1-SNAPSHOT 4.0.0 diff --git a/dubbo-metadata-report/dubbo-metadata-report-zookeeper/src/test/java/org/apache/dubbo/metadata/store/zookeeper/ZookeeperMetadataReportTest.java b/dubbo-metadata-report/dubbo-metadata-report-zookeeper/src/test/java/org/apache/dubbo/metadata/store/zookeeper/ZookeeperMetadataReportTest.java index d25241e32c5..c9ed9cfa9bb 100644 --- a/dubbo-metadata-report/dubbo-metadata-report-zookeeper/src/test/java/org/apache/dubbo/metadata/store/zookeeper/ZookeeperMetadataReportTest.java +++ b/dubbo-metadata-report/dubbo-metadata-report-zookeeper/src/test/java/org/apache/dubbo/metadata/store/zookeeper/ZookeeperMetadataReportTest.java @@ -38,7 +38,6 @@ /** * 2018/10/9 */ -@Disabled("Keeps fail on Travis") public class ZookeeperMetadataReportTest { private TestingServer zkServer; private ZookeeperMetadataReport zookeeperMetadataReport; @@ -75,15 +74,18 @@ public void testStoreProvider() throws ClassNotFoundException, InterruptedExcept MetadataIdentifier providerMetadataIdentifier = storePrivider(zookeeperMetadataReport, interfaceName, version, group, application); String fileContent = zookeeperMetadataReport.zkClient.getContent(zookeeperMetadataReport.getNodePath(providerMetadataIdentifier)); + fileContent = waitSeconds(fileContent, 3500, zookeeperMetadataReport.getNodePath(providerMetadataIdentifier)); Assertions.assertNotNull(fileContent); deletePath(providerMetadataIdentifier, zookeeperMetadataReport); fileContent = zookeeperMetadataReport.zkClient.getContent(zookeeperMetadataReport.getNodePath(providerMetadataIdentifier)); + fileContent = waitSeconds(fileContent, 1000, zookeeperMetadataReport.getNodePath(providerMetadataIdentifier)); Assertions.assertNull(fileContent); providerMetadataIdentifier = storePrivider(zookeeperMetadataReport, interfaceName, version, group, application); fileContent = zookeeperMetadataReport.zkClient.getContent(zookeeperMetadataReport.getNodePath(providerMetadataIdentifier)); + fileContent = waitSeconds(fileContent, 3500, zookeeperMetadataReport.getNodePath(providerMetadataIdentifier)); Assertions.assertNotNull(fileContent); Gson gson = new Gson(); @@ -101,14 +103,17 @@ public void testConsumer() throws ClassNotFoundException, InterruptedException { MetadataIdentifier consumerMetadataIdentifier = storeConsumer(zookeeperMetadataReport, interfaceName, version, group, application); String fileContent = zookeeperMetadataReport.zkClient.getContent(zookeeperMetadataReport.getNodePath(consumerMetadataIdentifier)); + fileContent = waitSeconds(fileContent, 3500, zookeeperMetadataReport.getNodePath(consumerMetadataIdentifier)); Assertions.assertNotNull(fileContent); deletePath(consumerMetadataIdentifier, zookeeperMetadataReport); fileContent = zookeeperMetadataReport.zkClient.getContent(zookeeperMetadataReport.getNodePath(consumerMetadataIdentifier)); + fileContent = waitSeconds(fileContent, 1000, zookeeperMetadataReport.getNodePath(consumerMetadataIdentifier)); Assertions.assertNull(fileContent); consumerMetadataIdentifier = storeConsumer(zookeeperMetadataReport, interfaceName, version, group, application); fileContent = zookeeperMetadataReport.zkClient.getContent(zookeeperMetadataReport.getNodePath(consumerMetadataIdentifier)); + fileContent = waitSeconds(fileContent, 3000, zookeeperMetadataReport.getNodePath(consumerMetadataIdentifier)); Assertions.assertNotNull(fileContent); Assertions.assertEquals(fileContent, "{\"paramConsumerTest\":\"zkCm\"}"); } @@ -141,4 +146,12 @@ private MetadataIdentifier storeConsumer(ZookeeperMetadataReport zookeeperMetada return consumerMetadataIdentifier; } + + private String waitSeconds(String value, long moreTime, String path) throws InterruptedException { + if (value == null) { + Thread.sleep(moreTime); + return zookeeperMetadataReport.zkClient.getContent(path); + } + return value; + } } diff --git a/dubbo-metadata-report/pom.xml b/dubbo-metadata-report/pom.xml index 0a7829056d3..195ae5e9299 100644 --- a/dubbo-metadata-report/pom.xml +++ b/dubbo-metadata-report/pom.xml @@ -14,13 +14,11 @@ See the License for the specific language governing permissions and limitations under the License. --> - + dubbo-parent org.apache.dubbo - 2.7.0-SNAPSHOT + 2.7.1-SNAPSHOT 4.0.0 diff --git a/dubbo-metrics/dubbo-metrics-api/pom.xml b/dubbo-metrics/dubbo-metrics-api/pom.xml index 493955fb3e5..b3f55e53171 100644 --- a/dubbo-metrics/dubbo-metrics-api/pom.xml +++ b/dubbo-metrics/dubbo-metrics-api/pom.xml @@ -14,13 +14,11 @@ See the License for the specific language governing permissions and limitations under the License. --> - + dubbo-metrics org.apache.dubbo - 2.7.0-SNAPSHOT + 2.7.1-SNAPSHOT 4.0.0 diff --git a/dubbo-metrics/dubbo-metrics-api/src/main/java/org/apache/dubbo/metrics/MetricLevel.java b/dubbo-metrics/dubbo-metrics-api/src/main/java/org/apache/dubbo/metrics/MetricLevel.java index 66343070a3d..d04509a0673 100644 --- a/dubbo-metrics/dubbo-metrics-api/src/main/java/org/apache/dubbo/metrics/MetricLevel.java +++ b/dubbo-metrics/dubbo-metrics-api/src/main/java/org/apache/dubbo/metrics/MetricLevel.java @@ -31,14 +31,6 @@ public enum MetricLevel { CRITICAL; // critical metrics - static { - for (MetricLevel level : MetricLevel.values()) { - if (level.ordinal() < 0) { - throw new RuntimeException("MetricLevel can not < 0"); - } - } - } - public static int getMaxValue() { MetricLevel[] levels = MetricLevel.values(); int max = levels[0].ordinal(); diff --git a/dubbo-metrics/pom.xml b/dubbo-metrics/pom.xml index d76e4e737d3..b1ecde927ba 100644 --- a/dubbo-metrics/pom.xml +++ b/dubbo-metrics/pom.xml @@ -14,13 +14,11 @@ See the License for the specific language governing permissions and limitations under the License. --> - + org.apache.dubbo dubbo-parent - 2.7.0-SNAPSHOT + 2.7.1-SNAPSHOT 4.0.0 diff --git a/dubbo-monitor/dubbo-monitor-api/pom.xml b/dubbo-monitor/dubbo-monitor-api/pom.xml index 899a511b0a8..dce8268c56a 100644 --- a/dubbo-monitor/dubbo-monitor-api/pom.xml +++ b/dubbo-monitor/dubbo-monitor-api/pom.xml @@ -1,24 +1,25 @@ 4.0.0 org.apache.dubbo dubbo-monitor - 2.7.0-SNAPSHOT + 2.7.1-SNAPSHOT dubbo-monitor-api jar diff --git a/dubbo-monitor/dubbo-monitor-default/pom.xml b/dubbo-monitor/dubbo-monitor-default/pom.xml index a786f42ffa1..a7ae0ecd00c 100644 --- a/dubbo-monitor/dubbo-monitor-default/pom.xml +++ b/dubbo-monitor/dubbo-monitor-default/pom.xml @@ -19,7 +19,7 @@ org.apache.dubbo dubbo-monitor - 2.7.0-SNAPSHOT + 2.7.1-SNAPSHOT dubbo-monitor-default jar diff --git a/dubbo-monitor/dubbo-monitor-default/src/test/java/org/apache/dubbo/monitor/dubbo/DubboMonitorTest.java b/dubbo-monitor/dubbo-monitor-default/src/test/java/org/apache/dubbo/monitor/dubbo/DubboMonitorTest.java index 38213f17021..b92c784a797 100644 --- a/dubbo-monitor/dubbo-monitor-default/src/test/java/org/apache/dubbo/monitor/dubbo/DubboMonitorTest.java +++ b/dubbo-monitor/dubbo-monitor-default/src/test/java/org/apache/dubbo/monitor/dubbo/DubboMonitorTest.java @@ -103,22 +103,23 @@ public void testCount() throws Exception { .addParameter(MonitorService.CONCURRENT, 1) .addParameter(MonitorService.MAX_CONCURRENT, 1); monitor.collect(statistics); + monitor.send(); while (lastStatistics == null) { Thread.sleep(10); } - Assertions.assertEquals(lastStatistics.getParameter(MonitorService.APPLICATION), "morgan"); - Assertions.assertEquals(lastStatistics.getProtocol(), "dubbo"); - Assertions.assertEquals(lastStatistics.getHost(), "10.20.153.10"); - Assertions.assertEquals(lastStatistics.getParameter(MonitorService.APPLICATION), "morgan"); - Assertions.assertEquals(lastStatistics.getParameter(MonitorService.INTERFACE), "MemberService"); - Assertions.assertEquals(lastStatistics.getParameter(MonitorService.METHOD), "findPerson"); - Assertions.assertEquals(lastStatistics.getParameter(MonitorService.CONSUMER), "10.20.153.11"); - Assertions.assertEquals(lastStatistics.getParameter(MonitorService.SUCCESS), "1"); - Assertions.assertEquals(lastStatistics.getParameter(MonitorService.FAILURE), "0"); - Assertions.assertEquals(lastStatistics.getParameter(MonitorService.ELAPSED), "3"); - Assertions.assertEquals(lastStatistics.getParameter(MonitorService.MAX_ELAPSED), "3"); - Assertions.assertEquals(lastStatistics.getParameter(MonitorService.CONCURRENT), "1"); - Assertions.assertEquals(lastStatistics.getParameter(MonitorService.MAX_CONCURRENT), "1"); + Assertions.assertEquals("morgan", lastStatistics.getParameter(MonitorService.APPLICATION)); + Assertions.assertEquals("dubbo", lastStatistics.getProtocol()); + Assertions.assertEquals("10.20.153.10", lastStatistics.getHost()); + Assertions.assertEquals("morgan", lastStatistics.getParameter(MonitorService.APPLICATION)); + Assertions.assertEquals("MemberService", lastStatistics.getParameter(MonitorService.INTERFACE)); + Assertions.assertEquals("findPerson", lastStatistics.getParameter(MonitorService.METHOD)); + Assertions.assertEquals("10.20.153.11", lastStatistics.getParameter(MonitorService.CONSUMER)); + Assertions.assertEquals("1", lastStatistics.getParameter(MonitorService.SUCCESS)); + Assertions.assertEquals("0", lastStatistics.getParameter(MonitorService.FAILURE)); + Assertions.assertEquals("3", lastStatistics.getParameter(MonitorService.ELAPSED)); + Assertions.assertEquals("3", lastStatistics.getParameter(MonitorService.MAX_ELAPSED)); + Assertions.assertEquals("1", lastStatistics.getParameter(MonitorService.CONCURRENT)); + Assertions.assertEquals("1", lastStatistics.getParameter(MonitorService.MAX_CONCURRENT)); monitor.destroy(); } diff --git a/dubbo-monitor/pom.xml b/dubbo-monitor/pom.xml index 37923da0f29..6e0171d303c 100644 --- a/dubbo-monitor/pom.xml +++ b/dubbo-monitor/pom.xml @@ -19,7 +19,7 @@ org.apache.dubbo dubbo-parent - 2.7.0-SNAPSHOT + 2.7.1-SNAPSHOT dubbo-monitor pom diff --git a/dubbo-plugin/dubbo-qos/pom.xml b/dubbo-plugin/dubbo-qos/pom.xml index a5fd3950f82..717c20ceac1 100644 --- a/dubbo-plugin/dubbo-qos/pom.xml +++ b/dubbo-plugin/dubbo-qos/pom.xml @@ -18,7 +18,7 @@ org.apache.dubbo dubbo-plugin - 2.7.0-SNAPSHOT + 2.7.1-SNAPSHOT 4.0.0 diff --git a/dubbo-plugin/dubbo-qos/src/main/java/org/apache/dubbo/qos/textui/TKv.java b/dubbo-plugin/dubbo-qos/src/main/java/org/apache/dubbo/qos/textui/TKv.java index 5bf517c6475..483b3f63dbf 100644 --- a/dubbo-plugin/dubbo-qos/src/main/java/org/apache/dubbo/qos/textui/TKv.java +++ b/dubbo-plugin/dubbo-qos/src/main/java/org/apache/dubbo/qos/textui/TKv.java @@ -59,9 +59,7 @@ public String rendering() { private String filterEmptyLine(String content) { final StringBuilder sb = new StringBuilder(); - Scanner scanner = null; - try { - scanner = new Scanner(content); + try (Scanner scanner = new Scanner(content)) { while (scanner.hasNextLine()) { String line = scanner.nextLine(); if (line != null) { @@ -73,10 +71,6 @@ private String filterEmptyLine(String content) { } sb.append(line).append(System.lineSeparator()); } - } finally { - if (null != scanner) { - scanner.close(); - } } return sb.toString(); diff --git a/dubbo-plugin/dubbo-qos/src/main/java/org/apache/dubbo/qos/textui/TTable.java b/dubbo-plugin/dubbo-qos/src/main/java/org/apache/dubbo/qos/textui/TTable.java index 051ae62c323..c9a67157282 100644 --- a/dubbo-plugin/dubbo-qos/src/main/java/org/apache/dubbo/qos/textui/TTable.java +++ b/dubbo-plugin/dubbo-qos/src/main/java/org/apache/dubbo/qos/textui/TTable.java @@ -419,13 +419,10 @@ private static String replaceTab(String string) { */ private static int width(String string) { int maxWidth = 0; - final Scanner scanner = new Scanner(new StringReader(string)); - try { + try (Scanner scanner = new Scanner(new StringReader(string))) { while (scanner.hasNextLine()) { maxWidth = max(length(scanner.nextLine()), maxWidth); } - } finally { - scanner.close(); } return maxWidth; } diff --git a/dubbo-plugin/dubbo-qos/src/main/java/org/apache/dubbo/qos/textui/TTree.java b/dubbo-plugin/dubbo-qos/src/main/java/org/apache/dubbo/qos/textui/TTree.java index b4aaf986de2..50dca53f537 100644 --- a/dubbo-plugin/dubbo-qos/src/main/java/org/apache/dubbo/qos/textui/TTree.java +++ b/dubbo-plugin/dubbo-qos/src/main/java/org/apache/dubbo/qos/textui/TTree.java @@ -78,16 +78,14 @@ public void callback(int deep, boolean isLast, String prefix, Node node) { treeSB.append(costPrefix); } - final Scanner scanner = new Scanner(new StringReader(node.data.toString())); - try { + try (Scanner scanner = new Scanner(new StringReader(node.data.toString()))) { boolean isFirst = true; while (scanner.hasNextLine()) { if (isFirst) { treeSB.append(scanner.nextLine()).append("\n"); isFirst = false; } else { - treeSB - .append(prefix) + treeSB.append(prefix) .append(repeat(' ', stepStringLength)) .append(hasChild ? "|" : EMPTY) .append(repeat(' ', costPrefixLength)) @@ -95,8 +93,6 @@ public void callback(int deep, boolean isLast, String prefix, Node node) { .append(System.lineSeparator()); } } - } finally { - scanner.close(); } } diff --git a/dubbo-plugin/dubbo-qos/src/test/java/org/apache/dubbo/qos/textui/TKvTest.java b/dubbo-plugin/dubbo-qos/src/test/java/org/apache/dubbo/qos/textui/TKvTest.java index e681b640f49..e630f71c7b5 100644 --- a/dubbo-plugin/dubbo-qos/src/test/java/org/apache/dubbo/qos/textui/TKvTest.java +++ b/dubbo-plugin/dubbo-qos/src/test/java/org/apache/dubbo/qos/textui/TKvTest.java @@ -35,9 +35,9 @@ public void test1() { }); String kv = tKv.rendering(); - assertThat(kv, containsString("ABCDEFGHIJ\n")); - assertThat(kv, containsString("KLMNOPQRST\n")); - assertThat(kv, containsString("UVWXYZ\n")); + assertThat(kv, containsString("ABCDEFGHIJ" + System.lineSeparator())); + assertThat(kv, containsString("KLMNOPQRST" + System.lineSeparator())); + assertThat(kv, containsString("UVWXYZ" + System.lineSeparator())); tTable.addRow("OPTIONS", kv); String table = tTable.rendering(); diff --git a/dubbo-plugin/dubbo-qos/src/test/java/org/apache/dubbo/qos/textui/TLadderTest.java b/dubbo-plugin/dubbo-qos/src/test/java/org/apache/dubbo/qos/textui/TLadderTest.java index 7b57edbc3f2..4feb69e55fb 100644 --- a/dubbo-plugin/dubbo-qos/src/test/java/org/apache/dubbo/qos/textui/TLadderTest.java +++ b/dubbo-plugin/dubbo-qos/src/test/java/org/apache/dubbo/qos/textui/TLadderTest.java @@ -31,10 +31,10 @@ public void testRendering() throws Exception { ladder.addItem("3"); ladder.addItem("4"); String result = ladder.rendering(); - String expected = "1\n" + - " `-2\n" + - " `-3\n" + - " `-4\n"; + String expected = "1" + System.lineSeparator() + + " `-2" + System.lineSeparator() + + " `-3" + System.lineSeparator() + + " `-4" + System.lineSeparator(); assertThat(result, equalTo(expected)); System.out.println(result); } diff --git a/dubbo-plugin/dubbo-qos/src/test/java/org/apache/dubbo/qos/textui/TTableTest.java b/dubbo-plugin/dubbo-qos/src/test/java/org/apache/dubbo/qos/textui/TTableTest.java index 7d91ea8b1ff..abc70292dab 100644 --- a/dubbo-plugin/dubbo-qos/src/test/java/org/apache/dubbo/qos/textui/TTableTest.java +++ b/dubbo-plugin/dubbo-qos/src/test/java/org/apache/dubbo/qos/textui/TTableTest.java @@ -28,11 +28,11 @@ public void test1() throws Exception { table.addRow(1, "one", "uno", "un"); table.addRow(2, "two", "dos", "deux"); String result = table.rendering(); - String expected = "+-+---+---+----+\n" + - "|1|one|uno|un |\n" + - "+-+---+---+----+\n" + - "|2|two|dos|deux|\n" + - "+-+---+---+----+\n"; + String expected = "+-+---+---+----+" + System.lineSeparator() + + "|1|one|uno|un |" + System.lineSeparator() + + "+-+---+---+----+" + System.lineSeparator() + + "|2|two|dos|deux|" + System.lineSeparator() + + "+-+---+---+----+" + System.lineSeparator(); assertThat(result, equalTo(expected)); System.out.println(result); } @@ -46,9 +46,9 @@ public void test2() throws Exception { }); table.addRow(1, "abcde", "ABCDE"); String result = table.rendering(); - String expected = "+-+----------+----------+\n" + - "|1| abcde | ABCDE|\n" + - "+-+----------+----------+\n"; + String expected = "+-+----------+----------+" + System.lineSeparator() + + "|1| abcde | ABCDE|" + System.lineSeparator() + + "+-+----------+----------+" + System.lineSeparator(); assertThat(result, equalTo(expected)); System.out.println(result); } diff --git a/dubbo-plugin/pom.xml b/dubbo-plugin/pom.xml index 23ae191dfc1..e5427760240 100644 --- a/dubbo-plugin/pom.xml +++ b/dubbo-plugin/pom.xml @@ -18,7 +18,7 @@ dubbo-parent org.apache.dubbo - 2.7.0-SNAPSHOT + 2.7.1-SNAPSHOT 4.0.0 diff --git a/dubbo-registry/dubbo-registry-api/pom.xml b/dubbo-registry/dubbo-registry-api/pom.xml index b8be6f46f76..d96df68084f 100644 --- a/dubbo-registry/dubbo-registry-api/pom.xml +++ b/dubbo-registry/dubbo-registry-api/pom.xml @@ -19,7 +19,7 @@ org.apache.dubbo dubbo-registry - 2.7.0-SNAPSHOT + 2.7.1-SNAPSHOT dubbo-registry-api jar diff --git a/dubbo-registry/dubbo-registry-api/src/main/java/org/apache/dubbo/registry/integration/RegistryDirectory.java b/dubbo-registry/dubbo-registry-api/src/main/java/org/apache/dubbo/registry/integration/RegistryDirectory.java index 41b55b2d59e..449bb286dce 100644 --- a/dubbo-registry/dubbo-registry-api/src/main/java/org/apache/dubbo/registry/integration/RegistryDirectory.java +++ b/dubbo-registry/dubbo-registry-api/src/main/java/org/apache/dubbo/registry/integration/RegistryDirectory.java @@ -23,10 +23,10 @@ import org.apache.dubbo.common.logger.Logger; import org.apache.dubbo.common.logger.LoggerFactory; import org.apache.dubbo.common.utils.Assert; +import org.apache.dubbo.common.utils.CollectionUtils; import org.apache.dubbo.common.utils.NetUtils; import org.apache.dubbo.common.utils.StringUtils; import org.apache.dubbo.common.utils.UrlUtils; -import org.apache.dubbo.common.utils.CollectionUtils; import org.apache.dubbo.configcenter.DynamicConfiguration; import org.apache.dubbo.registry.NotifyListener; import org.apache.dubbo.registry.Registry; @@ -90,6 +90,8 @@ public class RegistryDirectory extends AbstractDirectory implements Notify private volatile URL overrideDirectoryUrl; // Initialization at construction time, assertion not null, and always assign non null value + private volatile URL registeredConsumerUrl; + /** * override rules * Priority: override>-D>consumer>provider @@ -158,6 +160,15 @@ public void destroy() { if (isDestroyed()) { return; } + + // unregister. + try { + if (getRegisteredConsumerUrl() != null && registry != null && registry.isAvailable()) { + registry.unregister(getRegisteredConsumerUrl()); + } + } catch (Throwable t) { + logger.warn("unexpected error when unregister service " + serviceKey + "from registry" + registry.getUrl(), t); + } // unsubscribe. try { if (getConsumerUrl() != null && registry != null && registry.isAvailable()) { @@ -217,9 +228,9 @@ private void refreshOverrideAndInvoker(List urls) { private void refreshInvoker(List invokerUrls) { Assert.notNull(invokerUrls, "invokerUrls should not be null"); - if (invokerUrls.size() == 1 && invokerUrls.get(0) != null && Constants.EMPTY_PROTOCOL.equals(invokerUrls - .get(0) - .getProtocol())) { + if (invokerUrls.size() == 1 + && invokerUrls.get(0) != null + && Constants.EMPTY_PROTOCOL.equals(invokerUrls.get(0).getProtocol())) { this.forbidden = true; // Forbid to access this.invokers = Collections.emptyList(); routerChain.setInvokers(this.invokers); @@ -241,8 +252,14 @@ private void refreshInvoker(List invokerUrls) { } Map> newUrlInvokerMap = toInvokers(invokerUrls);// Translate url list to Invoker map - // state change - // If the calculation is wrong, it is not processed. + /** + * If the calculation is wrong, it is not processed. + * + * 1. The protocol configured by the client is inconsistent with the protocol of the server. + * eg: consumer protocol = dubbo, provider only has other protocol services(rest). + * 2. The registration center is not robust and pushes illegal specification data. + * + */ if (CollectionUtils.isEmptyMap(newUrlInvokerMap)) { logger.error(new IllegalStateException("urls to invokers error .invokerUrls.size :" + invokerUrls.size() + ", invoker.size :0. urls :" + invokerUrls .toString())); @@ -565,6 +582,14 @@ public URL getUrl() { return this.overrideDirectoryUrl; } + public URL getRegisteredConsumerUrl() { + return registeredConsumerUrl; + } + + public void setRegisteredConsumerUrl(URL registeredConsumerUrl) { + this.registeredConsumerUrl = registeredConsumerUrl; + } + @Override public boolean isAvailable() { if (isDestroyed()) { diff --git a/dubbo-registry/dubbo-registry-api/src/main/java/org/apache/dubbo/registry/integration/RegistryProtocol.java b/dubbo-registry/dubbo-registry-api/src/main/java/org/apache/dubbo/registry/integration/RegistryProtocol.java index 4cb5efd6f41..5343e183637 100644 --- a/dubbo-registry/dubbo-registry-api/src/main/java/org/apache/dubbo/registry/integration/RegistryProtocol.java +++ b/dubbo-registry/dubbo-registry-api/src/main/java/org/apache/dubbo/registry/integration/RegistryProtocol.java @@ -67,8 +67,7 @@ import static org.apache.dubbo.common.Constants.DEFAULT_REGISTER_PROVIDER_KEYS; import static org.apache.dubbo.common.Constants.DEFAULT_REGISTRY; import static org.apache.dubbo.common.Constants.EXPORT_KEY; -import static org.apache.dubbo.common.Constants.EXTRA_CONSUMER_CONFIG_KEYS_KEY; -import static org.apache.dubbo.common.Constants.EXTRA_PROVIDER_CONFIG_KEYS_KEY; +import static org.apache.dubbo.common.Constants.EXTRA_KEYS_KEY; import static org.apache.dubbo.common.Constants.HIDE_KEY_PREFIX; import static org.apache.dubbo.common.Constants.INTERFACES; import static org.apache.dubbo.common.Constants.METHODS_KEY; @@ -84,8 +83,7 @@ import static org.apache.dubbo.common.Constants.REGISTRY_KEY; import static org.apache.dubbo.common.Constants.REGISTRY_PROTOCOL; import static org.apache.dubbo.common.Constants.ROUTERS_CATEGORY; -import static org.apache.dubbo.common.Constants.SIMPLE_CONSUMER_CONFIG_KEY; -import static org.apache.dubbo.common.Constants.SIMPLE_PROVIDER_CONFIG_KEY; +import static org.apache.dubbo.common.Constants.SIMPLIFIED_KEY; import static org.apache.dubbo.common.Constants.VALIDATION_KEY; import static org.apache.dubbo.common.utils.UrlUtils.classifyUrls; @@ -299,13 +297,13 @@ private URL getRegistryUrl(Invoker originInvoker) { */ private URL getRegisteredProviderUrl(final URL providerUrl, final URL registryUrl) { //The address you see at the registry - if (!registryUrl.getParameter(SIMPLE_PROVIDER_CONFIG_KEY, false)) { + if (!registryUrl.getParameter(SIMPLIFIED_KEY, false)) { return providerUrl.removeParameters(getFilteredKeys(providerUrl)).removeParameters( MONITOR_KEY, BIND_IP_KEY, BIND_PORT_KEY, QOS_ENABLE, QOS_PORT, ACCEPT_FOREIGN_IP, VALIDATION_KEY, INTERFACES); } else { String[] paramsToRegistry = getParamsToRegistry(DEFAULT_REGISTER_PROVIDER_KEYS, - registryUrl.getParameter(EXTRA_PROVIDER_CONFIG_KEYS_KEY, new String[0])); + registryUrl.getParameter(EXTRA_KEYS_KEY, new String[0])); return URL.valueOf(providerUrl, paramsToRegistry, providerUrl.getParameter(METHODS_KEY, (String[]) null)); } @@ -374,7 +372,8 @@ private Invoker doRefer(Cluster cluster, Registry registry, Class type Map parameters = new HashMap(directory.getUrl().getParameters()); URL subscribeUrl = new URL(CONSUMER_PROTOCOL, parameters.remove(REGISTER_IP_KEY), 0, type.getName(), parameters); if (!ANY_VALUE.equals(url.getServiceInterface()) && url.getParameter(REGISTER_KEY, true)) { - registry.register(getRegisteredConsumerUrl(subscribeUrl, url)); + directory.setRegisteredConsumerUrl(getRegisteredConsumerUrl(subscribeUrl, url)); + registry.register(directory.getRegisteredConsumerUrl()); } directory.buildRouterChain(subscribeUrl); directory.subscribe(subscribeUrl.addParameter(CATEGORY_KEY, @@ -385,14 +384,12 @@ private Invoker doRefer(Cluster cluster, Registry registry, Class type return invoker; } - private URL getRegisteredConsumerUrl(final URL consumerUrl, URL registryUrl) { - if (!registryUrl.getParameter(SIMPLE_CONSUMER_CONFIG_KEY, false)) { + public URL getRegisteredConsumerUrl(final URL consumerUrl, URL registryUrl) { + if (!registryUrl.getParameter(SIMPLIFIED_KEY, false)) { return consumerUrl.addParameters(CATEGORY_KEY, CONSUMERS_CATEGORY, CHECK_KEY, String.valueOf(false)); } else { - String[] paramsToRegistry = getParamsToRegistry(DEFAULT_REGISTER_CONSUMER_KEYS, - registryUrl.getParameter(EXTRA_CONSUMER_CONFIG_KEYS_KEY, new String[0])); - return URL.valueOf(consumerUrl, paramsToRegistry, null).addParameters( + return URL.valueOf(consumerUrl, DEFAULT_REGISTER_CONSUMER_KEYS, null).addParameters( CATEGORY_KEY, CONSUMERS_CATEGORY, CHECK_KEY, String.valueOf(false)); } } @@ -598,6 +595,7 @@ protected void notifyOverrides() { overrideListeners.values().forEach(listener -> ((OverrideListener) listener).doOverrideIfNecessary()); } } + /** * exporter proxy, establish the corresponding relationship between the returned exporter and the exporter * exported by the protocol, and can modify the relationship at the time of override. diff --git a/dubbo-registry/dubbo-registry-api/src/main/java/org/apache/dubbo/registry/support/AbstractRegistry.java b/dubbo-registry/dubbo-registry-api/src/main/java/org/apache/dubbo/registry/support/AbstractRegistry.java index 4ea61085821..bc119d0f604 100644 --- a/dubbo-registry/dubbo-registry-api/src/main/java/org/apache/dubbo/registry/support/AbstractRegistry.java +++ b/dubbo-registry/dubbo-registry-api/src/main/java/org/apache/dubbo/registry/support/AbstractRegistry.java @@ -20,6 +20,7 @@ import org.apache.dubbo.common.URL; import org.apache.dubbo.common.logger.Logger; import org.apache.dubbo.common.logger.LoggerFactory; +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.NamedThreadFactory; @@ -52,7 +53,6 @@ /** * AbstractRegistry. (SPI, Prototype, ThreadSafe) - * */ public abstract class AbstractRegistry implements Registry { @@ -62,16 +62,16 @@ public abstract class AbstractRegistry implements Registry { private static final String URL_SPLIT = "\\s+"; // Log output protected final Logger logger = LoggerFactory.getLogger(getClass()); - // Local disk cache, where the special key value.registies records the list of registry centers, and the others are the list of notified service providers + // Local disk cache, where the special key value.registries records the list of registry centers, and the others are the list of notified service providers private final Properties properties = new Properties(); // File cache timing writing private final ExecutorService registryCacheExecutor = Executors.newFixedThreadPool(1, new NamedThreadFactory("DubboSaveRegistryCache", true)); // Is it synchronized to save the file private final boolean syncSaveFile; private final AtomicLong lastCacheChanged = new AtomicLong(); - private final Set registered = new ConcurrentHashSet(); - private final ConcurrentMap> subscribed = new ConcurrentHashMap>(); - private final ConcurrentMap>> notified = new ConcurrentHashMap>>(); + private final Set registered = new ConcurrentHashSet<>(); + private final ConcurrentMap> subscribed = new ConcurrentHashMap<>(); + private final ConcurrentMap>> notified = new ConcurrentHashMap<>(); private URL registryUrl; // Local disk cache file private File file; @@ -91,13 +91,15 @@ public AbstractRegistry(URL url) { } } this.file = file; + // When starting the subscription center, + // we need to read the local cache file for future Registry fault tolerance processing. loadProperties(); notify(url.getBackupUrls()); } protected static List filterEmpty(URL url, List urls) { - if (urls == null || urls.isEmpty()) { - List result = new ArrayList(1); + if (CollectionUtils.isEmpty(urls)) { + List result = new ArrayList<>(1); result.add(url.setProtocol(Constants.EMPTY_PROTOCOL)); return result; } @@ -153,33 +155,23 @@ public void doSaveProperties(long version) { if (!lockfile.exists()) { lockfile.createNewFile(); } - RandomAccessFile raf = new RandomAccessFile(lockfile, "rw"); - try { - FileChannel channel = raf.getChannel(); + try (RandomAccessFile raf = new RandomAccessFile(lockfile, "rw"); + FileChannel channel = raf.getChannel()) { + FileLock lock = channel.tryLock(); + if (lock == null) { + throw new IOException("Can not lock the registry cache file " + file.getAbsolutePath() + ", ignore and retry later, maybe multi java process use the file, please config: dubbo.registry.file=xxx.properties"); + } + // Save try { - FileLock lock = channel.tryLock(); - if (lock == null) { - throw new IOException("Can not lock the registry cache file " + file.getAbsolutePath() + ", ignore and retry later, maybe multi java process use the file, please config: dubbo.registry.file=xxx.properties"); + if (!file.exists()) { + file.createNewFile(); } - // Save - try { - if (!file.exists()) { - file.createNewFile(); - } - FileOutputStream outputFile = new FileOutputStream(file); - try { - properties.store(outputFile, "Dubbo Registry Cache"); - } finally { - outputFile.close(); - } - } finally { - lock.release(); + try (FileOutputStream outputFile = new FileOutputStream(file)) { + properties.store(outputFile, "Dubbo Registry Cache"); } } finally { - channel.close(); + lock.release(); } - } finally { - raf.close(); } } catch (Throwable e) { if (version < lastCacheChanged.get()) { @@ -222,7 +214,7 @@ public List getCacheUrls(URL url) { && (Character.isLetter(key.charAt(0)) || key.charAt(0) == '_') && value != null && value.length() > 0) { String[] arr = value.trim().split(URL_SPLIT); - List urls = new ArrayList(); + List urls = new ArrayList<>(); for (String u : arr) { urls.add(URL.valueOf(u)); } @@ -234,7 +226,7 @@ public List getCacheUrls(URL url) { @Override public List lookup(URL url) { - List result = new ArrayList(); + List result = new ArrayList<>(); Map> notifiedUrls = getNotified().get(url); if (notifiedUrls != null && notifiedUrls.size() > 0) { for (List urls : notifiedUrls.values()) { @@ -245,7 +237,7 @@ public List lookup(URL url) { } } } else { - final AtomicReference> reference = new AtomicReference>(); + final AtomicReference> reference = new AtomicReference<>(); NotifyListener listener = reference::set; subscribe(url, listener); // Subscribe logic guarantees the first notify to return List urls = reference.get(); @@ -293,10 +285,7 @@ public void subscribe(URL url, NotifyListener listener) { if (logger.isInfoEnabled()) { logger.info("Subscribe: " + url); } - - Set listeners = subscribed.computeIfAbsent(url, k -> { - return new ConcurrentHashSet<>(); - }); + Set listeners = subscribed.computeIfAbsent(url, n -> new ConcurrentHashSet<>()); listeners.add(listener); } @@ -319,7 +308,7 @@ public void unsubscribe(URL url, NotifyListener listener) { protected void recover() throws Exception { // register - Set recoverRegistered = new HashSet(getRegistered()); + Set recoverRegistered = new HashSet<>(getRegistered()); if (!recoverRegistered.isEmpty()) { if (logger.isInfoEnabled()) { logger.info("Recover register url " + recoverRegistered); @@ -329,7 +318,7 @@ protected void recover() throws Exception { } } // subscribe - Map> recoverSubscribed = new HashMap>(getSubscribed()); + Map> recoverSubscribed = new HashMap<>(getSubscribed()); if (!recoverSubscribed.isEmpty()) { if (logger.isInfoEnabled()) { logger.info("Recover subscribe url " + recoverSubscribed.keySet()); @@ -344,7 +333,7 @@ protected void recover() throws Exception { } protected void notify(List urls) { - if (urls == null || urls.isEmpty()) { + if (CollectionUtils.isEmpty(urls)) { return; } @@ -368,6 +357,13 @@ protected void notify(List urls) { } } + /** + * Notify changes from the Provider side. + * + * @param url consumer side url + * @param listener listener + * @param urls provider latest urls + */ protected void notify(URL url, NotifyListener listener, List urls) { if (url == null) { throw new IllegalArgumentException("notify url == null"); @@ -375,7 +371,7 @@ protected void notify(URL url, NotifyListener listener, List urls) { if (listener == null) { throw new IllegalArgumentException("notify listener == null"); } - if ((urls == null || urls.isEmpty()) + if ((CollectionUtils.isEmpty(urls)) && !Constants.ANY_VALUE.equals(url.getServiceInterface())) { logger.warn("Ignore empty notify urls for subscribe url " + url); return; @@ -383,28 +379,27 @@ protected void notify(URL url, NotifyListener listener, List urls) { if (logger.isInfoEnabled()) { logger.info("Notify urls for subscribe url " + url + ", urls: " + urls); } - Map> result = new HashMap>(); + // keep every provider's category. + Map> result = new HashMap<>(); for (URL u : urls) { if (UrlUtils.isMatch(url, u)) { String category = u.getParameter(Constants.CATEGORY_KEY, Constants.DEFAULT_CATEGORY); - List categoryList = result.computeIfAbsent(category, k -> { - return new ArrayList<>(); - }); + List categoryList = result.computeIfAbsent(category, k -> new ArrayList<>()); categoryList.add(u); } } if (result.size() == 0) { return; } - Map> categoryNotified = notified.computeIfAbsent(url, k -> { - return new ConcurrentHashMap<>(); - }); + Map> categoryNotified = notified.computeIfAbsent(url, u -> new ConcurrentHashMap<>()); for (Map.Entry> entry : result.entrySet()) { String category = entry.getKey(); List categoryList = entry.getValue(); categoryNotified.put(category, categoryList); - saveProperties(url); listener.notify(categoryList); + // We will update our cache file after each notification. + // When our Registry has a subscribe failure due to network jitter, we can return at least the existing cache URL. + saveProperties(url); } } @@ -443,9 +438,9 @@ public void destroy() { if (logger.isInfoEnabled()) { logger.info("Destroy registry:" + getUrl()); } - Set destroyRegistered = new HashSet(getRegistered()); + Set destroyRegistered = new HashSet<>(getRegistered()); if (!destroyRegistered.isEmpty()) { - for (URL url : new HashSet(getRegistered())) { + for (URL url : new HashSet<>(getRegistered())) { if (url.getParameter(Constants.DYNAMIC_KEY, true)) { try { unregister(url); @@ -458,7 +453,7 @@ public void destroy() { } } } - Map> destroySubscribed = new HashMap>(getSubscribed()); + Map> destroySubscribed = new HashMap<>(getSubscribed()); if (!destroySubscribed.isEmpty()) { for (Map.Entry> entry : destroySubscribed.entrySet()) { URL url = entry.getKey(); diff --git a/dubbo-registry/dubbo-registry-api/src/test/java/org/apache/dubbo/registry/ZKTools.java b/dubbo-registry/dubbo-registry-api/src/test/java/org/apache/dubbo/registry/ZKTools.java index e3dfe643f3e..0d9f9492430 100644 --- a/dubbo-registry/dubbo-registry-api/src/test/java/org/apache/dubbo/registry/ZKTools.java +++ b/dubbo-registry/dubbo-registry-api/src/test/java/org/apache/dubbo/registry/ZKTools.java @@ -70,7 +70,7 @@ public void eventReceived(CuratorFramework client, CuratorEvent event) throws Ex public static void testStartupConfig() { String str = "dubbo.registry.address=zookeeper://127.0.0.1:2181\n" + "dubbo.registry.group=dubboregistrygroup1\n" + - "dubbo.metadatareport.address=zookeeper://127.0.0.1:2181\n" + + "dubbo.metadata-report.address=zookeeper://127.0.0.1:2181\n" + "dubbo.protocol.port=20990\n" + "dubbo.service.org.apache.dubbo.demo.DemoService.timeout=9999\n"; diff --git a/dubbo-registry/dubbo-registry-default/pom.xml b/dubbo-registry/dubbo-registry-default/pom.xml index ff9bb630f0e..73bda5ceab8 100644 --- a/dubbo-registry/dubbo-registry-default/pom.xml +++ b/dubbo-registry/dubbo-registry-default/pom.xml @@ -20,7 +20,7 @@ org.apache.dubbo dubbo-registry - 2.7.0-SNAPSHOT + 2.7.1-SNAPSHOT dubbo-registry-default jar diff --git a/dubbo-registry/dubbo-registry-default/src/test/resources/log4j.xml b/dubbo-registry/dubbo-registry-default/src/test/resources/log4j.xml index c8d6d8c5b58..91905fd10b2 100644 --- a/dubbo-registry/dubbo-registry-default/src/test/resources/log4j.xml +++ b/dubbo-registry/dubbo-registry-default/src/test/resources/log4j.xml @@ -21,6 +21,7 @@ + @@ -30,14 +31,8 @@ --> - - - - - - \ No newline at end of file diff --git a/dubbo-registry/dubbo-registry-multicast/pom.xml b/dubbo-registry/dubbo-registry-multicast/pom.xml index 79e2e4ee57f..61a8669e8fb 100644 --- a/dubbo-registry/dubbo-registry-multicast/pom.xml +++ b/dubbo-registry/dubbo-registry-multicast/pom.xml @@ -19,7 +19,7 @@ org.apache.dubbo dubbo-registry - 2.7.0-SNAPSHOT + 2.7.1-SNAPSHOT dubbo-registry-multicast jar diff --git a/dubbo-registry/dubbo-registry-multicast/src/main/java/org/apache/dubbo/registry/multicast/MulticastRegistry.java b/dubbo-registry/dubbo-registry-multicast/src/main/java/org/apache/dubbo/registry/multicast/MulticastRegistry.java index 5498e9efbfd..3223532c07f 100644 --- a/dubbo-registry/dubbo-registry-multicast/src/main/java/org/apache/dubbo/registry/multicast/MulticastRegistry.java +++ b/dubbo-registry/dubbo-registry-multicast/src/main/java/org/apache/dubbo/registry/multicast/MulticastRegistry.java @@ -20,17 +20,18 @@ import org.apache.dubbo.common.URL; import org.apache.dubbo.common.logger.Logger; import org.apache.dubbo.common.logger.LoggerFactory; +import org.apache.dubbo.common.utils.CollectionUtils; import org.apache.dubbo.common.utils.ConcurrentHashSet; import org.apache.dubbo.common.utils.ExecutorUtil; import org.apache.dubbo.common.utils.NamedThreadFactory; import org.apache.dubbo.common.utils.NetUtils; import org.apache.dubbo.common.utils.UrlUtils; -import org.apache.dubbo.common.utils.CollectionUtils; import org.apache.dubbo.registry.NotifyListener; import org.apache.dubbo.registry.support.FailbackRegistry; import java.io.IOException; import java.net.DatagramPacket; +import java.net.Inet4Address; import java.net.InetAddress; import java.net.InetSocketAddress; import java.net.MulticastSocket; @@ -81,14 +82,11 @@ public MulticastRegistry(URL url) { } try { multicastAddress = InetAddress.getByName(url.getHost()); - if (!multicastAddress.isMulticastAddress()) { - throw new IllegalArgumentException("Invalid multicast address " + url.getHost() + - ", ipv4 multicast address scope: 224.0.0.0 - 239.255.255.255."); - } + checkMulticastAddress(multicastAddress); + multicastPort = url.getPort() <= 0 ? DEFAULT_MULTICAST_PORT : url.getPort(); multicastSocket = new MulticastSocket(multicastPort); - multicastSocket.setLoopbackMode(false); - multicastSocket.joinGroup(multicastAddress); + NetUtils.joinMulticastGroup(multicastSocket, multicastAddress); Thread thread = new Thread(new Runnable() { @Override public void run() { @@ -134,6 +132,19 @@ public void run() { } } + private void checkMulticastAddress(InetAddress multicastAddress) { + if (!multicastAddress.isMulticastAddress()) { + String message = "Invalid multicast address " + multicastAddress; + if (!(multicastAddress instanceof Inet4Address)) { + throw new IllegalArgumentException(message + ", " + + "ipv4 multicast address scope: 224.0.0.0 - 239.255.255.255."); + } else { + throw new IllegalArgumentException(message + ", " + "ipv6 multicast address must start with ff, " + + "for example: ff01::1"); + } + } + } + /** * Remove the expired providers, only when "clean" parameter is true. */ @@ -153,40 +164,18 @@ private void clean() { } private boolean isExpired(URL url) { - if (!url.getParameter(Constants.DYNAMIC_KEY, true) - || url.getPort() <= 0 - || Constants.CONSUMER_PROTOCOL.equals(url.getProtocol()) - || Constants.ROUTE_PROTOCOL.equals(url.getProtocol()) - || Constants.OVERRIDE_PROTOCOL.equals(url.getProtocol())) { + if (!url.getParameter(Constants.DYNAMIC_KEY, true) || url.getPort() <= 0 || Constants.CONSUMER_PROTOCOL.equals(url.getProtocol()) || Constants.ROUTE_PROTOCOL.equals(url.getProtocol()) || Constants.OVERRIDE_PROTOCOL.equals(url.getProtocol())) { return false; } - Socket socket = null; - try { - socket = new Socket(url.getHost(), url.getPort()); + try (Socket socket = new Socket(url.getHost(), url.getPort())) { } catch (Throwable e) { try { Thread.sleep(100); } catch (Throwable e2) { } - Socket socket2 = null; - try { - socket2 = new Socket(url.getHost(), url.getPort()); + try (Socket socket2 = new Socket(url.getHost(), url.getPort())) { } catch (Throwable e2) { return true; - } finally { - if (socket2 != null) { - try { - socket2.close(); - } catch (Throwable e2) { - } - } - } - } finally { - if (socket != null) { - try { - socket.close(); - } catch (Throwable e) { - } } } return false; @@ -208,8 +197,7 @@ private void receive(String msg, InetSocketAddress remoteAddress) { if (CollectionUtils.isNotEmpty(urls)) { for (URL u : urls) { if (UrlUtils.isMatch(url, u)) { - String host = remoteAddress != null && remoteAddress.getAddress() != null - ? remoteAddress.getAddress().getHostAddress() : url.getIp(); + String host = remoteAddress != null && remoteAddress.getAddress() != null ? remoteAddress.getAddress().getHostAddress() : url.getIp(); if (url.getParameter("unicast", true) // Whether the consumer's machine has only one process && !NetUtils.getLocalHost().equals(host)) { // Multiple processes in the same machine cannot be unicast with unicast or there will be only one process receiving information unicast(Constants.REGISTER + " " + u.toFullString(), host); @@ -275,8 +263,7 @@ public void doSubscribe(URL url, NotifyListener listener) { @Override public void doUnsubscribe(URL url, NotifyListener listener) { - if (!Constants.ANY_VALUE.equals(url.getServiceInterface()) - && url.getParameter(Constants.REGISTER_KEY, true)) { + if (!Constants.ANY_VALUE.equals(url.getServiceInterface()) && url.getParameter(Constants.REGISTER_KEY, true)) { unregister(url); } multicast(Constants.UNSUBSCRIBE + " " + url.toFullString()); @@ -396,7 +383,7 @@ public void unsubscribe(URL url, NotifyListener listener) { @Override public List lookup(URL url) { - List urls = new ArrayList(); + List urls = new ArrayList<>(); Map> notifiedUrls = getNotified().get(url); if (notifiedUrls != null && notifiedUrls.size() > 0) { for (List values : notifiedUrls.values()) { diff --git a/dubbo-registry/dubbo-registry-multicast/src/test/java/org/apache/dubbo/registry/multicast/MulticastRegistryTest.java b/dubbo-registry/dubbo-registry-multicast/src/test/java/org/apache/dubbo/registry/multicast/MulticastRegistryTest.java index 939a2af0981..93c59bce316 100644 --- a/dubbo-registry/dubbo-registry-multicast/src/test/java/org/apache/dubbo/registry/multicast/MulticastRegistryTest.java +++ b/dubbo-registry/dubbo-registry-multicast/src/test/java/org/apache/dubbo/registry/multicast/MulticastRegistryTest.java @@ -24,15 +24,16 @@ import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; +import java.net.InetAddress; import java.net.MulticastSocket; import java.util.List; import java.util.Map; import java.util.Set; import static org.hamcrest.CoreMatchers.is; +import static org.hamcrest.MatcherAssert.assertThat; import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertFalse; -import static org.hamcrest.MatcherAssert.assertThat; import static org.junit.jupiter.api.Assertions.assertTrue; public class MulticastRegistryTest { @@ -220,4 +221,41 @@ public void testCustomedPort() { } } + @Test + public void testMulticastAddress() { + InetAddress multicastAddress = null; + MulticastSocket multicastSocket = null; + try { + // ipv4 multicast address + multicastAddress = InetAddress.getByName("224.55.66.77"); + multicastSocket = new MulticastSocket(2345); + multicastSocket.setLoopbackMode(false); + NetUtils.setInterface(multicastSocket, false); + multicastSocket.joinGroup(multicastAddress); + } catch (Exception e) { + Assertions.fail(e); + } finally { + if (multicastSocket != null) { + multicastSocket.close(); + } + } + + // multicast ipv6 address, + try { + multicastAddress = InetAddress.getByName("ff01::1"); + + multicastSocket = new MulticastSocket(); + multicastSocket.setLoopbackMode(false); + NetUtils.setInterface(multicastSocket, true); + multicastSocket.joinGroup(multicastAddress); + } catch (Throwable t) { + t.printStackTrace(); + } finally { + if (multicastSocket != null) { + multicastSocket.close(); + } + } + + } + } diff --git a/dubbo-registry/dubbo-registry-redis/pom.xml b/dubbo-registry/dubbo-registry-redis/pom.xml index 12f2aecbe6f..7644e1ca85a 100644 --- a/dubbo-registry/dubbo-registry-redis/pom.xml +++ b/dubbo-registry/dubbo-registry-redis/pom.xml @@ -19,7 +19,7 @@ org.apache.dubbo dubbo-registry - 2.7.0-SNAPSHOT + 2.7.1-SNAPSHOT dubbo-registry-redis jar diff --git a/dubbo-registry/dubbo-registry-redis/src/main/java/org/apache/dubbo/registry/redis/RedisRegistry.java b/dubbo-registry/dubbo-registry-redis/src/main/java/org/apache/dubbo/registry/redis/RedisRegistry.java index 589e92f4032..f8a24b13ffe 100644 --- a/dubbo-registry/dubbo-registry-redis/src/main/java/org/apache/dubbo/registry/redis/RedisRegistry.java +++ b/dubbo-registry/dubbo-registry-redis/src/main/java/org/apache/dubbo/registry/redis/RedisRegistry.java @@ -16,21 +16,20 @@ */ package org.apache.dubbo.registry.redis; +import org.apache.commons.pool2.impl.GenericObjectPoolConfig; import org.apache.dubbo.common.Constants; import org.apache.dubbo.common.URL; import org.apache.dubbo.common.logger.Logger; import org.apache.dubbo.common.logger.LoggerFactory; +import org.apache.dubbo.common.utils.ArrayUtils; +import org.apache.dubbo.common.utils.CollectionUtils; import org.apache.dubbo.common.utils.ExecutorUtil; import org.apache.dubbo.common.utils.NamedThreadFactory; import org.apache.dubbo.common.utils.StringUtils; import org.apache.dubbo.common.utils.UrlUtils; -import org.apache.dubbo.common.utils.CollectionUtils; -import org.apache.dubbo.common.utils.ArrayUtils; import org.apache.dubbo.registry.NotifyListener; import org.apache.dubbo.registry.support.FailbackRegistry; import org.apache.dubbo.rpc.RpcException; - -import org.apache.commons.pool2.impl.GenericObjectPoolConfig; import redis.clients.jedis.Jedis; import redis.clients.jedis.JedisPool; import redis.clients.jedis.JedisPubSub; @@ -38,6 +37,7 @@ import java.util.ArrayList; import java.util.Arrays; import java.util.Collection; +import java.util.Collections; import java.util.Date; import java.util.HashMap; import java.util.HashSet; @@ -156,14 +156,11 @@ public RedisRegistry(URL url) { this.root = group; this.expirePeriod = url.getParameter(Constants.SESSION_TIMEOUT_KEY, Constants.DEFAULT_SESSION_TIMEOUT); - this.expireFuture = expireExecutor.scheduleWithFixedDelay(new Runnable() { - @Override - public void run() { - try { - deferExpired(); // Extend the expiration time - } catch (Throwable t) { // Defensive fault tolerance - logger.error("Unexpected exception occur at defer expire time, cause: " + t.getMessage(), t); - } + this.expireFuture = expireExecutor.scheduleWithFixedDelay(() -> { + try { + deferExpired(); // Extend the expiration time + } catch (Throwable t) { // Defensive fault tolerance + logger.error("Unexpected exception occur at defer expire time, cause: " + t.getMessage(), t); } }, expirePeriod / 2, expirePeriod / 2, TimeUnit.MILLISECONDS); } @@ -172,9 +169,8 @@ private void deferExpired() { for (Map.Entry entry : jedisPools.entrySet()) { JedisPool jedisPool = entry.getValue(); try { - Jedis jedis = jedisPool.getResource(); - try { - for (URL url : new HashSet(getRegistered())) { + try (Jedis jedis = jedisPool.getResource()) { + for (URL url : new HashSet<>(getRegistered())) { if (url.getParameter(Constants.DYNAMIC_KEY, true)) { String key = toCategoryPath(url); if (jedis.hset(key, url.toFullString(), String.valueOf(System.currentTimeMillis() + expirePeriod)) == 1) { @@ -188,8 +184,6 @@ private void deferExpired() { if (!replicate) { break;//  If the server side has synchronized data, just write a single machine } - } finally { - jedis.close(); } } catch (Throwable t) { logger.warn("Failed to write provider heartbeat to redis registry. registry: " + entry.getKey() + ", cause: " + t.getMessage(), t); @@ -230,14 +224,9 @@ private void clean(Jedis jedis) { @Override public boolean isAvailable() { for (JedisPool jedisPool : jedisPools.values()) { - try { - Jedis jedis = jedisPool.getResource(); - try { - if (jedis.isConnected()) { - return true; // At least one single machine is available. - } - } finally { - jedis.close(); + try (Jedis jedis = jedisPool.getResource()) { + if (jedis.isConnected()) { + return true; // At least one single machine is available. } } catch (Throwable t) { } @@ -281,16 +270,13 @@ public void doRegister(URL url) { for (Map.Entry entry : jedisPools.entrySet()) { JedisPool jedisPool = entry.getValue(); try { - Jedis jedis = jedisPool.getResource(); - try { + try (Jedis jedis = jedisPool.getResource()) { jedis.hset(key, value, expire); jedis.publish(key, Constants.REGISTER); success = true; if (!replicate) { break; //  If the server side has synchronized data, just write a single machine } - } finally { - jedis.close(); } } catch (Throwable t) { exception = new RpcException("Failed to register service to redis registry. registry: " + entry.getKey() + ", service: " + url + ", cause: " + t.getMessage(), t); @@ -314,16 +300,13 @@ public void doUnregister(URL url) { for (Map.Entry entry : jedisPools.entrySet()) { JedisPool jedisPool = entry.getValue(); try { - Jedis jedis = jedisPool.getResource(); - try { + try (Jedis jedis = jedisPool.getResource()) { jedis.hdel(key, value); jedis.publish(key, Constants.UNREGISTER); success = true; if (!replicate) { break; //  If the server side has synchronized data, just write a single machine } - } finally { - jedis.close(); } } catch (Throwable t) { exception = new RpcException("Failed to unregister service to redis registry. registry: " + entry.getKey() + ", service: " + url + ", cause: " + t.getMessage(), t); @@ -355,8 +338,7 @@ public void doSubscribe(final URL url, final NotifyListener listener) { for (Map.Entry entry : jedisPools.entrySet()) { JedisPool jedisPool = entry.getValue(); try { - Jedis jedis = jedisPool.getResource(); - try { + try (Jedis jedis = jedisPool.getResource()) { if (service.endsWith(Constants.ANY_VALUE)) { admin = true; Set keys = jedis.keys(service); @@ -364,24 +346,18 @@ public void doSubscribe(final URL url, final NotifyListener listener) { Map> serviceKeys = new HashMap<>(); for (String key : keys) { String serviceKey = toServicePath(key); - Set sk = serviceKeys.get(serviceKey); - if (sk == null) { - sk = new HashSet<>(); - serviceKeys.put(serviceKey, sk); - } + Set sk = serviceKeys.computeIfAbsent(serviceKey, k -> new HashSet<>()); sk.add(key); } for (Set sk : serviceKeys.values()) { - doNotify(jedis, sk, url, Arrays.asList(listener)); + doNotify(jedis, sk, url, Collections.singletonList(listener)); } } } else { - doNotify(jedis, jedis.keys(service + Constants.PATH_SEPARATOR + Constants.ANY_VALUE), url, Arrays.asList(listener)); + doNotify(jedis, jedis.keys(service + Constants.PATH_SEPARATOR + Constants.ANY_VALUE), url, Collections.singletonList(listener)); } success = true; break; // Just read one server's data - } finally { - jedis.close(); } } catch (Throwable t) { // Try the next server exception = new RpcException("Failed to subscribe service from redis registry. registry: " + entry.getKey() + ", service: " + url + ", cause: " + t.getMessage(), t); @@ -402,7 +378,7 @@ public void doUnsubscribe(URL url, NotifyListener listener) { private void doNotify(Jedis jedis, String key) { for (Map.Entry> entry : new HashMap<>(getSubscribed()).entrySet()) { - doNotify(jedis, Arrays.asList(key), entry.getKey(), new HashSet<>(entry.getValue())); + doNotify(jedis, Collections.singletonList(key), entry.getKey(), new HashSet<>(entry.getValue())); } } @@ -428,7 +404,7 @@ private void doNotify(Jedis jedis, Collection keys, URL url, Collection< } List urls = new ArrayList<>(); Map values = jedis.hgetAll(key); - if (CollectionUtils.isEmptyMap(values)) { + if (CollectionUtils.isNotEmptyMap(values)) { for (Map.Entry entry : values.entrySet()) { URL u = URL.valueOf(entry.getKey()); if (!u.getParameter(Constants.DYNAMIC_KEY, true) @@ -450,7 +426,7 @@ private void doNotify(Jedis jedis, Collection keys, URL url, Collection< logger.info("redis notify: " + key + " = " + urls); } } - if (result == null || result.isEmpty()) { + if (CollectionUtils.isEmpty(result)) { return; } for (NotifyListener listener : listeners) { diff --git a/dubbo-registry/dubbo-registry-zookeeper/pom.xml b/dubbo-registry/dubbo-registry-zookeeper/pom.xml index edadb7a9c99..2c565d8b1a8 100644 --- a/dubbo-registry/dubbo-registry-zookeeper/pom.xml +++ b/dubbo-registry/dubbo-registry-zookeeper/pom.xml @@ -19,7 +19,7 @@ org.apache.dubbo dubbo-registry - 2.7.0-SNAPSHOT + 2.7.1-SNAPSHOT dubbo-registry-zookeeper jar diff --git a/dubbo-registry/pom.xml b/dubbo-registry/pom.xml index 822aec8a078..93f64bfe8a4 100644 --- a/dubbo-registry/pom.xml +++ b/dubbo-registry/pom.xml @@ -19,7 +19,7 @@ org.apache.dubbo dubbo-parent - 2.7.0-SNAPSHOT + 2.7.1-SNAPSHOT dubbo-registry pom diff --git a/dubbo-remoting/dubbo-remoting-api/pom.xml b/dubbo-remoting/dubbo-remoting-api/pom.xml index 629a4da2cb2..ec278e96e02 100644 --- a/dubbo-remoting/dubbo-remoting-api/pom.xml +++ b/dubbo-remoting/dubbo-remoting-api/pom.xml @@ -19,7 +19,7 @@ org.apache.dubbo dubbo-remoting - 2.7.0-SNAPSHOT + 2.7.1-SNAPSHOT dubbo-remoting-api jar diff --git a/dubbo-remoting/dubbo-remoting-api/src/main/java/org/apache/dubbo/remoting/Client.java b/dubbo-remoting/dubbo-remoting-api/src/main/java/org/apache/dubbo/remoting/Client.java index b8ccad201c8..7f15535353c 100644 --- a/dubbo-remoting/dubbo-remoting-api/src/main/java/org/apache/dubbo/remoting/Client.java +++ b/dubbo-remoting/dubbo-remoting-api/src/main/java/org/apache/dubbo/remoting/Client.java @@ -25,7 +25,7 @@ * * @see org.apache.dubbo.remoting.Transporter#connect(org.apache.dubbo.common.URL, ChannelHandler) */ -public interface Client extends Endpoint, Channel, Resetable { +public interface Client extends Endpoint, Channel, Resetable, IdleSensible { /** * reconnect. @@ -35,4 +35,4 @@ public interface Client extends Endpoint, Channel, Resetable { @Deprecated void reset(org.apache.dubbo.common.Parameters parameters); -} \ No newline at end of file +} diff --git a/dubbo-remoting/dubbo-remoting-api/src/main/java/org/apache/dubbo/remoting/IdleSensible.java b/dubbo-remoting/dubbo-remoting-api/src/main/java/org/apache/dubbo/remoting/IdleSensible.java new file mode 100644 index 00000000000..14e371e60d6 --- /dev/null +++ b/dubbo-remoting/dubbo-remoting-api/src/main/java/org/apache/dubbo/remoting/IdleSensible.java @@ -0,0 +1,37 @@ +/* + * 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.remoting; + +/** + * Indicate whether the implementation (for both server and client) has the ability to sense and handle idle connection. + * If the server has the ability to handle idle connection, it should close the connection when it happens, and if + * the client has the ability to handle idle connection, it should send the heartbeat to the server. + */ +public interface IdleSensible { + /** + * Whether the implementation can sense and handle the idle connection. By default it's false, the implementation + * relies on dedicated timer to take care of idle connection. + * + * @return whether has the ability to handle idle connection + */ + default boolean canHandleIdle() { + return false; + } +} diff --git a/dubbo-remoting/dubbo-remoting-api/src/main/java/org/apache/dubbo/remoting/Server.java b/dubbo-remoting/dubbo-remoting-api/src/main/java/org/apache/dubbo/remoting/Server.java index f413cb0bb85..c6ecf16d44b 100755 --- a/dubbo-remoting/dubbo-remoting-api/src/main/java/org/apache/dubbo/remoting/Server.java +++ b/dubbo-remoting/dubbo-remoting-api/src/main/java/org/apache/dubbo/remoting/Server.java @@ -28,7 +28,7 @@ * * @see org.apache.dubbo.remoting.Transporter#bind(org.apache.dubbo.common.URL, ChannelHandler) */ -public interface Server extends Endpoint, Resetable { +public interface Server extends Endpoint, Resetable, IdleSensible { /** * is bound. @@ -55,4 +55,4 @@ public interface Server extends Endpoint, Resetable { @Deprecated void reset(org.apache.dubbo.common.Parameters parameters); -} \ No newline at end of file +} diff --git a/dubbo-remoting/dubbo-remoting-api/src/main/java/org/apache/dubbo/remoting/exchange/support/header/AbstractTimerTask.java b/dubbo-remoting/dubbo-remoting-api/src/main/java/org/apache/dubbo/remoting/exchange/support/header/AbstractTimerTask.java index 003af243d86..befa6887806 100644 --- a/dubbo-remoting/dubbo-remoting-api/src/main/java/org/apache/dubbo/remoting/exchange/support/header/AbstractTimerTask.java +++ b/dubbo-remoting/dubbo-remoting-api/src/main/java/org/apache/dubbo/remoting/exchange/support/header/AbstractTimerTask.java @@ -34,6 +34,8 @@ public abstract class AbstractTimerTask implements TimerTask { private final Long tick; + protected volatile boolean cancel = false; + AbstractTimerTask(ChannelProvider channelProvider, Long tick) { if (channelProvider == null || tick == null) { throw new IllegalArgumentException(); @@ -54,11 +56,19 @@ static Long now() { return System.currentTimeMillis(); } + public void cancel() { + this.cancel = true; + } + private void reput(Timeout timeout, Long tick) { if (timeout == null || tick == null) { throw new IllegalArgumentException(); } + if (cancel) { + return; + } + Timer timer = timeout.timer(); if (timer.isStop() || timeout.isCancelled()) { return; diff --git a/dubbo-remoting/dubbo-remoting-api/src/main/java/org/apache/dubbo/remoting/exchange/support/header/CloseTimerTask.java b/dubbo-remoting/dubbo-remoting-api/src/main/java/org/apache/dubbo/remoting/exchange/support/header/CloseTimerTask.java new file mode 100644 index 00000000000..4081c309d05 --- /dev/null +++ b/dubbo-remoting/dubbo-remoting-api/src/main/java/org/apache/dubbo/remoting/exchange/support/header/CloseTimerTask.java @@ -0,0 +1,55 @@ +/* + * 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.remoting.exchange.support.header; + +import org.apache.dubbo.common.logger.Logger; +import org.apache.dubbo.common.logger.LoggerFactory; +import org.apache.dubbo.remoting.Channel; + +/** + * CloseTimerTask + */ +public class CloseTimerTask extends AbstractTimerTask { + + private static final Logger logger = LoggerFactory.getLogger(CloseTimerTask.class); + + private final int idleTimeout; + + public CloseTimerTask(ChannelProvider channelProvider, Long heartbeatTimeoutTick, int idleTimeout) { + super(channelProvider, heartbeatTimeoutTick); + this.idleTimeout = idleTimeout; + } + + @Override + protected void doTask(Channel channel) { + try { + Long lastRead = lastRead(channel); + Long lastWrite = lastWrite(channel); + Long now = now(); + // check ping & pong at server + if ((lastRead != null && now - lastRead > idleTimeout) + || (lastWrite != null && now - lastWrite > idleTimeout)) { + logger.warn("Close channel " + channel + ", because idleCheck timeout: " + + idleTimeout + "ms"); + channel.close(); + } + } catch (Throwable t) { + logger.warn("Exception when close remote channel " + channel.getRemoteAddress(), t); + } + } +} diff --git a/dubbo-remoting/dubbo-remoting-api/src/main/java/org/apache/dubbo/remoting/exchange/support/header/HeaderExchangeClient.java b/dubbo-remoting/dubbo-remoting-api/src/main/java/org/apache/dubbo/remoting/exchange/support/header/HeaderExchangeClient.java index 3abbe5b5422..3e57fba90c4 100644 --- a/dubbo-remoting/dubbo-remoting-api/src/main/java/org/apache/dubbo/remoting/exchange/support/header/HeaderExchangeClient.java +++ b/dubbo-remoting/dubbo-remoting-api/src/main/java/org/apache/dubbo/remoting/exchange/support/header/HeaderExchangeClient.java @@ -19,6 +19,7 @@ import org.apache.dubbo.common.Constants; import org.apache.dubbo.common.URL; import org.apache.dubbo.common.timer.HashedWheelTimer; +import org.apache.dubbo.common.utils.Assert; import org.apache.dubbo.common.utils.NamedThreadFactory; import org.apache.dubbo.remoting.ChannelHandler; import org.apache.dubbo.remoting.Client; @@ -32,6 +33,9 @@ import java.util.Collections; import java.util.concurrent.TimeUnit; +import static org.apache.dubbo.common.utils.UrlUtils.getHeartbeat; +import static org.apache.dubbo.common.utils.UrlUtils.getIdleTimeout; + /** * DefaultMessageClient */ @@ -39,32 +43,21 @@ public class HeaderExchangeClient implements ExchangeClient { private final Client client; private final ExchangeChannel channel; - // heartbeat(ms), default value is 0 , won't execute a heartbeat. - private int heartbeat; - private int heartbeatTimeout; - private HashedWheelTimer heartbeatTimer; + private static final HashedWheelTimer IDLE_CHECK_TIMER = new HashedWheelTimer( + new NamedThreadFactory("dubbo-client-idleCheck", true), 1, TimeUnit.SECONDS, Constants.TICKS_PER_WHEEL); + private HeartbeatTimerTask heartBeatTimerTask; + private ReconnectTimerTask reconnectTimerTask; - public HeaderExchangeClient(Client client, boolean needHeartbeat) { - if (client == null) { - throw new IllegalArgumentException("client == null"); - } + public HeaderExchangeClient(Client client, boolean startTimer) { + Assert.notNull(client, "Client can't be null"); this.client = client; this.channel = new HeaderExchangeChannel(client); - String dubbo = client.getUrl().getParameter(Constants.DUBBO_VERSION_KEY); - - this.heartbeat = client.getUrl().getParameter(Constants.HEARTBEAT_KEY, dubbo != null && - dubbo.startsWith("1.0.") ? Constants.DEFAULT_HEARTBEAT : 0); - this.heartbeatTimeout = client.getUrl().getParameter(Constants.HEARTBEAT_TIMEOUT_KEY, heartbeat * 3); - if (heartbeatTimeout < heartbeat * 2) { - throw new IllegalStateException("heartbeatTimeout < heartbeatInterval * 2"); - } - if (needHeartbeat) { - long tickDuration = calculateLeastDuration(heartbeat); - heartbeatTimer = new HashedWheelTimer(new NamedThreadFactory("dubbo-client-heartbeat", true), tickDuration, - TimeUnit.MILLISECONDS, Constants.TICKS_PER_WHEEL); - startHeartbeatTimer(); + if (startTimer) { + URL url = client.getUrl(); + startReconnectTask(url); + startHeartBeatTask(url); } } @@ -145,6 +138,7 @@ public void startClose() { @Override public void reset(URL url) { client.reset(url); + // FIXME, should cancel and restart timer tasks if parameters in the new URL are different? } @Override @@ -178,28 +172,34 @@ public boolean hasAttribute(String key) { return channel.hasAttribute(key); } - private void startHeartbeatTimer() { - AbstractTimerTask.ChannelProvider cp = () -> Collections.singletonList(HeaderExchangeClient.this); - - long heartbeatTick = calculateLeastDuration(heartbeat); - long heartbeatTimeoutTick = calculateLeastDuration(heartbeatTimeout); - HeartbeatTimerTask heartBeatTimerTask = new HeartbeatTimerTask(cp, heartbeatTick, heartbeat); - ReconnectTimerTask reconnectTimerTask = new ReconnectTimerTask(cp, heartbeatTimeoutTick, heartbeatTimeout); - - // init task and start timer. - heartbeatTimer.newTimeout(heartBeatTimerTask, heartbeatTick, TimeUnit.MILLISECONDS); - heartbeatTimer.newTimeout(reconnectTimerTask, heartbeatTimeoutTick, TimeUnit.MILLISECONDS); + private void startHeartBeatTask(URL url) { + if (!client.canHandleIdle()) { + AbstractTimerTask.ChannelProvider cp = () -> Collections.singletonList(HeaderExchangeClient.this); + int heartbeat = getHeartbeat(url); + long heartbeatTick = calculateLeastDuration(heartbeat); + this.heartBeatTimerTask = new HeartbeatTimerTask(cp, heartbeatTick, heartbeat); + IDLE_CHECK_TIMER.newTimeout(heartBeatTimerTask, heartbeatTick, TimeUnit.MILLISECONDS); + } } - private void stopHeartbeatTimer() { - if (heartbeatTimer != null) { - heartbeatTimer.stop(); - heartbeatTimer = null; + private void startReconnectTask(URL url) { + if (shouldReconnect(url)) { + AbstractTimerTask.ChannelProvider cp = () -> Collections.singletonList(HeaderExchangeClient.this); + int idleTimeout = getIdleTimeout(url); + long heartbeatTimeoutTick = calculateLeastDuration(idleTimeout); + this.reconnectTimerTask = new ReconnectTimerTask(cp, heartbeatTimeoutTick, idleTimeout); + IDLE_CHECK_TIMER.newTimeout(reconnectTimerTask, heartbeatTimeoutTick, TimeUnit.MILLISECONDS); } } private void doClose() { - stopHeartbeatTimer(); + if (heartBeatTimerTask != null) { + heartBeatTimerTask.cancel(); + } + + if (reconnectTimerTask != null) { + reconnectTimerTask.cancel(); + } } /** @@ -213,6 +213,10 @@ private long calculateLeastDuration(int time) { } } + private boolean shouldReconnect(URL url) { + return url.getParameter(Constants.RECONNECT_KEY, true); + } + @Override public String toString() { return "HeaderExchangeClient [channel=" + channel + "]"; diff --git a/dubbo-remoting/dubbo-remoting-api/src/main/java/org/apache/dubbo/remoting/exchange/support/header/HeaderExchangeServer.java b/dubbo-remoting/dubbo-remoting-api/src/main/java/org/apache/dubbo/remoting/exchange/support/header/HeaderExchangeServer.java index e339c15ab94..8a74e234134 100644 --- a/dubbo-remoting/dubbo-remoting-api/src/main/java/org/apache/dubbo/remoting/exchange/support/header/HeaderExchangeServer.java +++ b/dubbo-remoting/dubbo-remoting-api/src/main/java/org/apache/dubbo/remoting/exchange/support/header/HeaderExchangeServer.java @@ -22,8 +22,10 @@ import org.apache.dubbo.common.logger.Logger; import org.apache.dubbo.common.logger.LoggerFactory; import org.apache.dubbo.common.timer.HashedWheelTimer; +import org.apache.dubbo.common.utils.Assert; import org.apache.dubbo.common.utils.CollectionUtils; import org.apache.dubbo.common.utils.NamedThreadFactory; +import org.apache.dubbo.common.utils.UrlUtils; import org.apache.dubbo.remoting.Channel; import org.apache.dubbo.remoting.ChannelHandler; import org.apache.dubbo.remoting.RemotingException; @@ -48,25 +50,17 @@ public class HeaderExchangeServer implements ExchangeServer { protected final Logger logger = LoggerFactory.getLogger(getClass()); private final Server server; - // heartbeat timeout (ms), default value is 0 , won't execute a heartbeat. - private int heartbeat; - private int heartbeatTimeout; private AtomicBoolean closed = new AtomicBoolean(false); - private HashedWheelTimer heartbeatTimer; + private static final HashedWheelTimer IDLE_CHECK_TIMER = new HashedWheelTimer(new NamedThreadFactory("dubbo-server-idleCheck", true), 1, + TimeUnit.SECONDS, Constants.TICKS_PER_WHEEL); + + private CloseTimerTask closeTimerTask; public HeaderExchangeServer(Server server) { - if (server == null) { - throw new IllegalArgumentException("server == null"); - } + Assert.notNull(server, "server == null"); this.server = server; - this.heartbeat = server.getUrl().getParameter(Constants.HEARTBEAT_KEY, 0); - this.heartbeatTimeout = server.getUrl().getParameter(Constants.HEARTBEAT_TIMEOUT_KEY, heartbeat * 3); - if (heartbeatTimeout < heartbeat * 2) { - throw new IllegalStateException("heartbeatTimeout < heartbeatInterval * 2"); - } - - startHeartbeatTimer(); + startIdleCheckTask(getUrl()); } public Server getServer() { @@ -149,7 +143,13 @@ private void doClose() { if (!closed.compareAndSet(false, true)) { return; } - stopHeartbeatTimer(); + cancelCloseTask(); + } + + private void cancelCloseTask() { + if (closeTimerTask != null) { + closeTimerTask.cancel(); + } } @Override @@ -205,20 +205,13 @@ public ChannelHandler getChannelHandler() { public void reset(URL url) { server.reset(url); try { - if (url.hasParameter(Constants.HEARTBEAT_KEY) - || url.hasParameter(Constants.HEARTBEAT_TIMEOUT_KEY)) { - int h = url.getParameter(Constants.HEARTBEAT_KEY, heartbeat); - int t = url.getParameter(Constants.HEARTBEAT_TIMEOUT_KEY, h * 3); - if (t < h * 2) { - throw new IllegalStateException("heartbeatTimeout < heartbeatInterval * 2"); - } - if (h != heartbeat || t != heartbeatTimeout) { - heartbeat = h; - heartbeatTimeout = t; - - stopHeartbeatTimer(); - startHeartbeatTimer(); - } + int currHeartbeat = UrlUtils.getHeartbeat(getUrl()); + int currIdleTimeout = UrlUtils.getIdleTimeout(getUrl()); + int heartbeat = UrlUtils.getHeartbeat(url); + int idleTimeout = UrlUtils.getIdleTimeout(url); + if (currHeartbeat != heartbeat || currIdleTimeout != idleTimeout) { + cancelCloseTask(); + startIdleCheckTask(url); } } catch (Throwable t) { logger.error(t.getMessage(), t); @@ -260,28 +253,16 @@ private long calculateLeastDuration(int time) { } } - private void startHeartbeatTimer() { - long tickDuration = calculateLeastDuration(heartbeat); - heartbeatTimer = new HashedWheelTimer(new NamedThreadFactory("dubbo-server-heartbeat", true), tickDuration, - TimeUnit.MILLISECONDS, Constants.TICKS_PER_WHEEL); - - AbstractTimerTask.ChannelProvider cp = () -> unmodifiableCollection(HeaderExchangeServer.this.getChannels()); - - long heartbeatTick = calculateLeastDuration(heartbeat); - long heartbeatTimeoutTick = calculateLeastDuration(heartbeatTimeout); - HeartbeatTimerTask heartBeatTimerTask = new HeartbeatTimerTask(cp, heartbeatTick, heartbeat); - ReconnectTimerTask reconnectTimerTask = new ReconnectTimerTask(cp, heartbeatTimeoutTick, heartbeatTimeout); + private void startIdleCheckTask(URL url) { + if (!server.canHandleIdle()) { + AbstractTimerTask.ChannelProvider cp = () -> unmodifiableCollection(HeaderExchangeServer.this.getChannels()); + int idleTimeout = UrlUtils.getIdleTimeout(url); + long idleTimeoutTick = calculateLeastDuration(idleTimeout); + CloseTimerTask closeTimerTask = new CloseTimerTask(cp, idleTimeoutTick, idleTimeout); + this.closeTimerTask = closeTimerTask; - // init task and start timer. - heartbeatTimer.newTimeout(heartBeatTimerTask, heartbeatTick, TimeUnit.MILLISECONDS); - heartbeatTimer.newTimeout(reconnectTimerTask, heartbeatTimeoutTick, TimeUnit.MILLISECONDS); - } - - private void stopHeartbeatTimer() { - if (heartbeatTimer != null) { - heartbeatTimer.stop(); - heartbeatTimer = null; + // init task and start timer. + IDLE_CHECK_TIMER.newTimeout(closeTimerTask, idleTimeoutTick, TimeUnit.MILLISECONDS); } } - } diff --git a/dubbo-remoting/dubbo-remoting-api/src/main/java/org/apache/dubbo/remoting/exchange/support/header/ReconnectTimerTask.java b/dubbo-remoting/dubbo-remoting-api/src/main/java/org/apache/dubbo/remoting/exchange/support/header/ReconnectTimerTask.java index 2b7dca552c8..5fd8c90b956 100644 --- a/dubbo-remoting/dubbo-remoting-api/src/main/java/org/apache/dubbo/remoting/exchange/support/header/ReconnectTimerTask.java +++ b/dubbo-remoting/dubbo-remoting-api/src/main/java/org/apache/dubbo/remoting/exchange/support/header/ReconnectTimerTask.java @@ -29,35 +29,39 @@ public class ReconnectTimerTask extends AbstractTimerTask { private static final Logger logger = LoggerFactory.getLogger(ReconnectTimerTask.class); - private final int heartbeatTimeout; + private final int idleTimeout; - ReconnectTimerTask(ChannelProvider channelProvider, Long heartbeatTimeoutTick, int heartbeatTimeout1) { + public ReconnectTimerTask(ChannelProvider channelProvider, Long heartbeatTimeoutTick, int idleTimeout) { super(channelProvider, heartbeatTimeoutTick); - this.heartbeatTimeout = heartbeatTimeout1; + this.idleTimeout = idleTimeout; } @Override protected void doTask(Channel channel) { - Long lastRead = lastRead(channel); - Long now = now(); - if (lastRead != null && now - lastRead > heartbeatTimeout) { - if (channel instanceof Client) { + try { + Long lastRead = lastRead(channel); + Long now = now(); + + // Rely on reconnect timer to reconnect when AbstractClient.doConnect fails to init the connection + if (!channel.isConnected()) { try { - logger.warn("Reconnect to remote channel " + channel.getRemoteAddress() + ", because heartbeat read idle time out: " - + heartbeatTimeout + "ms"); + logger.info("Initial connection to " + channel); ((Client) channel).reconnect(); - } catch (Throwable t) { - // do nothing + } catch (Exception e) { + logger.error("Fail to connect to " + channel, e); } - } else { + // check pong at client + } else if (lastRead != null && now - lastRead > idleTimeout) { + logger.warn("Reconnect to channel " + channel + ", because heartbeat read idle time out: " + + idleTimeout + "ms"); try { - logger.warn("Close channel " + channel + ", because heartbeat read idle time out: " - + heartbeatTimeout + "ms"); - channel.close(); - } catch (Throwable t) { - logger.warn("Exception when close channel " + channel, t); + ((Client) channel).reconnect(); + } catch (Exception e) { + logger.error(channel + "reconnect failed during idle time.", e); } } + } catch (Throwable t) { + logger.warn("Exception when reconnect to remote channel " + channel.getRemoteAddress(), t); } } } diff --git a/dubbo-remoting/dubbo-remoting-api/src/main/java/org/apache/dubbo/remoting/telnet/support/TelnetHandlerAdapter.java b/dubbo-remoting/dubbo-remoting-api/src/main/java/org/apache/dubbo/remoting/telnet/support/TelnetHandlerAdapter.java index f740b3d0bd1..66418f3b573 100644 --- a/dubbo-remoting/dubbo-remoting-api/src/main/java/org/apache/dubbo/remoting/telnet/support/TelnetHandlerAdapter.java +++ b/dubbo-remoting/dubbo-remoting-api/src/main/java/org/apache/dubbo/remoting/telnet/support/TelnetHandlerAdapter.java @@ -81,20 +81,17 @@ public String telnet(Channel channel, String message) throws RemotingException { } private boolean commandEnabled(URL url, String command) { - boolean commandEnable = false; String supportCommands = url.getParameter(Constants.TELNET); if (StringUtils.isEmpty(supportCommands)) { - commandEnable = true; - } else { - String[] commands = Constants.COMMA_SPLIT_PATTERN.split(supportCommands); - for (String c : commands) { - if (command.equals(c)) { - commandEnable = true; - break; - } + return true; + } + String[] commands = Constants.COMMA_SPLIT_PATTERN.split(supportCommands); + for (String c : commands) { + if (command.equals(c)) { + return true; } } - return commandEnable; + return false; } } diff --git a/dubbo-remoting/dubbo-remoting-api/src/main/java/org/apache/dubbo/remoting/telnet/support/command/LogTelnetHandler.java b/dubbo-remoting/dubbo-remoting-api/src/main/java/org/apache/dubbo/remoting/telnet/support/command/LogTelnetHandler.java index bdbdebf6cfa..db531dc626f 100644 --- a/dubbo-remoting/dubbo-remoting-api/src/main/java/org/apache/dubbo/remoting/telnet/support/command/LogTelnetHandler.java +++ b/dubbo-remoting/dubbo-remoting-api/src/main/java/org/apache/dubbo/remoting/telnet/support/command/LogTelnetHandler.java @@ -56,10 +56,8 @@ public String telnet(Channel channel, String message) { if (file != null && file.exists()) { try { - FileInputStream fis = new FileInputStream(file); - try { - FileChannel filechannel = fis.getChannel(); - try { + try (FileInputStream fis = new FileInputStream(file)) { + try (FileChannel filechannel = fis.getChannel()) { size = filechannel.size(); ByteBuffer bb; if (size <= showLogLength) { @@ -78,11 +76,7 @@ public String telnet(Channel channel, String message) { buf.append("\r\nmodified:" + (new SimpleDateFormat("yyyy-MM-dd HH:mm:ss") .format(new Date(file.lastModified())))); buf.append("\r\nsize:" + size + "\r\n"); - } finally { - filechannel.close(); } - } finally { - fis.close(); } } catch (Exception e) { buf.append(e.getMessage()); diff --git a/dubbo-remoting/dubbo-remoting-api/src/main/java/org/apache/dubbo/remoting/transport/AbstractClient.java b/dubbo-remoting/dubbo-remoting-api/src/main/java/org/apache/dubbo/remoting/transport/AbstractClient.java index 9b1c9ba8daa..4138398f235 100644 --- a/dubbo-remoting/dubbo-remoting-api/src/main/java/org/apache/dubbo/remoting/transport/AbstractClient.java +++ b/dubbo-remoting/dubbo-remoting-api/src/main/java/org/apache/dubbo/remoting/transport/AbstractClient.java @@ -24,9 +24,7 @@ import org.apache.dubbo.common.logger.LoggerFactory; import org.apache.dubbo.common.store.DataStore; import org.apache.dubbo.common.utils.ExecutorUtil; -import org.apache.dubbo.common.utils.NamedThreadFactory; import org.apache.dubbo.common.utils.NetUtils; -import org.apache.dubbo.common.utils.StringUtils; import org.apache.dubbo.remoting.Channel; import org.apache.dubbo.remoting.ChannelHandler; import org.apache.dubbo.remoting.Client; @@ -35,12 +33,6 @@ import java.net.InetSocketAddress; import java.util.concurrent.ExecutorService; -import java.util.concurrent.Executors; -import java.util.concurrent.ScheduledFuture; -import java.util.concurrent.ScheduledThreadPoolExecutor; -import java.util.concurrent.TimeUnit; -import java.util.concurrent.atomic.AtomicBoolean; -import java.util.concurrent.atomic.AtomicInteger; import java.util.concurrent.locks.Lock; import java.util.concurrent.locks.ReentrantLock; @@ -51,31 +43,14 @@ public abstract class AbstractClient extends AbstractEndpoint implements Client protected static final String CLIENT_THREAD_POOL_NAME = "DubboClientHandler"; private static final Logger logger = LoggerFactory.getLogger(AbstractClient.class); - private static final AtomicInteger CLIENT_THREAD_POOL_ID = new AtomicInteger(); - private static final ScheduledThreadPoolExecutor reconnectExecutorService = new ScheduledThreadPoolExecutor(2, new NamedThreadFactory("DubboClientReconnectTimer", true)); private final Lock connectLock = new ReentrantLock(); - private final boolean send_reconnect; - private final AtomicInteger reconnect_count = new AtomicInteger(0); - // Reconnection error log has been called before? - private final AtomicBoolean reconnect_error_log_flag = new AtomicBoolean(false); - // reconnect warning period. Reconnect warning interval (log warning after how many times) //for test - private final int reconnect_warning_period; - private final long shutdown_timeout; + private final boolean needReconnect; protected volatile ExecutorService executor; - private volatile ScheduledFuture reconnectExecutorFuture = null; - // the last successed connected time - private long lastConnectedTime = System.currentTimeMillis(); - public AbstractClient(URL url, ChannelHandler handler) throws RemotingException { super(url, handler); - send_reconnect = url.getParameter(Constants.SEND_RECONNECT_KEY, false); - - shutdown_timeout = url.getParameter(Constants.SHUTDOWN_TIMEOUT_KEY, Constants.DEFAULT_SHUTDOWN_TIMEOUT); - - // The default reconnection interval is 2s, 1800 means warning interval is 1 hour. - reconnect_warning_period = url.getParameter("reconnect.waring.period", 1800); + needReconnect = url.getParameter(Constants.SEND_RECONNECT_KEY, false); try { doOpen(); @@ -118,81 +93,6 @@ protected static ChannelHandler wrapChannelHandler(URL url, ChannelHandler handl return ChannelHandlers.wrap(handler, url); } - /** - * @param url - * @return 0-false - */ - private static int getReconnectParam(URL url) { - int reconnect; - String param = url.getParameter(Constants.RECONNECT_KEY); - if (StringUtils.isEmpty(param) || "true".equalsIgnoreCase(param)) { - reconnect = Constants.DEFAULT_RECONNECT_PERIOD; - } else if ("false".equalsIgnoreCase(param)) { - reconnect = 0; - } else { - try { - reconnect = Integer.parseInt(param); - } catch (Exception e) { - throw new IllegalArgumentException("reconnect param must be nonnegative integer or false/true. input is:" + param); - } - if (reconnect < 0) { - throw new IllegalArgumentException("reconnect param must be nonnegative integer or false/true. input is:" + param); - } - } - return reconnect; - } - - /** - * init reconnect thread - */ - private synchronized void initConnectStatusCheckCommand() { - //reconnect=false to close reconnect - int reconnect = getReconnectParam(getUrl()); - if (reconnect > 0 && (reconnectExecutorFuture == null || reconnectExecutorFuture.isCancelled())) { - Runnable connectStatusCheckCommand = new Runnable() { - @Override - public void run() { - try { - if (!isConnected()) { - connect(); - } else { - lastConnectedTime = System.currentTimeMillis(); - } - } catch (Throwable t) { - String errorMsg = "client reconnect to " + getUrl().getAddress() + " find error . url: " + getUrl(); - // wait registry sync provider list - if (System.currentTimeMillis() - lastConnectedTime > shutdown_timeout) { - if (!reconnect_error_log_flag.get()) { - reconnect_error_log_flag.set(true); - logger.error(errorMsg, t); - return; - } - } - if (reconnect_count.getAndIncrement() % reconnect_warning_period == 0) { - logger.warn(errorMsg, t); - } - } - } - }; - reconnectExecutorFuture = reconnectExecutorService.scheduleWithFixedDelay(connectStatusCheckCommand, reconnect, reconnect, TimeUnit.MILLISECONDS); - } - } - - private synchronized void destroyConnectStatusCheckCommand() { - try { - if (reconnectExecutorFuture != null && !reconnectExecutorFuture.isDone()) { - reconnectExecutorFuture.cancel(true); - reconnectExecutorService.purge(); - } - } catch (Throwable e) { - logger.warn(e.getMessage(), e); - } - } - - protected ExecutorService createExecutor() { - return Executors.newCachedThreadPool(new NamedThreadFactory(CLIENT_THREAD_POOL_NAME + CLIENT_THREAD_POOL_ID.incrementAndGet() + "-" + getUrl().getAddress(), true)); - } - public InetSocketAddress getConnectAddress() { return new InetSocketAddress(NetUtils.filterLocalHost(getUrl().getHost()), getUrl().getPort()); } @@ -262,7 +162,7 @@ public boolean hasAttribute(String key) { @Override public void send(Object message, boolean sent) throws RemotingException { - if (send_reconnect && !isConnected()) { + if (needReconnect && !isConnected()) { connect(); } Channel channel = getChannel(); @@ -279,7 +179,7 @@ protected void connect() throws RemotingException { if (isConnected()) { return; } - initConnectStatusCheckCommand(); + doConnect(); if (!isConnected()) { throw new RemotingException(this, "Failed connect to server " + getRemoteAddress() + " from " + getClass().getSimpleName() + " " @@ -292,8 +192,6 @@ protected void connect() throws RemotingException { + ", channel is " + this.getChannel()); } } - reconnect_count.set(0); - reconnect_error_log_flag.set(false); } catch (RemotingException e) { throw e; } catch (Throwable e) { @@ -308,7 +206,6 @@ protected void connect() throws RemotingException { public void disconnect() { connectLock.lock(); try { - destroyConnectStatusCheckCommand(); try { Channel channel = getChannel(); if (channel != null) { @@ -345,14 +242,14 @@ public void reconnect() throws RemotingException { @Override public void close() { try { - if (executor != null) { - ExecutorUtil.shutdownNow(executor, 100); - } + super.close(); } catch (Throwable e) { logger.warn(e.getMessage(), e); } try { - super.close(); + if (executor != null) { + ExecutorUtil.shutdownNow(executor, 100); + } } catch (Throwable e) { logger.warn(e.getMessage(), e); } diff --git a/dubbo-remoting/dubbo-remoting-grizzly/pom.xml b/dubbo-remoting/dubbo-remoting-grizzly/pom.xml index 6c57b7312c3..f740422a7ae 100644 --- a/dubbo-remoting/dubbo-remoting-grizzly/pom.xml +++ b/dubbo-remoting/dubbo-remoting-grizzly/pom.xml @@ -19,7 +19,7 @@ org.apache.dubbo dubbo-remoting - 2.7.0-SNAPSHOT + 2.7.1-SNAPSHOT dubbo-remoting-grizzly jar diff --git a/dubbo-remoting/dubbo-remoting-http/pom.xml b/dubbo-remoting/dubbo-remoting-http/pom.xml index 755fdd019bd..85ea81dff12 100644 --- a/dubbo-remoting/dubbo-remoting-http/pom.xml +++ b/dubbo-remoting/dubbo-remoting-http/pom.xml @@ -19,7 +19,7 @@ org.apache.dubbo dubbo-remoting - 2.7.0-SNAPSHOT + 2.7.1-SNAPSHOT dubbo-remoting-http jar diff --git a/dubbo-remoting/dubbo-remoting-mina/pom.xml b/dubbo-remoting/dubbo-remoting-mina/pom.xml index c46a6928533..a10aacc52d2 100644 --- a/dubbo-remoting/dubbo-remoting-mina/pom.xml +++ b/dubbo-remoting/dubbo-remoting-mina/pom.xml @@ -19,7 +19,7 @@ org.apache.dubbo dubbo-remoting - 2.7.0-SNAPSHOT + 2.7.1-SNAPSHOT dubbo-remoting-mina jar diff --git a/dubbo-remoting/dubbo-remoting-netty/pom.xml b/dubbo-remoting/dubbo-remoting-netty/pom.xml index 2098b6d304a..cfa826279e5 100644 --- a/dubbo-remoting/dubbo-remoting-netty/pom.xml +++ b/dubbo-remoting/dubbo-remoting-netty/pom.xml @@ -1,24 +1,25 @@ 4.0.0 org.apache.dubbo dubbo-remoting - 2.7.0-SNAPSHOT + 2.7.1-SNAPSHOT dubbo-remoting-netty jar diff --git a/dubbo-remoting/dubbo-remoting-netty/src/test/java/org/apache/dubbo/remoting/exchange/support/header/HeartbeatHandlerTest.java b/dubbo-remoting/dubbo-remoting-netty/src/test/java/org/apache/dubbo/remoting/exchange/support/header/HeartbeatHandlerTest.java index 13b1f99acad..52c3e9d03e7 100644 --- a/dubbo-remoting/dubbo-remoting-netty/src/test/java/org/apache/dubbo/remoting/exchange/support/header/HeartbeatHandlerTest.java +++ b/dubbo-remoting/dubbo-remoting-netty/src/test/java/org/apache/dubbo/remoting/exchange/support/header/HeartbeatHandlerTest.java @@ -53,6 +53,9 @@ public void after() throws Exception { server.close(); server = null; } + + // wait for timer to finish + Thread.sleep(2000); } @Test diff --git a/dubbo-remoting/dubbo-remoting-netty/src/test/java/org/apache/dubbo/remoting/transport/netty/ClientReconnectTest.java b/dubbo-remoting/dubbo-remoting-netty/src/test/java/org/apache/dubbo/remoting/transport/netty/ClientReconnectTest.java index 16160b40ae7..4cb7eb6784d 100644 --- a/dubbo-remoting/dubbo-remoting-netty/src/test/java/org/apache/dubbo/remoting/transport/netty/ClientReconnectTest.java +++ b/dubbo-remoting/dubbo-remoting-netty/src/test/java/org/apache/dubbo/remoting/transport/netty/ClientReconnectTest.java @@ -18,7 +18,6 @@ import org.apache.dubbo.common.Constants; import org.apache.dubbo.common.utils.DubboAppender; -import org.apache.dubbo.common.utils.LogUtil; import org.apache.dubbo.common.utils.NetUtils; import org.apache.dubbo.remoting.Channel; import org.apache.dubbo.remoting.Client; @@ -27,7 +26,6 @@ import org.apache.dubbo.remoting.exchange.Exchangers; import org.apache.dubbo.remoting.exchange.support.ExchangeHandlerAdapter; -import org.apache.log4j.Level; import org.junit.jupiter.api.Assertions; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; @@ -36,9 +34,6 @@ * Client reconnect test */ public class ClientReconnectTest { - public static void main(String[] args) { - System.out.println(3 % 1); - } @BeforeEach public void clear() { @@ -73,31 +68,9 @@ public void testReconnect() throws RemotingException, InterruptedException { } } - /** - * Reconnect log check, when the time is not enough for shutdown time, there is no error log, but there must be a warn log - */ - @Test - public void testReconnectWarnLog() throws RemotingException, InterruptedException { - int port = NetUtils.getAvailablePort(); - DubboAppender.doStart(); - String url = "exchange://127.0.0.1:" + port + "/client.reconnect.test?check=false&client=netty3&" - + Constants.RECONNECT_KEY + "=" + 1; //1ms reconnect, ensure that there is enough frequency to reconnect - try { - Exchangers.connect(url); - } catch (Exception e) { - - //do nothing - } - Thread.sleep(1500); - //Time is not long enough to produce a error log - Assertions.assertEquals(0, LogUtil.findMessage(Level.ERROR, "client reconnect to "), "no error message "); - //The first reconnection failed to have a warn log - Assertions.assertEquals(1, LogUtil.findMessage(Level.WARN, "client reconnect to "), "must have one warn message "); - DubboAppender.doStop(); - } - public Client startClient(int port, int reconnectPeriod) throws RemotingException { - final String url = "exchange://127.0.0.1:" + port + "/client.reconnect.test?check=false&client=netty3&" + Constants.RECONNECT_KEY + "=" + reconnectPeriod; + public Client startClient(int port, int heartbeat) throws RemotingException { + final String url = "exchange://127.0.0.1:" + port + "/client.reconnect.test?check=false&client=netty3&" + Constants.HEARTBEAT_KEY + "=" + heartbeat; return Exchangers.connect(url); } diff --git a/dubbo-remoting/dubbo-remoting-netty/src/test/resources/log4j.xml b/dubbo-remoting/dubbo-remoting-netty/src/test/resources/log4j.xml index acb85098b27..fc40926e12a 100644 --- a/dubbo-remoting/dubbo-remoting-netty/src/test/resources/log4j.xml +++ b/dubbo-remoting/dubbo-remoting-netty/src/test/resources/log4j.xml @@ -21,6 +21,7 @@ + diff --git a/dubbo-remoting/dubbo-remoting-netty4/pom.xml b/dubbo-remoting/dubbo-remoting-netty4/pom.xml index 6253fa1d2f9..e17cfe185f7 100644 --- a/dubbo-remoting/dubbo-remoting-netty4/pom.xml +++ b/dubbo-remoting/dubbo-remoting-netty4/pom.xml @@ -18,7 +18,7 @@ dubbo-remoting org.apache.dubbo - 2.7.0-SNAPSHOT + 2.7.1-SNAPSHOT 4.0.0 diff --git a/dubbo-remoting/dubbo-remoting-netty4/src/main/java/org/apache/dubbo/remoting/transport/netty4/NettyClient.java b/dubbo-remoting/dubbo-remoting-netty4/src/main/java/org/apache/dubbo/remoting/transport/netty4/NettyClient.java index 4ea6fe12c52..464087e7c23 100644 --- a/dubbo-remoting/dubbo-remoting-netty4/src/main/java/org/apache/dubbo/remoting/transport/netty4/NettyClient.java +++ b/dubbo-remoting/dubbo-remoting-netty4/src/main/java/org/apache/dubbo/remoting/transport/netty4/NettyClient.java @@ -22,6 +22,7 @@ import org.apache.dubbo.common.logger.Logger; import org.apache.dubbo.common.logger.LoggerFactory; import org.apache.dubbo.common.utils.NetUtils; +import org.apache.dubbo.common.utils.UrlUtils; import org.apache.dubbo.remoting.ChannelHandler; import org.apache.dubbo.remoting.RemotingException; import org.apache.dubbo.remoting.transport.AbstractClient; @@ -34,9 +35,10 @@ import io.netty.channel.ChannelOption; import io.netty.channel.nio.NioEventLoopGroup; import io.netty.channel.socket.nio.NioSocketChannel; +import io.netty.handler.timeout.IdleStateHandler; import io.netty.util.concurrent.DefaultThreadFactory; -import java.util.concurrent.TimeUnit; +import static java.util.concurrent.TimeUnit.MILLISECONDS; /** * NettyClient. @@ -76,10 +78,12 @@ protected void doOpen() throws Throwable { @Override protected void initChannel(Channel ch) throws Exception { + int heartbeatInterval = UrlUtils.getIdleTimeout(getUrl()); NettyCodecAdapter adapter = new NettyCodecAdapter(getCodec(), getUrl(), NettyClient.this); ch.pipeline()//.addLast("logging",new LoggingHandler(LogLevel.INFO))//for debug .addLast("decoder", adapter.getDecoder()) .addLast("encoder", adapter.getEncoder()) + .addLast("client-idle-handler", new IdleStateHandler(heartbeatInterval, 0, 0, MILLISECONDS)) .addLast("handler", nettyClientHandler); } }); @@ -90,7 +94,7 @@ protected void doConnect() throws Throwable { long start = System.currentTimeMillis(); ChannelFuture future = bootstrap.connect(getConnectAddress()); try { - boolean ret = future.awaitUninterruptibly(getConnectTimeout(), TimeUnit.MILLISECONDS); + boolean ret = future.awaitUninterruptibly(getConnectTimeout(), MILLISECONDS); if (ret && future.isSuccess()) { Channel newChannel = future.channel(); @@ -162,4 +166,8 @@ protected org.apache.dubbo.remoting.Channel getChannel() { return NettyChannel.getOrAddChannel(c, getUrl(), this); } + @Override + public boolean canHandleIdle() { + return true; + } } diff --git a/dubbo-remoting/dubbo-remoting-netty4/src/main/java/org/apache/dubbo/remoting/transport/netty4/NettyClientHandler.java b/dubbo-remoting/dubbo-remoting-netty4/src/main/java/org/apache/dubbo/remoting/transport/netty4/NettyClientHandler.java index 2d8981170f3..c7077086dbb 100644 --- a/dubbo-remoting/dubbo-remoting-netty4/src/main/java/org/apache/dubbo/remoting/transport/netty4/NettyClientHandler.java +++ b/dubbo-remoting/dubbo-remoting-netty4/src/main/java/org/apache/dubbo/remoting/transport/netty4/NettyClientHandler.java @@ -17,6 +17,9 @@ package org.apache.dubbo.remoting.transport.netty4; import org.apache.dubbo.common.URL; +import org.apache.dubbo.common.Version; +import org.apache.dubbo.common.logger.Logger; +import org.apache.dubbo.common.logger.LoggerFactory; import org.apache.dubbo.common.utils.StringUtils; import org.apache.dubbo.remoting.ChannelHandler; import org.apache.dubbo.remoting.exchange.Request; @@ -25,12 +28,14 @@ import io.netty.channel.ChannelDuplexHandler; import io.netty.channel.ChannelHandlerContext; import io.netty.channel.ChannelPromise; +import io.netty.handler.timeout.IdleStateEvent; /** * NettyClientHandler */ @io.netty.channel.ChannelHandler.Sharable public class NettyClientHandler extends ChannelDuplexHandler { + private static final Logger logger = LoggerFactory.getLogger(NettyClient.class); private final URL url; @@ -47,7 +52,6 @@ public NettyClientHandler(URL url, ChannelHandler handler) { this.handler = handler; } - @Override public void channelActive(ChannelHandlerContext ctx) throws Exception { NettyChannel channel = NettyChannel.getOrAddChannel(ctx.channel(), url, handler); @@ -78,26 +82,53 @@ public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception } } - @Override public void write(ChannelHandlerContext ctx, Object msg, ChannelPromise promise) throws Exception { super.write(ctx, msg, promise); - NettyChannel channel = NettyChannel.getOrAddChannel(ctx.channel(), url, handler); - try { - // if error happens from write, mock a BAD_REQUEST response so that invoker can return immediately without - // waiting until timeout. FIXME: not sure if this is the right approach, but exceptionCaught doesn't work - // as expected. - if (promise.cause() != null && msg instanceof Request) { - Request request = (Request) msg; - Response response = new Response(request.getId(), request.getVersion()); - response.setStatus(Response.BAD_REQUEST); - response.setErrorMessage(StringUtils.toString(promise.cause())); - handler.received(channel, response); - } else { - handler.sent(channel, msg); + final NettyChannel channel = NettyChannel.getOrAddChannel(ctx.channel(), url, handler); + final boolean isRequest = msg instanceof Request; + + // We add listeners to make sure our out bound event is correct. + // If our out bound event has an error (in most cases the encoder fails), + // we need to have the request return directly instead of blocking the invoke process. + promise.addListener(future -> { + try { + if (future.isSuccess()) { + // if our future is success, mark the future to sent. + handler.sent(channel, msg); + return; + } + + Throwable t = future.cause(); + if (t != null && isRequest) { + Request request = (Request) msg; + Response response = buildErrorResponse(request, t); + handler.received(channel, response); + } + } finally { + NettyChannel.removeChannelIfDisconnected(ctx.channel()); } - } finally { - NettyChannel.removeChannelIfDisconnected(ctx.channel()); + }); + } + + @Override + public void userEventTriggered(ChannelHandlerContext ctx, Object evt) throws Exception { + if (evt instanceof IdleStateEvent) { + try { + NettyChannel channel = NettyChannel.getOrAddChannel(ctx.channel(), url, handler); + if (logger.isDebugEnabled()) { + logger.debug("IdleStateEvent triggered, send heartbeat to channel " + channel); + } + Request req = new Request(); + req.setVersion(Version.getProtocolVersion()); + req.setTwoWay(true); + req.setEvent(Request.HEARTBEAT_EVENT); + channel.send(req); + } finally { + NettyChannel.removeChannelIfDisconnected(ctx.channel()); + } + } else { + super.userEventTriggered(ctx, evt); } } @@ -111,4 +142,18 @@ public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) NettyChannel.removeChannelIfDisconnected(ctx.channel()); } } -} \ No newline at end of file + + /** + * build a bad request's response + * + * @param request the request + * @param t the throwable. In most cases, serialization fails. + * @return the response + */ + private static Response buildErrorResponse(Request request, Throwable t) { + Response response = new Response(request.getId(), request.getVersion()); + response.setStatus(Response.BAD_REQUEST); + response.setErrorMessage(StringUtils.toString(t)); + return response; + } +} diff --git a/dubbo-remoting/dubbo-remoting-netty4/src/main/java/org/apache/dubbo/remoting/transport/netty4/NettyServer.java b/dubbo-remoting/dubbo-remoting-netty4/src/main/java/org/apache/dubbo/remoting/transport/netty4/NettyServer.java index a8da94e05bd..62b6c55f93c 100644 --- a/dubbo-remoting/dubbo-remoting-netty4/src/main/java/org/apache/dubbo/remoting/transport/netty4/NettyServer.java +++ b/dubbo-remoting/dubbo-remoting-netty4/src/main/java/org/apache/dubbo/remoting/transport/netty4/NettyServer.java @@ -22,6 +22,7 @@ import org.apache.dubbo.common.logger.LoggerFactory; import org.apache.dubbo.common.utils.ExecutorUtil; import org.apache.dubbo.common.utils.NetUtils; +import org.apache.dubbo.common.utils.UrlUtils; import org.apache.dubbo.remoting.Channel; import org.apache.dubbo.remoting.ChannelHandler; import org.apache.dubbo.remoting.RemotingException; @@ -38,6 +39,7 @@ import io.netty.channel.nio.NioEventLoopGroup; import io.netty.channel.socket.nio.NioServerSocketChannel; import io.netty.channel.socket.nio.NioSocketChannel; +import io.netty.handler.timeout.IdleStateHandler; import io.netty.util.concurrent.DefaultThreadFactory; import java.net.InetSocketAddress; @@ -45,6 +47,8 @@ import java.util.HashSet; import java.util.Map; +import static java.util.concurrent.TimeUnit.MILLISECONDS; + /** * NettyServer */ @@ -84,10 +88,13 @@ protected void doOpen() throws Throwable { .childHandler(new ChannelInitializer() { @Override protected void initChannel(NioSocketChannel ch) throws Exception { + // FIXME: should we use getTimeout()? + int idleTimeout = UrlUtils.getIdleTimeout(getUrl()); NettyCodecAdapter adapter = new NettyCodecAdapter(getCodec(), getUrl(), NettyServer.this); ch.pipeline()//.addLast("logging",new LoggingHandler(LogLevel.INFO))//for debug .addLast("decoder", adapter.getDecoder()) .addLast("encoder", adapter.getEncoder()) + .addLast("server-idle-handler", new IdleStateHandler(0, 0, idleTimeout, MILLISECONDS)) .addLast("handler", nettyServerHandler); } }); @@ -157,6 +164,11 @@ public Channel getChannel(InetSocketAddress remoteAddress) { return channels.get(NetUtils.toAddressString(remoteAddress)); } + @Override + public boolean canHandleIdle() { + return true; + } + @Override public boolean isBound() { return channel.isActive(); diff --git a/dubbo-remoting/dubbo-remoting-netty4/src/main/java/org/apache/dubbo/remoting/transport/netty4/NettyServerHandler.java b/dubbo-remoting/dubbo-remoting-netty4/src/main/java/org/apache/dubbo/remoting/transport/netty4/NettyServerHandler.java index 56d4ff69c99..ea5b3249839 100644 --- a/dubbo-remoting/dubbo-remoting-netty4/src/main/java/org/apache/dubbo/remoting/transport/netty4/NettyServerHandler.java +++ b/dubbo-remoting/dubbo-remoting-netty4/src/main/java/org/apache/dubbo/remoting/transport/netty4/NettyServerHandler.java @@ -17,6 +17,8 @@ package org.apache.dubbo.remoting.transport.netty4; import org.apache.dubbo.common.URL; +import org.apache.dubbo.common.logger.Logger; +import org.apache.dubbo.common.logger.LoggerFactory; import org.apache.dubbo.common.utils.NetUtils; import org.apache.dubbo.remoting.Channel; import org.apache.dubbo.remoting.ChannelHandler; @@ -24,6 +26,7 @@ import io.netty.channel.ChannelDuplexHandler; import io.netty.channel.ChannelHandlerContext; import io.netty.channel.ChannelPromise; +import io.netty.handler.timeout.IdleStateEvent; import java.net.InetSocketAddress; import java.util.Map; @@ -34,6 +37,7 @@ */ @io.netty.channel.ChannelHandler.Sharable public class NettyServerHandler extends ChannelDuplexHandler { + private static final Logger logger = LoggerFactory.getLogger(NettyServerHandler.class); private final Map channels = new ConcurrentHashMap(); // @@ -102,6 +106,20 @@ public void write(ChannelHandlerContext ctx, Object msg, ChannelPromise promise) } } + @Override + public void userEventTriggered(ChannelHandlerContext ctx, Object evt) throws Exception { + if (evt instanceof IdleStateEvent) { + NettyChannel channel = NettyChannel.getOrAddChannel(ctx.channel(), url, handler); + try { + logger.info("IdleStateEvent triggered, close channel " + channel); + channel.close(); + } finally { + NettyChannel.removeChannelIfDisconnected(ctx.channel()); + } + } + super.userEventTriggered(ctx, evt); + } + @Override public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception { @@ -112,4 +130,4 @@ public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) NettyChannel.removeChannelIfDisconnected(ctx.channel()); } } -} \ No newline at end of file +} diff --git a/dubbo-remoting/dubbo-remoting-netty4/src/test/java/org/apache/dubbo/remoting/transport/netty4/ClientReconnectTest.java b/dubbo-remoting/dubbo-remoting-netty4/src/test/java/org/apache/dubbo/remoting/transport/netty4/ClientReconnectTest.java index eae66742767..f21918d3d15 100644 --- a/dubbo-remoting/dubbo-remoting-netty4/src/test/java/org/apache/dubbo/remoting/transport/netty4/ClientReconnectTest.java +++ b/dubbo-remoting/dubbo-remoting-netty4/src/test/java/org/apache/dubbo/remoting/transport/netty4/ClientReconnectTest.java @@ -71,8 +71,8 @@ public void testReconnect() throws RemotingException, InterruptedException { } - public Client startClient(int port, int reconnectPeriod) throws RemotingException { - final String url = "exchange://127.0.0.1:" + port + "/client.reconnect.test?client=netty4&check=false&" + Constants.RECONNECT_KEY + "=" + reconnectPeriod; + public Client startClient(int port, int heartbeat) throws RemotingException { + final String url = "exchange://127.0.0.1:" + port + "/client.reconnect.test?client=netty4&check=false&" + Constants.HEARTBEAT_KEY + "=" + heartbeat; return Exchangers.connect(url); } diff --git a/dubbo-remoting/dubbo-remoting-p2p/pom.xml b/dubbo-remoting/dubbo-remoting-p2p/pom.xml index 18be11a1e20..238398e4a16 100644 --- a/dubbo-remoting/dubbo-remoting-p2p/pom.xml +++ b/dubbo-remoting/dubbo-remoting-p2p/pom.xml @@ -14,13 +14,12 @@ See the License for the specific language governing permissions and limitations under the License. --> - + 4.0.0 org.apache.dubbo dubbo-remoting - 2.7.0-SNAPSHOT + 2.7.1-SNAPSHOT dubbo-remoting-p2p jar diff --git a/dubbo-remoting/dubbo-remoting-zookeeper/pom.xml b/dubbo-remoting/dubbo-remoting-zookeeper/pom.xml index a6cb828d878..97ce12adc23 100644 --- a/dubbo-remoting/dubbo-remoting-zookeeper/pom.xml +++ b/dubbo-remoting/dubbo-remoting-zookeeper/pom.xml @@ -1,24 +1,25 @@ 4.0.0 org.apache.dubbo dubbo-remoting - 2.7.0-SNAPSHOT + 2.7.1-SNAPSHOT dubbo-remoting-zookeeper jar diff --git a/dubbo-remoting/dubbo-remoting-zookeeper/src/main/java/org/apache/dubbo/remoting/zookeeper/curator/CuratorZookeeperClient.java b/dubbo-remoting/dubbo-remoting-zookeeper/src/main/java/org/apache/dubbo/remoting/zookeeper/curator/CuratorZookeeperClient.java index e1315e3ef4a..a78edda76a6 100644 --- a/dubbo-remoting/dubbo-remoting-zookeeper/src/main/java/org/apache/dubbo/remoting/zookeeper/curator/CuratorZookeeperClient.java +++ b/dubbo-remoting/dubbo-remoting-zookeeper/src/main/java/org/apache/dubbo/remoting/zookeeper/curator/CuratorZookeeperClient.java @@ -16,19 +16,18 @@ */ package org.apache.dubbo.remoting.zookeeper.curator; -import org.apache.dubbo.common.Constants; -import org.apache.dubbo.common.URL; -import org.apache.dubbo.common.utils.StringUtils; -import org.apache.dubbo.remoting.zookeeper.ChildListener; -import org.apache.dubbo.remoting.zookeeper.StateListener; -import org.apache.dubbo.remoting.zookeeper.support.AbstractZookeeperClient; - import org.apache.curator.framework.CuratorFramework; import org.apache.curator.framework.CuratorFrameworkFactory; import org.apache.curator.framework.api.CuratorWatcher; import org.apache.curator.framework.state.ConnectionState; import org.apache.curator.framework.state.ConnectionStateListener; import org.apache.curator.retry.RetryNTimes; +import org.apache.dubbo.common.Constants; +import org.apache.dubbo.common.URL; +import org.apache.dubbo.common.utils.StringUtils; +import org.apache.dubbo.remoting.zookeeper.ChildListener; +import org.apache.dubbo.remoting.zookeeper.StateListener; +import org.apache.dubbo.remoting.zookeeper.support.AbstractZookeeperClient; import org.apache.zookeeper.CreateMode; import org.apache.zookeeper.KeeperException.NoNodeException; import org.apache.zookeeper.KeeperException.NodeExistsException; @@ -43,6 +42,7 @@ public class CuratorZookeeperClient extends AbstractZookeeperClient + * If you want to extends this, implements createZookeeperClient. + */ +public abstract class AbstractZookeeperTransporter implements ZookeeperTransporter { + private static final Logger logger = LoggerFactory.getLogger(ZookeeperTransporter.class); + private final Map zookeeperClientMap = new ConcurrentHashMap<>(); + + /** + * share connnect for registry, metadata, etc.. + *

+ * Make sure the connection is connected. + * + * @param url + * @return + */ + @Override + public ZookeeperClient connect(URL url) { + ZookeeperClient zookeeperClient; + List addressList = getURLBackupAddress(url); + // The field define the zookeeper server , including protocol, host, port, username, password + if ((zookeeperClient = fetchAndUpdateZookeeperClientCache(addressList)) != null && zookeeperClient.isConnected()) { + logger.info("find valid zookeeper client from the cache for address: " + url); + return zookeeperClient; + } + // avoid creating too many connections, so add lock + synchronized (zookeeperClientMap) { + if ((zookeeperClient = fetchAndUpdateZookeeperClientCache(addressList)) != null && zookeeperClient.isConnected()) { + logger.info("find valid zookeeper client from the cache for address: " + url); + return zookeeperClient; + } + + zookeeperClient = createZookeeperClient(toClientURL(url)); + logger.info("No valid zookeeper client found from cache, therefore create a new client for url. " + url); + writeToClientMap(addressList, zookeeperClient); + } + return zookeeperClient; + } + + /** + * @param url the url that will create zookeeper connection . + * The url in AbstractZookeeperTransporter#connect parameter is rewritten by this one. + * such as: zookeeper://127.0.0.1:2181/org.apache.dubbo.remoting.zookeeper.ZookeeperTransporter + * @return + */ + protected abstract ZookeeperClient createZookeeperClient(URL url); + + /** + * get the ZookeeperClient from cache, the ZookeeperClient must be connected. + *

+ * It is not private method for unit test. + * + * @param addressList + * @return + */ + ZookeeperClient fetchAndUpdateZookeeperClientCache(List addressList) { + + ZookeeperClient zookeeperClient = null; + for (String address : addressList) { + if ((zookeeperClient = zookeeperClientMap.get(address)) != null && zookeeperClient.isConnected()) { + break; + } + } + if (zookeeperClient != null && zookeeperClient.isConnected()) { + writeToClientMap(addressList, zookeeperClient); + } + return zookeeperClient; + } + + /** + * get all zookeeper urls (such as :zookeeper://127.0.0.1:2181?127.0.0.1:8989,127.0.0.1:9999) + * + * @param url such as:zookeeper://127.0.0.1:2181?127.0.0.1:8989,127.0.0.1:9999 + * @return such as 127.0.0.1:2181,127.0.0.1:8989,127.0.0.1:9999 + */ + List getURLBackupAddress(URL url) { + List addressList = new ArrayList(); + addressList.add(url.getAddress()); + + addressList.addAll(url.getParameter(Constants.BACKUP_KEY, Collections.EMPTY_LIST)); + return addressList; + } + + /** + * write address-ZookeeperClient relationship to Map + * + * @param addressList + * @param zookeeperClient + */ + void writeToClientMap(List addressList, ZookeeperClient zookeeperClient) { + for (String address : addressList) { + zookeeperClientMap.put(address, zookeeperClient); + } + } + + /** + * redefine the url for zookeeper. just keep protocol, username, password, host, port, and individual parameter. + * + * @param url + * @return + */ + URL toClientURL(URL url) { + Map parameterMap = new HashMap<>(); + // for CuratorZookeeperClient + if (url.getParameter(Constants.TIMEOUT_KEY) != null) { + parameterMap.put(Constants.TIMEOUT_KEY, url.getParameter(Constants.TIMEOUT_KEY)); + } + if (url.getParameter(Constants.BACKUP_KEY) != null) { + parameterMap.put(Constants.BACKUP_KEY, url.getParameter(Constants.BACKUP_KEY)); + } + return new URL(url.getProtocol(), url.getUsername(), url.getPassword(), url.getHost(), url.getPort(), + ZookeeperTransporter.class.getName(), parameterMap); + } + + /** + * for unit test + * + * @return + */ + Map getZookeeperClientMap() { + return zookeeperClientMap; + } +} diff --git a/dubbo-remoting/dubbo-remoting-zookeeper/src/main/java/org/apache/dubbo/remoting/zookeeper/zkclient/ZkClientWrapper.java b/dubbo-remoting/dubbo-remoting-zookeeper/src/main/java/org/apache/dubbo/remoting/zookeeper/zkclient/ZkClientWrapper.java index 3f873affa42..ae8a3ef87b2 100644 --- a/dubbo-remoting/dubbo-remoting-zookeeper/src/main/java/org/apache/dubbo/remoting/zookeeper/zkclient/ZkClientWrapper.java +++ b/dubbo-remoting/dubbo-remoting-zookeeper/src/main/java/org/apache/dubbo/remoting/zookeeper/zkclient/ZkClientWrapper.java @@ -16,13 +16,12 @@ */ package org.apache.dubbo.remoting.zookeeper.zkclient; -import org.apache.dubbo.common.logger.Logger; -import org.apache.dubbo.common.logger.LoggerFactory; -import org.apache.dubbo.common.utils.Assert; - import org.I0Itec.zkclient.IZkChildListener; import org.I0Itec.zkclient.IZkStateListener; import org.I0Itec.zkclient.ZkClient; +import org.apache.dubbo.common.logger.Logger; +import org.apache.dubbo.common.logger.LoggerFactory; +import org.apache.dubbo.common.utils.Assert; import org.apache.zookeeper.Watcher.Event.KeeperState; import java.util.List; diff --git a/dubbo-remoting/dubbo-remoting-zookeeper/src/main/java/org/apache/dubbo/remoting/zookeeper/zkclient/ZkclientZookeeperClient.java b/dubbo-remoting/dubbo-remoting-zookeeper/src/main/java/org/apache/dubbo/remoting/zookeeper/zkclient/ZkclientZookeeperClient.java index 21339520fc7..c36640025b9 100644 --- a/dubbo-remoting/dubbo-remoting-zookeeper/src/main/java/org/apache/dubbo/remoting/zookeeper/zkclient/ZkclientZookeeperClient.java +++ b/dubbo-remoting/dubbo-remoting-zookeeper/src/main/java/org/apache/dubbo/remoting/zookeeper/zkclient/ZkclientZookeeperClient.java @@ -16,6 +16,11 @@ */ package org.apache.dubbo.remoting.zookeeper.zkclient; + +import org.I0Itec.zkclient.IZkChildListener; +import org.I0Itec.zkclient.IZkStateListener; +import org.I0Itec.zkclient.exception.ZkNoNodeException; +import org.I0Itec.zkclient.exception.ZkNodeExistsException; import org.apache.dubbo.common.Constants; import org.apache.dubbo.common.URL; import org.apache.dubbo.common.logger.Logger; @@ -23,11 +28,6 @@ import org.apache.dubbo.remoting.zookeeper.ChildListener; import org.apache.dubbo.remoting.zookeeper.StateListener; import org.apache.dubbo.remoting.zookeeper.support.AbstractZookeeperClient; - -import org.I0Itec.zkclient.IZkChildListener; -import org.I0Itec.zkclient.IZkStateListener; -import org.I0Itec.zkclient.exception.ZkNoNodeException; -import org.I0Itec.zkclient.exception.ZkNodeExistsException; import org.apache.zookeeper.Watcher.Event.KeeperState; import java.util.List; @@ -63,7 +63,6 @@ public void handleNewSession() throws Exception { client.start(); } - @Override public void createPersistent(String path) { try { diff --git a/dubbo-remoting/dubbo-remoting-zookeeper/src/main/java/org/apache/dubbo/remoting/zookeeper/zkclient/ZkclientZookeeperTransporter.java b/dubbo-remoting/dubbo-remoting-zookeeper/src/main/java/org/apache/dubbo/remoting/zookeeper/zkclient/ZkclientZookeeperTransporter.java index de5ee4b9d4e..0ad86ff7850 100644 --- a/dubbo-remoting/dubbo-remoting-zookeeper/src/main/java/org/apache/dubbo/remoting/zookeeper/zkclient/ZkclientZookeeperTransporter.java +++ b/dubbo-remoting/dubbo-remoting-zookeeper/src/main/java/org/apache/dubbo/remoting/zookeeper/zkclient/ZkclientZookeeperTransporter.java @@ -18,12 +18,11 @@ import org.apache.dubbo.common.URL; import org.apache.dubbo.remoting.zookeeper.ZookeeperClient; -import org.apache.dubbo.remoting.zookeeper.ZookeeperTransporter; - -public class ZkclientZookeeperTransporter implements ZookeeperTransporter { +import org.apache.dubbo.remoting.zookeeper.support.AbstractZookeeperTransporter; +public class ZkclientZookeeperTransporter extends AbstractZookeeperTransporter { @Override - public ZookeeperClient connect(URL url) { + public ZookeeperClient createZookeeperClient(URL url) { return new ZkclientZookeeperClient(url); } diff --git a/dubbo-remoting/dubbo-remoting-zookeeper/src/test/java/org/apache/dubbo/remoting/zookeeper/curator/CuratorZookeeperTransporterTest.java b/dubbo-remoting/dubbo-remoting-zookeeper/src/test/java/org/apache/dubbo/remoting/zookeeper/curator/CuratorZookeeperTransporterTest.java index f66d89693a0..2fe78745add 100644 --- a/dubbo-remoting/dubbo-remoting-zookeeper/src/test/java/org/apache/dubbo/remoting/zookeeper/curator/CuratorZookeeperTransporterTest.java +++ b/dubbo-remoting/dubbo-remoting-zookeeper/src/test/java/org/apache/dubbo/remoting/zookeeper/curator/CuratorZookeeperTransporterTest.java @@ -16,6 +16,7 @@ */ package org.apache.dubbo.remoting.zookeeper.curator; +import org.apache.curator.test.TestingServer; import org.apache.dubbo.common.URL; import org.apache.dubbo.common.utils.NetUtils; import org.apache.dubbo.remoting.zookeeper.ZookeeperClient; @@ -32,13 +33,16 @@ public class CuratorZookeeperTransporterTest { private TestingServer zkServer; private ZookeeperClient zookeeperClient; + private CuratorZookeeperTransporter curatorZookeeperTransporter; + private int zkServerPort; @BeforeEach public void setUp() throws Exception { - int zkServerPort = NetUtils.getAvailablePort(); + zkServerPort = NetUtils.getAvailablePort(); zkServer = new TestingServer(zkServerPort, true); zookeeperClient = new CuratorZookeeperTransporter().connect(URL.valueOf("zookeeper://127.0.0.1:" + zkServerPort + "/service")); + curatorZookeeperTransporter = new CuratorZookeeperTransporter(); } @Test @@ -51,4 +55,4 @@ public void testZookeeperClient() { public void tearDown() throws Exception { zkServer.stop(); } -} \ No newline at end of file +} diff --git a/dubbo-remoting/dubbo-remoting-zookeeper/src/test/java/org/apache/dubbo/remoting/zookeeper/support/AbstractZookeeperTransporterTest.java b/dubbo-remoting/dubbo-remoting-zookeeper/src/test/java/org/apache/dubbo/remoting/zookeeper/support/AbstractZookeeperTransporterTest.java new file mode 100644 index 00000000000..eb6965a0c65 --- /dev/null +++ b/dubbo-remoting/dubbo-remoting-zookeeper/src/test/java/org/apache/dubbo/remoting/zookeeper/support/AbstractZookeeperTransporterTest.java @@ -0,0 +1,238 @@ +/* + * 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.remoting.zookeeper.support; + +import org.apache.dubbo.common.Constants; +import org.apache.dubbo.common.URL; +import org.apache.dubbo.common.utils.NetUtils; +import org.apache.dubbo.remoting.zookeeper.ZookeeperClient; +import org.apache.dubbo.remoting.zookeeper.ZookeeperTransporter; +import org.apache.dubbo.remoting.zookeeper.curator.CuratorZookeeperTransporter; + +import org.apache.curator.test.TestingServer; +import org.junit.jupiter.api.AfterEach; +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; + +import java.util.List; + +import static org.hamcrest.MatcherAssert.assertThat; +import static org.hamcrest.core.IsNot.not; +import static org.hamcrest.core.IsNull.nullValue; + +/** + * AbstractZookeeperTransporterTest + */ +public class AbstractZookeeperTransporterTest { + private TestingServer zkServer; + private ZookeeperClient zookeeperClient; + private AbstractZookeeperTransporter abstractZookeeperTransporter; + private int zkServerPort; + + @BeforeEach + public void setUp() throws Exception { + zkServerPort = NetUtils.getAvailablePort(); + zkServer = new TestingServer(zkServerPort, true); + zookeeperClient = new CuratorZookeeperTransporter().connect(URL.valueOf("zookeeper://127.0.0.1:" + + zkServerPort + "/service")); + abstractZookeeperTransporter = new CuratorZookeeperTransporter(); + } + + + @AfterEach + public void tearDown() throws Exception { + zkServer.stop(); + } + + @Test + public void testZookeeperClient() { + assertThat(zookeeperClient, not(nullValue())); + zookeeperClient.close(); + } + + @Test + public void testCreateServerURL() { + URL url = URL.valueOf("zookeeper://127.0.0.1:" + zkServerPort + "/org.apache.dubbo.registry.RegistryService?application=metadatareport-local-xml-provider2&dubbo=2.0.2&interface=org.apache.dubbo.registry.RegistryService&pid=47418&specVersion=2.7.0-SNAPSHOT×tamp=1547102428828&timeout=2300"); + URL newUrl = abstractZookeeperTransporter.toClientURL(url); + Assertions.assertEquals(newUrl.getProtocol(), "zookeeper"); + Assertions.assertEquals(newUrl.getHost(), "127.0.0.1"); + Assertions.assertEquals(newUrl.getPort(), zkServerPort); + Assertions.assertNull(newUrl.getUsername()); + Assertions.assertNull(newUrl.getPassword()); + Assertions.assertEquals(newUrl.getParameter(Constants.TIMEOUT_KEY, 5000), 2300); + Assertions.assertEquals(newUrl.getParameters().size(), 1); + Assertions.assertEquals(newUrl.getPath(), ZookeeperTransporter.class.getName()); + } + + + @Test + public void testToCreateURLWhenHasUser() { + URL url = URL.valueOf("zookeeper://us2:pw2@127.0.0.1:" + zkServerPort + "/org.apache.dubbo.registry.RegistryService?application=metadatareport-local-xml-provider2&dubbo=2.0.2&interface=org.apache.dubbo.registry.RegistryService&pid=47418&specVersion=2.7.0-SNAPSHOT×tamp=1547102428828"); + URL newUrl = abstractZookeeperTransporter.toClientURL(url); + Assertions.assertEquals(newUrl.getProtocol(), "zookeeper"); + Assertions.assertEquals(newUrl.getHost(), "127.0.0.1"); + Assertions.assertEquals(newUrl.getPort(), zkServerPort); + Assertions.assertEquals(newUrl.getUsername(), "us2"); + Assertions.assertEquals(newUrl.getPassword(), "pw2"); + Assertions.assertEquals(newUrl.getParameters().size(), 0); + Assertions.assertEquals(newUrl.getPath(), ZookeeperTransporter.class.getName()); + } + + @Test + public void testGetURLBackupAddress() { + URL url = URL.valueOf("zookeeper://127.0.0.1:" + zkServerPort + "/org.apache.dubbo.registry.RegistryService?backup=127.0.0.1:" + 9099 + "&application=metadatareport-local-xml-provider2&dubbo=2.0.2&interface=org.apache.dubbo.registry.RegistryService&pid=47418&specVersion=2.7.0-SNAPSHOT×tamp=1547102428828"); + List stringList = abstractZookeeperTransporter.getURLBackupAddress(url); + Assertions.assertEquals(stringList.size(), 2); + Assertions.assertEquals(stringList.get(0), "127.0.0.1:" + zkServerPort); + Assertions.assertEquals(stringList.get(1), "127.0.0.1:9099"); + } + + @Test + public void testGetURLBackupAddressNoBack() { + URL url = URL.valueOf("zookeeper://127.0.0.1:" + zkServerPort + "/org.apache.dubbo.registry.RegistryService?application=metadatareport-local-xml-provider2&dubbo=2.0.2&interface=org.apache.dubbo.registry.RegistryService&pid=47418&specVersion=2.7.0-SNAPSHOT×tamp=1547102428828"); + List stringList = abstractZookeeperTransporter.getURLBackupAddress(url); + Assertions.assertEquals(stringList.size(), 1); + Assertions.assertEquals(stringList.get(0), "127.0.0.1:" + zkServerPort); + } + + @Test + public void testFetchAndUpdateZookeeperClientCache() throws Exception { + int zkServerPort2 = NetUtils.getAvailablePort(); + TestingServer zkServer2 = new TestingServer(zkServerPort2, true); + + int zkServerPort3 = NetUtils.getAvailablePort(); + TestingServer zkServer3 = new TestingServer(zkServerPort3, true); + + URL url = URL.valueOf("zookeeper://127.0.0.1:" + zkServerPort + "/org.apache.dubbo.registry.RegistryService?backup=127.0.0.1:" + zkServerPort3 + ",127.0.0.1:" + zkServerPort2 + "&application=metadatareport-local-xml-provider2&dubbo=2.0.2&interface=org.apache.dubbo.registry.RegistryService&pid=47418&specVersion=2.7.0-SNAPSHOT×tamp=1547102428828"); + ZookeeperClient newZookeeperClient = abstractZookeeperTransporter.connect(url); + //just for connected + newZookeeperClient.getContent("/dubbo/test"); + Assertions.assertEquals(abstractZookeeperTransporter.getZookeeperClientMap().size(), 3); + Assertions.assertEquals(abstractZookeeperTransporter.getZookeeperClientMap().get("127.0.0.1:" + zkServerPort), newZookeeperClient); + + URL url2 = URL.valueOf("zookeeper://127.0.0.1:" + zkServerPort + "/org.apache.dubbo.metadata.store.MetadataReport?address=zookeeper://127.0.0.1:2181&application=metadatareport-local-xml-provider2&cycle-report=false&interface=org.apache.dubbo.metadata.store.MetadataReport&retry-period=4590&retry-times=23&sync-report=true"); + checkFetchAndUpdateCacheNotNull(url2); + URL url3 = URL.valueOf("zookeeper://127.0.0.1:8778/org.apache.dubbo.metadata.store.MetadataReport?backup=127.0.0.1:" + zkServerPort3 + "&address=zookeeper://127.0.0.1:2181&application=metadatareport-local-xml-provider2&cycle-report=false&interface=org.apache.dubbo.metadata.store.MetadataReport&retry-period=4590&retry-times=23&sync-report=true"); + checkFetchAndUpdateCacheNotNull(url3); + + zkServer2.stop(); + zkServer3.stop(); + } + + private void checkFetchAndUpdateCacheNotNull(URL url) { + List addressList = abstractZookeeperTransporter.getURLBackupAddress(url); + ZookeeperClient zookeeperClient = abstractZookeeperTransporter.fetchAndUpdateZookeeperClientCache(addressList); + Assertions.assertNotNull(zookeeperClient); + } + + @Test + public void testRepeatConnect() { + URL url = URL.valueOf("zookeeper://127.0.0.1:" + zkServerPort + "/org.apache.dubbo.registry.RegistryService?application=metadatareport-local-xml-provider2&dubbo=2.0.2&interface=org.apache.dubbo.registry.RegistryService&pid=47418&specVersion=2.7.0-SNAPSHOT×tamp=1547102428828"); + URL url2 = URL.valueOf("zookeeper://127.0.0.1:" + zkServerPort + "/org.apache.dubbo.metadata.store.MetadataReport?address=zookeeper://127.0.0.1:2181&application=metadatareport-local-xml-provider2&cycle-report=false&interface=org.apache.dubbo.metadata.store.MetadataReport&retry-period=4590&retry-times=23&sync-report=true"); + ZookeeperClient newZookeeperClient = abstractZookeeperTransporter.connect(url); + //just for connected + newZookeeperClient.getContent("/dubbo/test"); + Assertions.assertEquals(abstractZookeeperTransporter.getZookeeperClientMap().size(), 1); + Assertions.assertEquals(abstractZookeeperTransporter.getZookeeperClientMap().get("127.0.0.1:" + zkServerPort), newZookeeperClient); + Assertions.assertTrue(newZookeeperClient.isConnected()); + + ZookeeperClient newZookeeperClient2 = abstractZookeeperTransporter.connect(url2); + //just for connected + newZookeeperClient2.getContent("/dubbo/test"); + Assertions.assertEquals(newZookeeperClient, newZookeeperClient2); + Assertions.assertEquals(abstractZookeeperTransporter.getZookeeperClientMap().size(), 1); + Assertions.assertEquals(abstractZookeeperTransporter.getZookeeperClientMap().get("127.0.0.1:" + zkServerPort), newZookeeperClient); + } + + @Test + public void testNotRepeatConnect() throws Exception { + int zkServerPort2 = NetUtils.getAvailablePort(); + TestingServer zkServer2 = new TestingServer(zkServerPort2, true); + + URL url = URL.valueOf("zookeeper://127.0.0.1:" + zkServerPort + "/org.apache.dubbo.registry.RegistryService?application=metadatareport-local-xml-provider2&dubbo=2.0.2&interface=org.apache.dubbo.registry.RegistryService&pid=47418&specVersion=2.7.0-SNAPSHOT×tamp=1547102428828"); + URL url2 = URL.valueOf("zookeeper://127.0.0.1:" + zkServerPort2 + "/org.apache.dubbo.metadata.store.MetadataReport?address=zookeeper://127.0.0.1:2181&application=metadatareport-local-xml-provider2&cycle-report=false&interface=org.apache.dubbo.metadata.store.MetadataReport&retry-period=4590&retry-times=23&sync-report=true"); + ZookeeperClient newZookeeperClient = abstractZookeeperTransporter.connect(url); + //just for connected + newZookeeperClient.getContent("/dubbo/test"); + Assertions.assertEquals(abstractZookeeperTransporter.getZookeeperClientMap().size(), 1); + Assertions.assertEquals(abstractZookeeperTransporter.getZookeeperClientMap().get("127.0.0.1:" + zkServerPort), newZookeeperClient); + + ZookeeperClient newZookeeperClient2 = abstractZookeeperTransporter.connect(url2); + //just for connected + newZookeeperClient2.getContent("/dubbo/test"); + Assertions.assertNotEquals(newZookeeperClient, newZookeeperClient2); + Assertions.assertEquals(abstractZookeeperTransporter.getZookeeperClientMap().size(), 2); + Assertions.assertEquals(abstractZookeeperTransporter.getZookeeperClientMap().get("127.0.0.1:" + zkServerPort2), newZookeeperClient2); + + zkServer2.stop(); + } + + @Test + public void testRepeatConnectForBackUpAdd() throws Exception { + int zkServerPort2 = NetUtils.getAvailablePort(); + TestingServer zkServer2 = new TestingServer(zkServerPort2, true); + + int zkServerPort3 = NetUtils.getAvailablePort(); + TestingServer zkServer3 = new TestingServer(zkServerPort3, true); + + URL url = URL.valueOf("zookeeper://127.0.0.1:" + zkServerPort + "/org.apache.dubbo.registry.RegistryService?backup=127.0.0.1:" + zkServerPort2 + "&application=metadatareport-local-xml-provider2&dubbo=2.0.2&interface=org.apache.dubbo.registry.RegistryService&pid=47418&specVersion=2.7.0-SNAPSHOT×tamp=1547102428828"); + URL url2 = URL.valueOf("zookeeper://127.0.0.1:" + zkServerPort2 + "/org.apache.dubbo.metadata.store.MetadataReport?backup=127.0.0.1:" + zkServerPort3 + "&address=zookeeper://127.0.0.1:2181&application=metadatareport-local-xml-provider2&cycle-report=false&interface=org.apache.dubbo.metadata.store.MetadataReport&retry-period=4590&retry-times=23&sync-report=true"); + ZookeeperClient newZookeeperClient = abstractZookeeperTransporter.connect(url); + //just for connected + newZookeeperClient.getContent("/dubbo/test"); + Assertions.assertEquals(abstractZookeeperTransporter.getZookeeperClientMap().size(), 2); + Assertions.assertEquals(abstractZookeeperTransporter.getZookeeperClientMap().get("127.0.0.1:" + zkServerPort), newZookeeperClient); + + ZookeeperClient newZookeeperClient2 = abstractZookeeperTransporter.connect(url2); + //just for connected + newZookeeperClient2.getContent("/dubbo/test"); + Assertions.assertEquals(newZookeeperClient, newZookeeperClient2); + Assertions.assertEquals(abstractZookeeperTransporter.getZookeeperClientMap().size(), 3); + Assertions.assertEquals(abstractZookeeperTransporter.getZookeeperClientMap().get("127.0.0.1:" + zkServerPort2), newZookeeperClient2); + + zkServer2.stop(); + zkServer3.stop(); + } + + @Test + public void testRepeatConnectForNoMatchBackUpAdd() throws Exception { + int zkServerPort2 = NetUtils.getAvailablePort(); + TestingServer zkServer2 = new TestingServer(zkServerPort2, true); + + int zkServerPort3 = NetUtils.getAvailablePort(); + TestingServer zkServer3 = new TestingServer(zkServerPort3, true); + + URL url = URL.valueOf("zookeeper://127.0.0.1:" + zkServerPort + "/org.apache.dubbo.registry.RegistryService?backup=127.0.0.1:" + zkServerPort3 + "&application=metadatareport-local-xml-provider2&dubbo=2.0.2&interface=org.apache.dubbo.registry.RegistryService&pid=47418&specVersion=2.7.0-SNAPSHOT×tamp=1547102428828"); + URL url2 = URL.valueOf("zookeeper://127.0.0.1:" + zkServerPort2 + "/org.apache.dubbo.metadata.store.MetadataReport?address=zookeeper://127.0.0.1:2181&application=metadatareport-local-xml-provider2&cycle-report=false&interface=org.apache.dubbo.metadata.store.MetadataReport&retry-period=4590&retry-times=23&sync-report=true"); + ZookeeperClient newZookeeperClient = abstractZookeeperTransporter.connect(url); + //just for connected + newZookeeperClient.getContent("/dubbo/test"); + Assertions.assertEquals(abstractZookeeperTransporter.getZookeeperClientMap().size(), 2); + Assertions.assertEquals(abstractZookeeperTransporter.getZookeeperClientMap().get("127.0.0.1:" + zkServerPort), newZookeeperClient); + + ZookeeperClient newZookeeperClient2 = abstractZookeeperTransporter.connect(url2); + //just for connected + newZookeeperClient2.getContent("/dubbo/test"); + Assertions.assertNotEquals(newZookeeperClient, newZookeeperClient2); + Assertions.assertEquals(abstractZookeeperTransporter.getZookeeperClientMap().size(), 3); + Assertions.assertEquals(abstractZookeeperTransporter.getZookeeperClientMap().get("127.0.0.1:" + zkServerPort2), newZookeeperClient2); + + zkServer2.stop(); + zkServer3.stop(); + } +} diff --git a/dubbo-remoting/pom.xml b/dubbo-remoting/pom.xml index e756783ba8a..d646c2235eb 100644 --- a/dubbo-remoting/pom.xml +++ b/dubbo-remoting/pom.xml @@ -20,7 +20,7 @@ org.apache.dubbo dubbo-parent - 2.7.0-SNAPSHOT + 2.7.1-SNAPSHOT dubbo-remoting pom diff --git a/dubbo-rpc/dubbo-rpc-api/pom.xml b/dubbo-rpc/dubbo-rpc-api/pom.xml index 2467d3f5fbe..06d17aec9e9 100644 --- a/dubbo-rpc/dubbo-rpc-api/pom.xml +++ b/dubbo-rpc/dubbo-rpc-api/pom.xml @@ -1,48 +1,48 @@ - - - 4.0.0 - - org.apache.dubbo - dubbo-rpc - 2.7.0-SNAPSHOT - - dubbo-rpc-api - jar - ${project.artifactId} - The rpc module of dubbo project - - false - - - - org.apache.dubbo - dubbo-common - ${project.parent.version} - - - org.apache.dubbo - dubbo-serialization-api - ${project.parent.version} - - - org.apache.dubbo - dubbo-remoting-api - ${project.parent.version} - - + + + 4.0.0 + + org.apache.dubbo + dubbo-rpc + 2.7.1-SNAPSHOT + + dubbo-rpc-api + jar + ${project.artifactId} + The rpc module of dubbo project + + false + + + + org.apache.dubbo + dubbo-common + ${project.parent.version} + + + org.apache.dubbo + dubbo-serialization-api + ${project.parent.version} + + + org.apache.dubbo + dubbo-remoting-api + ${project.parent.version} + + \ No newline at end of file diff --git a/dubbo-rpc/dubbo-rpc-api/src/main/java/org/apache/dubbo/rpc/AsyncContext.java b/dubbo-rpc/dubbo-rpc-api/src/main/java/org/apache/dubbo/rpc/AsyncContext.java index cc9ff1a2d9a..1f51a54d4ff 100644 --- a/dubbo-rpc/dubbo-rpc-api/src/main/java/org/apache/dubbo/rpc/AsyncContext.java +++ b/dubbo-rpc/dubbo-rpc-api/src/main/java/org/apache/dubbo/rpc/AsyncContext.java @@ -16,8 +16,6 @@ */ package org.apache.dubbo.rpc; -import java.util.concurrent.CompletableFuture; - /** * AsyncContext works like {@see javax.servlet.AsyncContext} in the Servlet 3.0. * An AsyncContext is stated by a call to {@link RpcContext#startAsync()}. @@ -27,14 +25,6 @@ */ public interface AsyncContext { - /** - * get the internal future which is binding to this async context - * - * @return the internal future - */ - // FIXME - CompletableFuture getInternalFuture(); - /** * write value and complete the async context. * diff --git a/dubbo-rpc/dubbo-rpc-api/src/main/java/org/apache/dubbo/rpc/AsyncContextImpl.java b/dubbo-rpc/dubbo-rpc-api/src/main/java/org/apache/dubbo/rpc/AsyncContextImpl.java index 77cf0bd17b8..f8f67433658 100644 --- a/dubbo-rpc/dubbo-rpc-api/src/main/java/org/apache/dubbo/rpc/AsyncContextImpl.java +++ b/dubbo-rpc/dubbo-rpc-api/src/main/java/org/apache/dubbo/rpc/AsyncContextImpl.java @@ -34,10 +34,6 @@ public class AsyncContextImpl implements AsyncContext { private RpcContext storedServerContext; public AsyncContextImpl() { - } - - public AsyncContextImpl(CompletableFuture future) { - this.future = future; this.storedContext = RpcContext.getContext(); this.storedServerContext = RpcContext.getServerContext(); } @@ -68,7 +64,9 @@ public boolean stop() { @Override public void start() { - this.started.set(true); + if (this.started.compareAndSet(false, true)) { + this.future = new CompletableFuture<>(); + } } @Override @@ -78,8 +76,7 @@ public void signalContextSwitch() { // Restore any other contexts in here if necessary. } - @Override - public CompletableFuture getInternalFuture() { + public CompletableFuture getInternalFuture() { return future; } } diff --git a/dubbo-rpc/dubbo-rpc-api/src/main/java/org/apache/dubbo/rpc/AsyncRpcResult.java b/dubbo-rpc/dubbo-rpc-api/src/main/java/org/apache/dubbo/rpc/AsyncRpcResult.java index 76675bcc265..b631dffe180 100644 --- a/dubbo-rpc/dubbo-rpc-api/src/main/java/org/apache/dubbo/rpc/AsyncRpcResult.java +++ b/dubbo-rpc/dubbo-rpc-api/src/main/java/org/apache/dubbo/rpc/AsyncRpcResult.java @@ -25,6 +25,34 @@ import java.util.function.Function; /** + * NOTICE!! + * + *

+ * You should never rely on this class directly when using or extending Dubbo, the implementation of {@link AsyncRpcResult} + * is only a workaround for compatibility purpose. It may be changed or even get removed from the next major version. + * Please only use {@link Result} or {@link RpcResult}. + * + * Extending the {@link Filter} is one typical use case: + *

+ * {@code
+ * public class YourFilter implements Filter {
+ *     @Override
+ *     public Result onResponse(Result result, Invoker invoker, Invocation invocation) {
+ *         System.out.println("Filter get the return value: " + result.getValue());
+ *         // Don't do this
+ *         // AsyncRpcResult asyncRpcResult = ((AsyncRpcResult)result;
+ *         // System.out.println("Filter get the return value: " + asyncRpcResult.getValue());
+ *         return result;
+ *     }
+ *
+ *     @Override
+ *     public Result invoke(Invoker invoker, Invocation invocation) throws RpcException {
+ *         return invoker.invoke(invocation);
+ *     }
+ * }
+ * }
+ * 
+ *

* TODO RpcResult can be an instance of {@link java.util.concurrent.CompletionStage} instead of composing CompletionStage inside. */ public class AsyncRpcResult extends AbstractResult { @@ -119,15 +147,15 @@ public void setResultFuture(CompletableFuture resultFuture) { } public Result getRpcResult() { - Result result; try { - result = resultFuture.get(); + if (resultFuture.isDone()) { + return resultFuture.get(); + } } catch (Exception e) { // This should never happen; - logger.error("", e); - result = new RpcResult(); + logger.error("Got exception when trying to fetch the underlying result from AsyncRpcResult.", e); } - return result; + return new RpcResult(); } @Override diff --git a/dubbo-rpc/dubbo-rpc-api/src/main/java/org/apache/dubbo/rpc/RpcContext.java b/dubbo-rpc/dubbo-rpc-api/src/main/java/org/apache/dubbo/rpc/RpcContext.java index f6c5699fd0a..7c10081e5f2 100644 --- a/dubbo-rpc/dubbo-rpc-api/src/main/java/org/apache/dubbo/rpc/RpcContext.java +++ b/dubbo-rpc/dubbo-rpc-api/src/main/java/org/apache/dubbo/rpc/RpcContext.java @@ -733,12 +733,11 @@ public void asyncCall(Runnable runnable) { @SuppressWarnings("unchecked") public static AsyncContext startAsync() throws IllegalStateException { RpcContext currentContext = getContext(); - if (currentContext.asyncContext != null) { - currentContext.asyncContext.start(); - return currentContext.asyncContext; - } else { - throw new IllegalStateException("This service does not support asynchronous operations, you should open async explicitly before use."); + if (currentContext.asyncContext == null) { + currentContext.asyncContext = new AsyncContextImpl(); } + currentContext.asyncContext.start(); + return currentContext.asyncContext; } public boolean isAsyncStarted() { @@ -752,10 +751,6 @@ public boolean stopAsync() { return asyncContext.stop(); } - public void setAsyncContext(AsyncContext asyncContext) { - this.asyncContext = asyncContext; - } - public AsyncContext getAsyncContext() { return asyncContext; } diff --git a/dubbo-rpc/dubbo-rpc-api/src/main/java/org/apache/dubbo/rpc/SimpleAsyncRpcResult.java b/dubbo-rpc/dubbo-rpc-api/src/main/java/org/apache/dubbo/rpc/SimpleAsyncRpcResult.java index 49a492b1ceb..98e42d94a38 100644 --- a/dubbo-rpc/dubbo-rpc-api/src/main/java/org/apache/dubbo/rpc/SimpleAsyncRpcResult.java +++ b/dubbo-rpc/dubbo-rpc-api/src/main/java/org/apache/dubbo/rpc/SimpleAsyncRpcResult.java @@ -20,6 +20,17 @@ /** * A sub class used for normal async invoke. + * + * NOTICE!! + * + *

+ * You should never rely on this class directly when using or extending Dubbo, the implementation of {@link SimpleAsyncRpcResult} + * is only a workaround for compatibility purpose. It may be changed or even get removed from the next major version. + * Please only use {@link Result} or {@link RpcResult}. + *

+ * + * Check {@link AsyncRpcResult} for more details. + * * TODO AsyncRpcResult, AsyncNormalRpcResult should not be a parent-child hierarchy. */ public class SimpleAsyncRpcResult extends AsyncRpcResult { diff --git a/dubbo-rpc/dubbo-rpc-api/src/main/java/org/apache/dubbo/rpc/filter/AccessLogFilter.java b/dubbo-rpc/dubbo-rpc-api/src/main/java/org/apache/dubbo/rpc/filter/AccessLogFilter.java index a3eb0bb251b..dd95d3fd10e 100644 --- a/dubbo-rpc/dubbo-rpc-api/src/main/java/org/apache/dubbo/rpc/filter/AccessLogFilter.java +++ b/dubbo-rpc/dubbo-rpc-api/src/main/java/org/apache/dubbo/rpc/filter/AccessLogFilter.java @@ -16,8 +16,6 @@ */ package org.apache.dubbo.rpc.filter; -import static org.apache.dubbo.common.utils.DateUtil.format; - import org.apache.dubbo.common.Constants; import org.apache.dubbo.common.extension.Activate; import org.apache.dubbo.common.logger.Logger; @@ -36,6 +34,8 @@ import java.io.File; import java.io.FileWriter; import java.io.IOException; +import java.text.DateFormat; +import java.text.SimpleDateFormat; import java.util.Date; import java.util.Iterator; import java.util.Map; @@ -72,6 +72,9 @@ public class AccessLogFilter implements Filter { private static final String FILE_DATE_FORMAT = "yyyyMMdd"; + // It's safe to declare it as singleton since it runs on single thread only + private static final DateFormat FILE_NAME_FORMATTER = new SimpleDateFormat(FILE_DATE_FORMAT); + private static final Map> logEntries = new ConcurrentHashMap>(); private static final ScheduledExecutorService logScheduled = Executors.newSingleThreadScheduledExecutor(new NamedThreadFactory("Dubbo-Access-Log", true)); @@ -185,12 +188,12 @@ private void createIfLogDirAbsent(File file) { private void renameFile(File file) { if (file.exists()) { - String now = format(new Date(), FILE_DATE_FORMAT); - String last = format(new Date(file.lastModified()), FILE_DATE_FORMAT); + String now = FILE_NAME_FORMATTER.format(new Date()); + String last = FILE_NAME_FORMATTER.format(new Date(file.lastModified())); if (!now.equals(last)) { File archive = new File(file.getAbsolutePath() + "." + last); file.renameTo(archive); } } } -} \ No newline at end of file +} diff --git a/dubbo-rpc/dubbo-rpc-api/src/main/java/org/apache/dubbo/rpc/filter/ContextFilter.java b/dubbo-rpc/dubbo-rpc-api/src/main/java/org/apache/dubbo/rpc/filter/ContextFilter.java index 7dd5522096a..7f30151d1d1 100644 --- a/dubbo-rpc/dubbo-rpc-api/src/main/java/org/apache/dubbo/rpc/filter/ContextFilter.java +++ b/dubbo-rpc/dubbo-rpc-api/src/main/java/org/apache/dubbo/rpc/filter/ContextFilter.java @@ -42,14 +42,18 @@ public class ContextFilter implements Filter { public Result invoke(Invoker invoker, Invocation invocation) throws RpcException { Map attachments = invocation.getAttachments(); if (attachments != null) { - attachments = new HashMap(attachments); + attachments = new HashMap<>(attachments); attachments.remove(Constants.PATH_KEY); + attachments.remove(Constants.INTERFACE_KEY); attachments.remove(Constants.GROUP_KEY); attachments.remove(Constants.VERSION_KEY); attachments.remove(Constants.DUBBO_VERSION_KEY); attachments.remove(Constants.TOKEN_KEY); attachments.remove(Constants.TIMEOUT_KEY); - attachments.remove(Constants.ASYNC_KEY);// Remove async property to avoid being passed to the following invoke chain. + // Remove async property to avoid being passed to the following invoke chain. + attachments.remove(Constants.ASYNC_KEY); + attachments.remove(Constants.TAG_KEY); + attachments.remove(Constants.FORCE_USE_TAG); } RpcContext.getContext() .setInvoker(invoker) diff --git a/dubbo-rpc/dubbo-rpc-api/src/main/java/org/apache/dubbo/rpc/filter/TimeoutFilter.java b/dubbo-rpc/dubbo-rpc-api/src/main/java/org/apache/dubbo/rpc/filter/TimeoutFilter.java index ad783efd992..c00689fc1c8 100644 --- a/dubbo-rpc/dubbo-rpc-api/src/main/java/org/apache/dubbo/rpc/filter/TimeoutFilter.java +++ b/dubbo-rpc/dubbo-rpc-api/src/main/java/org/apache/dubbo/rpc/filter/TimeoutFilter.java @@ -25,6 +25,7 @@ import org.apache.dubbo.rpc.Invoker; import org.apache.dubbo.rpc.Result; import org.apache.dubbo.rpc.RpcException; +import org.apache.dubbo.rpc.RpcInvocation; import java.util.Arrays; @@ -36,21 +37,38 @@ public class TimeoutFilter implements Filter { private static final Logger logger = LoggerFactory.getLogger(TimeoutFilter.class); + private static final String TIMEOUT_FILTER_START_TIME = "timeout_filter_start_time"; + @Override public Result invoke(Invoker invoker, Invocation invocation) throws RpcException { - long start = System.currentTimeMillis(); - Result result = invoker.invoke(invocation); - long elapsed = System.currentTimeMillis() - start; - if (invoker.getUrl() != null - && elapsed > invoker.getUrl().getMethodParameter(invocation.getMethodName(), - "timeout", Integer.MAX_VALUE)) { - if (logger.isWarnEnabled()) { - logger.warn("invoke time out. method: " + invocation.getMethodName() - + " arguments: " + Arrays.toString(invocation.getArguments()) + " , url is " - + invoker.getUrl() + ", invoke elapsed " + elapsed + " ms."); + if (invocation.getAttachments() != null) { + long start = System.currentTimeMillis(); + invocation.getAttachments().put(TIMEOUT_FILTER_START_TIME, String.valueOf(start)); + } else { + if (invocation instanceof RpcInvocation) { + RpcInvocation invc = (RpcInvocation) invocation; + long start = System.currentTimeMillis(); + invc.setAttachment(TIMEOUT_FILTER_START_TIME, String.valueOf(start)); } } - return result; + return invoker.invoke(invocation); } + @Override + public Result onResponse(Result result, Invoker invoker, Invocation invocation) { + String startAttach = invocation.getAttachment(TIMEOUT_FILTER_START_TIME); + if (startAttach != null) { + long elapsed = System.currentTimeMillis() - Long.valueOf(startAttach); + if (invoker.getUrl() != null + && elapsed > invoker.getUrl().getMethodParameter(invocation.getMethodName(), + "timeout", Integer.MAX_VALUE)) { + if (logger.isWarnEnabled()) { + logger.warn("invoke time out. method: " + invocation.getMethodName() + + " arguments: " + Arrays.toString(invocation.getArguments()) + " , url is " + + invoker.getUrl() + ", invoke elapsed " + elapsed + " ms."); + } + } + } + return result; + } } diff --git a/dubbo-rpc/dubbo-rpc-api/src/main/java/org/apache/dubbo/rpc/protocol/AbstractInvoker.java b/dubbo-rpc/dubbo-rpc-api/src/main/java/org/apache/dubbo/rpc/protocol/AbstractInvoker.java index 4979916e66f..3df1f1d741e 100644 --- a/dubbo-rpc/dubbo-rpc-api/src/main/java/org/apache/dubbo/rpc/protocol/AbstractInvoker.java +++ b/dubbo-rpc/dubbo-rpc-api/src/main/java/org/apache/dubbo/rpc/protocol/AbstractInvoker.java @@ -22,6 +22,7 @@ import org.apache.dubbo.common.logger.Logger; import org.apache.dubbo.common.logger.LoggerFactory; import org.apache.dubbo.common.utils.ArrayUtils; +import org.apache.dubbo.common.utils.CollectionUtils; import org.apache.dubbo.common.utils.NetUtils; import org.apache.dubbo.rpc.Invocation; import org.apache.dubbo.rpc.Invoker; @@ -134,11 +135,11 @@ public Result invoke(Invocation inv) throws RpcException { } RpcInvocation invocation = (RpcInvocation) inv; invocation.setInvoker(this); - if (attachment != null && attachment.size() > 0) { + if (CollectionUtils.isNotEmptyMap(attachment)) { invocation.addAttachmentsIfAbsent(attachment); } Map contextAttachments = RpcContext.getContext().getAttachments(); - if (contextAttachments != null && contextAttachments.size() != 0) { + if (CollectionUtils.isNotEmptyMap(contextAttachments)) { /** * invocation.addAttachmentsIfAbsent(context){@link RpcInvocation#addAttachmentsIfAbsent(Map)}should not be used here, * because the {@link RpcContext#setAttachment(String, String)} is passed in the Filter when the call is triggered @@ -152,7 +153,6 @@ public Result invoke(Invocation inv) throws RpcException { } RpcUtils.attachInvocationIdIfAsync(getUrl(), invocation); - try { return doInvoke(invocation); } catch (InvocationTargetException e) { // biz exception diff --git a/dubbo-rpc/dubbo-rpc-api/src/main/java/org/apache/dubbo/rpc/protocol/AbstractProxyProtocol.java b/dubbo-rpc/dubbo-rpc-api/src/main/java/org/apache/dubbo/rpc/protocol/AbstractProxyProtocol.java index c87f244ac62..a77a5bdc5f3 100644 --- a/dubbo-rpc/dubbo-rpc-api/src/main/java/org/apache/dubbo/rpc/protocol/AbstractProxyProtocol.java +++ b/dubbo-rpc/dubbo-rpc-api/src/main/java/org/apache/dubbo/rpc/protocol/AbstractProxyProtocol.java @@ -28,6 +28,7 @@ import org.apache.dubbo.rpc.RpcException; import java.util.List; +import java.util.Objects; import java.util.concurrent.CopyOnWriteArrayList; /** @@ -66,7 +67,10 @@ public Exporter export(final Invoker invoker) throws RpcException { final String uri = serviceKey(invoker.getUrl()); Exporter exporter = (Exporter) exporterMap.get(uri); if (exporter != null) { - return exporter; + // When modifying the configuration through override, you need to re-expose the newly modified service. + if (Objects.equals(exporter.getInvoker().getUrl(), invoker.getUrl())) { + return exporter; + } } final Runnable runnable = doExport(proxyFactory.getProxy(invoker, true), invoker.getInterface(), invoker.getUrl()); exporter = new AbstractExporter(invoker) { diff --git a/dubbo-rpc/dubbo-rpc-api/src/main/java/org/apache/dubbo/rpc/proxy/AbstractProxyInvoker.java b/dubbo-rpc/dubbo-rpc-api/src/main/java/org/apache/dubbo/rpc/proxy/AbstractProxyInvoker.java index 0f5a5df6252..6a562d6f6fd 100644 --- a/dubbo-rpc/dubbo-rpc-api/src/main/java/org/apache/dubbo/rpc/proxy/AbstractProxyInvoker.java +++ b/dubbo-rpc/dubbo-rpc-api/src/main/java/org/apache/dubbo/rpc/proxy/AbstractProxyInvoker.java @@ -19,6 +19,7 @@ import org.apache.dubbo.common.URL; import org.apache.dubbo.common.logger.Logger; import org.apache.dubbo.common.logger.LoggerFactory; +import org.apache.dubbo.rpc.AsyncContextImpl; import org.apache.dubbo.rpc.AsyncRpcResult; import org.apache.dubbo.rpc.Invocation; import org.apache.dubbo.rpc.Invoker; @@ -86,7 +87,7 @@ public Result invoke(Invocation invocation) throws RpcException { if (RpcUtils.isReturnTypeFuture(invocation)) { return new AsyncRpcResult((CompletableFuture) obj); } else if (rpcContext.isAsyncStarted()) { // ignore obj in case of RpcContext.startAsync()? always rely on user to write back. - return new AsyncRpcResult(rpcContext.getAsyncContext().getInternalFuture()); + return new AsyncRpcResult(((AsyncContextImpl)(rpcContext.getAsyncContext())).getInternalFuture()); } else { return new RpcResult(obj); } diff --git a/dubbo-rpc/dubbo-rpc-api/src/main/java/org/apache/dubbo/rpc/proxy/jdk/JdkProxyFactory.java b/dubbo-rpc/dubbo-rpc-api/src/main/java/org/apache/dubbo/rpc/proxy/jdk/JdkProxyFactory.java index b74fb702567..dc9bdfc0162 100644 --- a/dubbo-rpc/dubbo-rpc-api/src/main/java/org/apache/dubbo/rpc/proxy/jdk/JdkProxyFactory.java +++ b/dubbo-rpc/dubbo-rpc-api/src/main/java/org/apache/dubbo/rpc/proxy/jdk/JdkProxyFactory.java @@ -26,7 +26,7 @@ import java.lang.reflect.Proxy; /** - * JavaassistRpcProxyFactory + * JdkRpcProxyFactory */ public class JdkProxyFactory extends AbstractProxyFactory { diff --git a/dubbo-rpc/dubbo-rpc-api/src/main/java/org/apache/dubbo/rpc/support/AccessLogData.java b/dubbo-rpc/dubbo-rpc-api/src/main/java/org/apache/dubbo/rpc/support/AccessLogData.java index 852381c94ff..b7d10961470 100644 --- a/dubbo-rpc/dubbo-rpc-api/src/main/java/org/apache/dubbo/rpc/support/AccessLogData.java +++ b/dubbo-rpc/dubbo-rpc-api/src/main/java/org/apache/dubbo/rpc/support/AccessLogData.java @@ -21,20 +21,24 @@ import com.alibaba.fastjson.JSON; +import java.text.DateFormat; +import java.text.SimpleDateFormat; import java.util.Arrays; import java.util.Date; import java.util.HashMap; import java.util.Map; -import static org.apache.dubbo.common.utils.DateUtil.format; - /** - * AccessLogData is a container for log event data. In internally uses map and store each filed of log as value. It does not generate any - * dynamic value e.g. time stamp, local jmv machine host address etc. It does not allow any null or empty key. + * AccessLogData is a container for log event data. In internally uses map and store each filed of log as value. It + * does not generate any dynamic value e.g. time stamp, local jmv machine host address etc. It does not allow any null + * or empty key. + * + * Note: since its date formatter is a singleton, make sure to run it in single thread only. */ public final class AccessLogData { private static final String MESSAGE_DATE_FORMAT = "yyyy-MM-dd HH:mm:ss"; + private static final DateFormat MESSAGE_DATE_FORMATTER = new SimpleDateFormat(MESSAGE_DATE_FORMAT); private static final String VERSION = "version"; private static final String GROUP = "group"; @@ -188,7 +192,7 @@ public String getLogMessage() { StringBuilder sn = new StringBuilder(); sn.append("[") - .append(format(getInvocationTime(), MESSAGE_DATE_FORMAT)) + .append(MESSAGE_DATE_FORMATTER.format(getInvocationTime())) .append("] ") .append(get(REMOTE_HOST)) .append(":") @@ -259,4 +263,4 @@ private void set(String key, Object value) { data.put(key, value); } -} \ No newline at end of file +} diff --git a/dubbo-rpc/dubbo-rpc-api/src/test/java/org/apache/dubbo/rpc/RpcContextTest.java b/dubbo-rpc/dubbo-rpc-api/src/test/java/org/apache/dubbo/rpc/RpcContextTest.java index 5e0cbce4e10..86717ef7011 100644 --- a/dubbo-rpc/dubbo-rpc-api/src/test/java/org/apache/dubbo/rpc/RpcContextTest.java +++ b/dubbo-rpc/dubbo-rpc-api/src/test/java/org/apache/dubbo/rpc/RpcContextTest.java @@ -17,12 +17,12 @@ package org.apache.dubbo.rpc; import org.apache.dubbo.common.URL; + import org.junit.jupiter.api.Assertions; import org.junit.jupiter.api.Test; import java.util.HashMap; import java.util.Map; -import java.util.concurrent.CompletableFuture; public class RpcContextTest { @@ -142,20 +142,14 @@ public void testObject() { @Test public void testAsync() { - CompletableFuture future = new CompletableFuture<>(); - AsyncContext asyncContext = new AsyncContextImpl(future); - RpcContext rpcContext = RpcContext.getContext(); Assertions.assertFalse(rpcContext.isAsyncStarted()); - rpcContext.setAsyncContext(asyncContext); - Assertions.assertFalse(rpcContext.isAsyncStarted()); - - RpcContext.startAsync(); + AsyncContext asyncContext = RpcContext.startAsync(); Assertions.assertTrue(rpcContext.isAsyncStarted()); asyncContext.write(new Object()); - Assertions.assertTrue(future.isDone()); + Assertions.assertTrue(((AsyncContextImpl)asyncContext).getInternalFuture().isDone()); rpcContext.stopAsync(); Assertions.assertTrue(rpcContext.isAsyncStarted()); diff --git a/dubbo-rpc/dubbo-rpc-api/src/test/java/org/apache/dubbo/rpc/filter/GenericFilterTest.java b/dubbo-rpc/dubbo-rpc-api/src/test/java/org/apache/dubbo/rpc/filter/GenericFilterTest.java index e09afe6e776..bd680e7502e 100644 --- a/dubbo-rpc/dubbo-rpc-api/src/test/java/org/apache/dubbo/rpc/filter/GenericFilterTest.java +++ b/dubbo-rpc/dubbo-rpc-api/src/test/java/org/apache/dubbo/rpc/filter/GenericFilterTest.java @@ -49,7 +49,7 @@ public void testInvokeWithDefault() throws Exception { RpcInvocation invocation = new RpcInvocation(Constants.$INVOKE, genericInvoke.getParameterTypes(), new Object[]{"getPerson", new String[]{Person.class.getCanonicalName()}, new Object[]{person}}); - URL url = URL.valueOf("test://test:11/com.alibaba.dubbo.rpc.support.DemoService?" + + URL url = URL.valueOf("test://test:11/org.apache.dubbo.rpc.support.DemoService?" + "accesslog=true&group=dubbo&version=1.1"); Invoker invoker = Mockito.mock(Invoker.class); when(invoker.invoke(any(Invocation.class))).thenReturn(new RpcResult(new Person("person", 10))); @@ -76,7 +76,7 @@ public void testInvokeWithJavaException() throws Exception { new Object[]{"getPerson", new String[]{Person.class.getCanonicalName()}, new Object[]{person}}); invocation.setAttachment(Constants.GENERIC_KEY, Constants.GENERIC_SERIALIZATION_NATIVE_JAVA); - URL url = URL.valueOf("test://test:11/com.alibaba.dubbo.rpc.support.DemoService?" + + URL url = URL.valueOf("test://test:11/org.apache.dubbo.rpc.support.DemoService?" + "accesslog=true&group=dubbo&version=1.1"); Invoker invoker = Mockito.mock(Invoker.class); when(invoker.invoke(any(Invocation.class))).thenReturn(new RpcResult(new Person("person", 10))); @@ -99,7 +99,7 @@ public void testInvokeWithJavaException() throws Exception { RpcInvocation invocation = new RpcInvocation("sayHi", genericInvoke.getParameterTypes() , new Object[]{"getPerson", new String[]{Person.class.getCanonicalName()}, new Object[]{person}}); - URL url = URL.valueOf("test://test:11/com.alibaba.dubbo.rpc.support.DemoService?" + + URL url = URL.valueOf("test://test:11/org.apache.dubbo.rpc.support.DemoService?" + "accesslog=true&group=dubbo&version=1.1"); Invoker invoker = Mockito.mock(Invoker.class); when(invoker.invoke(any(Invocation.class))).thenReturn(new RpcResult(new Person("person", 10))); @@ -123,7 +123,7 @@ public void testInvokeWithMethodArgumentSizeIsNot3() { RpcInvocation invocation = new RpcInvocation(Constants.$INVOKE, genericInvoke.getParameterTypes() , new Object[]{"getPerson", new String[]{Person.class.getCanonicalName()}}); - URL url = URL.valueOf("test://test:11/com.alibaba.dubbo.rpc.support.DemoService?" + + URL url = URL.valueOf("test://test:11/org.apache.dubbo.rpc.support.DemoService?" + "accesslog=true&group=dubbo&version=1.1"); Invoker invoker = Mockito.mock(Invoker.class); when(invoker.invoke(any(Invocation.class))).thenReturn(new RpcResult(new Person("person", 10))); diff --git a/dubbo-rpc/dubbo-rpc-api/src/test/java/org/apache/dubbo/rpc/filter/GenericImplFilterTest.java b/dubbo-rpc/dubbo-rpc-api/src/test/java/org/apache/dubbo/rpc/filter/GenericImplFilterTest.java index fbeb84ef6d0..43930ef6605 100644 --- a/dubbo-rpc/dubbo-rpc-api/src/test/java/org/apache/dubbo/rpc/filter/GenericImplFilterTest.java +++ b/dubbo-rpc/dubbo-rpc-api/src/test/java/org/apache/dubbo/rpc/filter/GenericImplFilterTest.java @@ -50,7 +50,7 @@ public void testInvoke() throws Exception { new Class[]{Person.class}, new Object[]{new Person("dubbo", 10)}); - URL url = URL.valueOf("test://test:11/com.alibaba.dubbo.rpc.support.DemoService?" + + URL url = URL.valueOf("test://test:11/org.apache.dubbo.rpc.support.DemoService?" + "accesslog=true&group=dubbo&version=1.1&generic=true"); Invoker invoker = Mockito.mock(Invoker.class); @@ -74,7 +74,7 @@ public void testInvokeWithException() throws Exception { RpcInvocation invocation = new RpcInvocation("getPerson", new Class[]{Person.class}, new Object[]{new Person("dubbo", 10)}); - URL url = URL.valueOf("test://test:11/com.alibaba.dubbo.rpc.support.DemoService?" + + URL url = URL.valueOf("test://test:11/org.apache.dubbo.rpc.support.DemoService?" + "accesslog=true&group=dubbo&version=1.1&generic=true"); Invoker invoker = Mockito.mock(Invoker.class); @@ -100,7 +100,7 @@ public void testInvokeWithException() throws Exception { RpcInvocation invocation = new RpcInvocation(Constants.$INVOKE, genericInvoke.getParameterTypes(), new Object[]{"getPerson", new String[]{Person.class.getCanonicalName()}, new Object[]{person}}); - URL url = URL.valueOf("test://test:11/com.alibaba.dubbo.rpc.support.DemoService?" + + URL url = URL.valueOf("test://test:11/org.apache.dubbo.rpc.support.DemoService?" + "accesslog=true&group=dubbo&version=1.1&generic=true"); Invoker invoker = Mockito.mock(Invoker.class); when(invoker.invoke(any(Invocation.class))).thenReturn(new RpcResult(new Person("person", 10))); diff --git a/dubbo-rpc/dubbo-rpc-api/src/test/resources/log4j.xml b/dubbo-rpc/dubbo-rpc-api/src/test/resources/log4j.xml index f041044f081..e0eda90175d 100644 --- a/dubbo-rpc/dubbo-rpc-api/src/test/resources/log4j.xml +++ b/dubbo-rpc/dubbo-rpc-api/src/test/resources/log4j.xml @@ -21,6 +21,7 @@ + diff --git a/dubbo-rpc/dubbo-rpc-dubbo/pom.xml b/dubbo-rpc/dubbo-rpc-dubbo/pom.xml index 354930c04e8..290f627b36f 100644 --- a/dubbo-rpc/dubbo-rpc-dubbo/pom.xml +++ b/dubbo-rpc/dubbo-rpc-dubbo/pom.xml @@ -19,7 +19,7 @@ org.apache.dubbo dubbo-rpc - 2.7.0-SNAPSHOT + 2.7.1-SNAPSHOT dubbo-rpc-dubbo jar diff --git a/dubbo-rpc/dubbo-rpc-dubbo/src/main/java/org/apache/dubbo/rpc/protocol/dubbo/DecodeableRpcResult.java b/dubbo-rpc/dubbo-rpc-dubbo/src/main/java/org/apache/dubbo/rpc/protocol/dubbo/DecodeableRpcResult.java index 7c72133e66b..fac7c64a6ca 100644 --- a/dubbo-rpc/dubbo-rpc-dubbo/src/main/java/org/apache/dubbo/rpc/protocol/dubbo/DecodeableRpcResult.java +++ b/dubbo-rpc/dubbo-rpc-dubbo/src/main/java/org/apache/dubbo/rpc/protocol/dubbo/DecodeableRpcResult.java @@ -20,6 +20,7 @@ import org.apache.dubbo.common.logger.LoggerFactory; import org.apache.dubbo.common.serialize.Cleanable; import org.apache.dubbo.common.serialize.ObjectInput; +import org.apache.dubbo.common.utils.ArrayUtils; import org.apache.dubbo.common.utils.Assert; import org.apache.dubbo.common.utils.StringUtils; import org.apache.dubbo.remoting.Channel; @@ -73,61 +74,27 @@ public void encode(Channel channel, OutputStream output, Object message) throws public Object decode(Channel channel, InputStream input) throws IOException { ObjectInput in = CodecSupport.getSerialization(channel.getUrl(), serializationType) .deserialize(channel.getUrl(), input); - + byte flag = in.readByte(); switch (flag) { case DubboCodec.RESPONSE_NULL_VALUE: break; case DubboCodec.RESPONSE_VALUE: - try { - Type[] returnType = RpcUtils.getReturnTypes(invocation); - setValue(returnType == null || returnType.length == 0 ? in.readObject() : - (returnType.length == 1 ? in.readObject((Class) returnType[0]) - : in.readObject((Class) returnType[0], returnType[1]))); - } catch (ClassNotFoundException e) { - throw new IOException(StringUtils.toString("Read response data failed.", e)); - } + handleValue(in); break; case DubboCodec.RESPONSE_WITH_EXCEPTION: - try { - Object obj = in.readObject(); - if (obj instanceof Throwable == false) { - throw new IOException("Response data error, expect Throwable, but get " + obj); - } - setException((Throwable) obj); - } catch (ClassNotFoundException e) { - throw new IOException(StringUtils.toString("Read response data failed.", e)); - } + handleException(in); break; case DubboCodec.RESPONSE_NULL_VALUE_WITH_ATTACHMENTS: - try { - setAttachments((Map) in.readObject(Map.class)); - } catch (ClassNotFoundException e) { - throw new IOException(StringUtils.toString("Read response data failed.", e)); - } + handleAttachment(in); break; case DubboCodec.RESPONSE_VALUE_WITH_ATTACHMENTS: - try { - Type[] returnType = RpcUtils.getReturnTypes(invocation); - setValue(returnType == null || returnType.length == 0 ? in.readObject() : - (returnType.length == 1 ? in.readObject((Class) returnType[0]) - : in.readObject((Class) returnType[0], returnType[1]))); - setAttachments((Map) in.readObject(Map.class)); - } catch (ClassNotFoundException e) { - throw new IOException(StringUtils.toString("Read response data failed.", e)); - } + handleValue(in); + handleAttachment(in); break; case DubboCodec.RESPONSE_WITH_EXCEPTION_WITH_ATTACHMENTS: - try { - Object obj = in.readObject(); - if (obj instanceof Throwable == false) { - throw new IOException("Response data error, expect Throwable, but get " + obj); - } - setException((Throwable) obj); - setAttachments((Map) in.readObject(Map.class)); - } catch (ClassNotFoundException e) { - throw new IOException(StringUtils.toString("Read response data failed.", e)); - } + handleException(in); + handleAttachment(in); break; default: throw new IOException("Unknown result flag, expect '0' '1' '2', get " + flag); @@ -155,4 +122,44 @@ public void decode() throws Exception { } } + private void handleValue(ObjectInput in) throws IOException { + try { + Type[] returnTypes = RpcUtils.getReturnTypes(invocation); + Object value = null; + if (ArrayUtils.isEmpty(returnTypes)) { + value = in.readObject(); + } else if (returnTypes.length == 1) { + value = in.readObject((Class) returnTypes[0]); + } else { + value = in.readObject((Class) returnTypes[0], returnTypes[1]); + } + setValue(value); + } catch (ClassNotFoundException e) { + rethrow(e); + } + } + + private void handleException(ObjectInput in) throws IOException { + try { + Object obj = in.readObject(); + if (!(obj instanceof Throwable)) { + throw new IOException("Response data error, expect Throwable, but get " + obj); + } + setException((Throwable) obj); + } catch (ClassNotFoundException e) { + rethrow(e); + } + } + + private void handleAttachment(ObjectInput in) throws IOException { + try { + setAttachments((Map) in.readObject(Map.class)); + } catch (ClassNotFoundException e) { + rethrow(e); + } + } + + private void rethrow(Exception e) throws IOException { + throw new IOException(StringUtils.toString("Read response data failed.", e)); + } } diff --git a/dubbo-rpc/dubbo-rpc-dubbo/src/main/java/org/apache/dubbo/rpc/protocol/dubbo/DubboProtocol.java b/dubbo-rpc/dubbo-rpc-dubbo/src/main/java/org/apache/dubbo/rpc/protocol/dubbo/DubboProtocol.java index 7a0be74dcc1..e9f42dd56f4 100644 --- a/dubbo-rpc/dubbo-rpc-dubbo/src/main/java/org/apache/dubbo/rpc/protocol/dubbo/DubboProtocol.java +++ b/dubbo-rpc/dubbo-rpc-dubbo/src/main/java/org/apache/dubbo/rpc/protocol/dubbo/DubboProtocol.java @@ -34,7 +34,6 @@ import org.apache.dubbo.remoting.exchange.ExchangeServer; import org.apache.dubbo.remoting.exchange.Exchangers; import org.apache.dubbo.remoting.exchange.support.ExchangeHandlerAdapter; -import org.apache.dubbo.rpc.AsyncContextImpl; import org.apache.dubbo.rpc.AsyncRpcResult; import org.apache.dubbo.rpc.Exporter; import org.apache.dubbo.rpc.Invocation; @@ -66,14 +65,22 @@ public class DubboProtocol extends AbstractProtocol { public static final int DEFAULT_PORT = 20880; private static final String IS_CALLBACK_SERVICE_INVOKE = "_isCallBackServiceInvoke"; private static DubboProtocol INSTANCE; - private final Map serverMap = new ConcurrentHashMap(); // - private final Map referenceClientMap = new ConcurrentHashMap(); // - private final ConcurrentMap ghostClientMap = new ConcurrentHashMap(); - private final ConcurrentMap locks = new ConcurrentHashMap(); - private final Set optimizers = new ConcurrentHashSet(); - //consumer side export a stub service for dispatching event - //servicekey-stubmethods - private final ConcurrentMap stubServiceMethodsMap = new ConcurrentHashMap(); + /** + * + */ + private final Map serverMap = new ConcurrentHashMap<>(); + /** + * + */ + private final Map referenceClientMap = new ConcurrentHashMap<>(); + private final ConcurrentMap ghostClientMap = new ConcurrentHashMap<>(); + private final ConcurrentMap locks = new ConcurrentHashMap<>(); + private final Set optimizers = new ConcurrentHashSet<>(); + /** + * consumer side export a stub service for dispatching event + * servicekey-stubmethods + */ + private final ConcurrentMap stubServiceMethodsMap = new ConcurrentHashMap<>(); private ExchangeHandler requestHandler = new ExchangeHandlerAdapter() { @Override @@ -105,11 +112,6 @@ public CompletableFuture reply(ExchangeChannel channel, Object message) } } RpcContext rpcContext = RpcContext.getContext(); - boolean supportServerAsync = invoker.getUrl().getMethodParameter(inv.getMethodName(), Constants.ASYNC_KEY, false); - if (supportServerAsync) { - CompletableFuture future = new CompletableFuture<>(); - rpcContext.setAsyncContext(new AsyncContextImpl(future)); - } rpcContext.setRemoteAddress(channel.getRemoteAddress()); Result result = invoker.invoke(inv); @@ -180,7 +182,8 @@ public DubboProtocol() { public static DubboProtocol getDubboProtocol() { if (INSTANCE == null) { - ExtensionLoader.getExtensionLoader(Protocol.class).getExtension(DubboProtocol.NAME); // load + // load + ExtensionLoader.getExtensionLoader(Protocol.class).getExtension(DubboProtocol.NAME); } return INSTANCE; } @@ -218,7 +221,7 @@ Invoker getInvoker(Channel channel, Invocation inv) throws RemotingException //callback isCallBackServiceInvoke = isClientSide(channel) && !isStubServiceInvoke; if (isCallBackServiceInvoke) { - path = inv.getAttachments().get(Constants.PATH_KEY) + "." + inv.getAttachments().get(Constants.CALLBACK_SERVICE_KEY); + path += "." + inv.getAttachments().get(Constants.CALLBACK_SERVICE_KEY); inv.getAttachments().put(IS_CALLBACK_SERVICE_INVOKE, Boolean.TRUE.toString()); } String serviceKey = serviceKey(port, path, inv.getAttachments().get(Constants.VERSION_KEY), inv.getAttachments().get(Constants.GROUP_KEY)); @@ -226,7 +229,8 @@ Invoker getInvoker(Channel channel, Invocation inv) throws RemotingException DubboExporter exporter = (DubboExporter) exporterMap.get(serviceKey); if (exporter == null) { - throw new RemotingException(channel, "Not found exported service: " + serviceKey + " in " + exporterMap.keySet() + ", may be version or group mismatch " + ", channel: consumer: " + channel.getRemoteAddress() + " --> provider: " + channel.getLocalAddress() + ", message:" + inv); + throw new RemotingException(channel, "Not found exported service: " + serviceKey + " in " + + exporterMap.keySet() + ", may be version or group mismatch " + ", channel: consumer: " + channel.getRemoteAddress() + " --> provider: " + channel.getLocalAddress() + ", message:" + inv); } return exporter.getInvoker(); @@ -447,7 +451,7 @@ private ExchangeClient initClient(URL url) { @Override public void destroy() { - for (String key : new ArrayList(serverMap.keySet())) { + for (String key : new ArrayList<>(serverMap.keySet())) { ExchangeServer server = serverMap.remove(key); if (server != null) { try { @@ -461,7 +465,7 @@ public void destroy() { } } - for (String key : new ArrayList(referenceClientMap.keySet())) { + for (String key : new ArrayList<>(referenceClientMap.keySet())) { ExchangeClient client = referenceClientMap.remove(key); if (client != null) { try { @@ -475,7 +479,7 @@ public void destroy() { } } - for (String key : new ArrayList(ghostClientMap.keySet())) { + for (String key : new ArrayList<>(ghostClientMap.keySet())) { ExchangeClient client = ghostClientMap.remove(key); if (client != null) { try { diff --git a/dubbo-rpc/dubbo-rpc-dubbo/src/main/java/org/apache/dubbo/rpc/protocol/dubbo/LazyConnectExchangeClient.java b/dubbo-rpc/dubbo-rpc-dubbo/src/main/java/org/apache/dubbo/rpc/protocol/dubbo/LazyConnectExchangeClient.java index b5a4057f54d..eaebb1985f3 100644 --- a/dubbo-rpc/dubbo-rpc-dubbo/src/main/java/org/apache/dubbo/rpc/protocol/dubbo/LazyConnectExchangeClient.java +++ b/dubbo-rpc/dubbo-rpc-dubbo/src/main/java/org/apache/dubbo/rpc/protocol/dubbo/LazyConnectExchangeClient.java @@ -40,14 +40,19 @@ @SuppressWarnings("deprecation") final class LazyConnectExchangeClient implements ExchangeClient { - // when this warning rises from invocation, program probably have bug. - static final String REQUEST_WITH_WARNING_KEY = "lazyclient_request_with_warning"; + /** + * when this warning rises from invocation, program probably have bug. + */ + protected static final String REQUEST_WITH_WARNING_KEY = "lazyclient_request_with_warning"; private final static Logger logger = LoggerFactory.getLogger(LazyConnectExchangeClient.class); protected final boolean requestWithWarning; private final URL url; private final ExchangeHandler requestHandler; private final Lock connectLock = new ReentrantLock(); - // lazy connect, initial state for connection + private final int warning_period = 5000; + /** + * lazy connect, initial state for connection + */ private final boolean initialState; private volatile ExchangeClient client; private AtomicLong warningcount = new AtomicLong(0); @@ -81,7 +86,7 @@ private void initClient() throws RemotingException { @Override public ResponseFuture request(Object request) throws RemotingException { - warning(request); + warning(); initClient(); return client.request(request); } @@ -102,19 +107,17 @@ public InetSocketAddress getRemoteAddress() { @Override public ResponseFuture request(Object request, int timeout) throws RemotingException { - warning(request); + warning(); initClient(); return client.request(request, timeout); } /** * If {@link #REQUEST_WITH_WARNING_KEY} is configured, then warn once every 5000 invocations. - * - * @param request */ - private void warning(Object request) { + private void warning() { if (requestWithWarning) { - if (warningcount.get() % 5000 == 0) { + if (warningcount.get() % warning_period == 0) { logger.warn(new IllegalStateException("safe guard client , should not be called ,must have a bug.")); } warningcount.incrementAndGet(); diff --git a/dubbo-rpc/dubbo-rpc-dubbo/src/main/java/org/apache/dubbo/rpc/protocol/dubbo/filter/TraceFilter.java b/dubbo-rpc/dubbo-rpc-dubbo/src/main/java/org/apache/dubbo/rpc/protocol/dubbo/filter/TraceFilter.java index d8406e861ae..1249c93e2c8 100644 --- a/dubbo-rpc/dubbo-rpc-dubbo/src/main/java/org/apache/dubbo/rpc/protocol/dubbo/filter/TraceFilter.java +++ b/dubbo-rpc/dubbo-rpc-dubbo/src/main/java/org/apache/dubbo/rpc/protocol/dubbo/filter/TraceFilter.java @@ -50,7 +50,7 @@ public class TraceFilter implements Filter { private static final String TRACE_COUNT = "trace.count"; - private static final ConcurrentMap> tracers = new ConcurrentHashMap>(); + private static final ConcurrentMap> tracers = new ConcurrentHashMap<>(); public static void addTracer(Class type, String method, Channel channel, int max) { channel.setAttribute(TRACE_MAX, max); @@ -58,7 +58,7 @@ public static void addTracer(Class type, String method, Channel channel, int String key = method != null && method.length() > 0 ? type.getName() + "." + method : type.getName(); Set channels = tracers.get(key); if (channels == null) { - tracers.putIfAbsent(key, new ConcurrentHashSet()); + tracers.putIfAbsent(key, new ConcurrentHashSet<>()); channels = tracers.get(key); } channels.add(channel); @@ -87,13 +87,13 @@ public Result invoke(Invoker invoker, Invocation invocation) throws RpcExcept channels = tracers.get(key); } if (CollectionUtils.isNotEmpty(channels)) { - for (Channel channel : new ArrayList(channels)) { + for (Channel channel : new ArrayList<>(channels)) { if (channel.isConnected()) { try { int max = 1; Integer m = (Integer) channel.getAttribute(TRACE_MAX); if (m != null) { - max = (int) m; + max = m; } int count = 0; AtomicInteger c = (AtomicInteger) channel.getAttribute(TRACE_COUNT); diff --git a/dubbo-rpc/dubbo-rpc-dubbo/src/main/java/org/apache/dubbo/rpc/protocol/dubbo/telnet/ShutdownTelnetHandler.java b/dubbo-rpc/dubbo-rpc-dubbo/src/main/java/org/apache/dubbo/rpc/protocol/dubbo/telnet/ShutdownTelnetHandler.java new file mode 100644 index 00000000000..ff5bf07cb33 --- /dev/null +++ b/dubbo-rpc/dubbo-rpc-dubbo/src/main/java/org/apache/dubbo/rpc/protocol/dubbo/telnet/ShutdownTelnetHandler.java @@ -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.rpc.protocol.dubbo.telnet; + +import org.apache.dubbo.common.extension.Activate; +import org.apache.dubbo.common.utils.StringUtils; +import org.apache.dubbo.config.DubboShutdownHook; +import org.apache.dubbo.remoting.Channel; +import org.apache.dubbo.remoting.RemotingException; +import org.apache.dubbo.remoting.telnet.TelnetHandler; +import org.apache.dubbo.remoting.telnet.support.Help; + +/** + * ShutdownTelnetHandler + */ +@Activate +@Help(parameter = "[-t ]", summary = "Shutdown Dubbo Application.", detail = "Shutdown Dubbo Application.") +public class ShutdownTelnetHandler implements TelnetHandler { + @Override + public String telnet(Channel channel, String message) throws RemotingException { + + int sleepMilliseconds = 0; + if (StringUtils.isNotEmpty(message)) { + String[] parameters = message.split("\\s+"); + if (parameters.length == 2 && parameters[0].equals("-t") && StringUtils.isInteger(parameters[1])) { + sleepMilliseconds = Integer.parseInt(parameters[1]); + } else { + return "Invalid parameter,please input like shutdown -t 10000"; + } + } + long start = System.currentTimeMillis(); + if (sleepMilliseconds > 0) { + try { + Thread.sleep(sleepMilliseconds); + } catch (InterruptedException e) { + return "Failed to invoke shutdown command, cause: " + e.getMessage(); + } + } + StringBuilder buf = new StringBuilder(); + DubboShutdownHook.getDubboShutdownHook().unregister(); + DubboShutdownHook.getDubboShutdownHook().doDestroy(); + long end = System.currentTimeMillis(); + buf.append("Application has shutdown successfully"); + buf.append("\r\nelapsed: "); + buf.append(end - start); + buf.append(" ms."); + return buf.toString(); + } +} diff --git a/dubbo-rpc/dubbo-rpc-dubbo/src/main/resources/META-INF/dubbo/internal/org.apache.dubbo.remoting.telnet.TelnetHandler b/dubbo-rpc/dubbo-rpc-dubbo/src/main/resources/META-INF/dubbo/internal/org.apache.dubbo.remoting.telnet.TelnetHandler index ef32515fe7a..99111639c26 100644 --- a/dubbo-rpc/dubbo-rpc-dubbo/src/main/resources/META-INF/dubbo/internal/org.apache.dubbo.remoting.telnet.TelnetHandler +++ b/dubbo-rpc/dubbo-rpc-dubbo/src/main/resources/META-INF/dubbo/internal/org.apache.dubbo.remoting.telnet.TelnetHandler @@ -5,4 +5,5 @@ pwd=org.apache.dubbo.rpc.protocol.dubbo.telnet.CurrentTelnetHandler invoke=org.apache.dubbo.rpc.protocol.dubbo.telnet.InvokeTelnetHandler trace=org.apache.dubbo.rpc.protocol.dubbo.telnet.TraceTelnetHandler count=org.apache.dubbo.rpc.protocol.dubbo.telnet.CountTelnetHandler -select=org.apache.dubbo.rpc.protocol.dubbo.telnet.SelectTelnetHandler \ No newline at end of file +select=org.apache.dubbo.rpc.protocol.dubbo.telnet.SelectTelnetHandler +shutdown=org.apache.dubbo.rpc.protocol.dubbo.telnet.ShutdownTelnetHandler \ No newline at end of file diff --git a/dubbo-rpc/dubbo-rpc-dubbo/src/test/java/org/apache/dubbo/rpc/protocol/dubbo/telnet/ShutdownTelnetHandlerTest.java b/dubbo-rpc/dubbo-rpc-dubbo/src/test/java/org/apache/dubbo/rpc/protocol/dubbo/telnet/ShutdownTelnetHandlerTest.java new file mode 100644 index 00000000000..6dbd026300e --- /dev/null +++ b/dubbo-rpc/dubbo-rpc-dubbo/src/test/java/org/apache/dubbo/rpc/protocol/dubbo/telnet/ShutdownTelnetHandlerTest.java @@ -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.protocol.dubbo.telnet; + +import org.apache.dubbo.remoting.Channel; +import org.apache.dubbo.remoting.RemotingException; +import org.apache.dubbo.remoting.telnet.TelnetHandler; +import org.junit.jupiter.api.Test; + +import static org.junit.jupiter.api.Assertions.assertTrue; +import static org.mockito.Mockito.mock; + +/** + * SelectTelnetHandlerTest.java + */ +public class ShutdownTelnetHandlerTest { + + private static TelnetHandler handler = new ShutdownTelnetHandler(); + private Channel mockChannel; + + @SuppressWarnings("unchecked") + @Test + public void testInvoke() throws RemotingException { + mockChannel = mock(Channel.class); + String result = handler.telnet(mockChannel, ""); + assertTrue(result.contains("Application has shutdown successfully")); + } + + + @SuppressWarnings("unchecked") + @Test + public void testInvokeWithTimeParameter() throws RemotingException { + mockChannel = mock(Channel.class); + int sleepTime = 2000; + long start = System.currentTimeMillis(); + String result = handler.telnet(mockChannel, "-t " + sleepTime); + long end = System.currentTimeMillis(); + assertTrue(result.contains("Application has shutdown successfully") && (end - start) > sleepTime); + } + + +} diff --git a/dubbo-rpc/dubbo-rpc-dubbo/src/test/java/org/apache/dubbo/rpc/validation/ValidationTest.java b/dubbo-rpc/dubbo-rpc-dubbo/src/test/java/org/apache/dubbo/rpc/validation/ValidationTest.java index 09f8ac4f1a5..691f925216c 100644 --- a/dubbo-rpc/dubbo-rpc-dubbo/src/test/java/org/apache/dubbo/rpc/validation/ValidationTest.java +++ b/dubbo-rpc/dubbo-rpc-dubbo/src/test/java/org/apache/dubbo/rpc/validation/ValidationTest.java @@ -23,11 +23,14 @@ import org.apache.dubbo.config.ReferenceConfig; import org.apache.dubbo.config.RegistryConfig; import org.apache.dubbo.config.ServiceConfig; +import org.apache.dubbo.config.context.ConfigManager; import org.apache.dubbo.rpc.RpcException; import org.apache.dubbo.rpc.service.GenericException; import org.apache.dubbo.rpc.service.GenericService; +import org.junit.jupiter.api.AfterEach; import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; import javax.validation.ConstraintViolation; @@ -41,20 +44,33 @@ * GenericServiceTest */ public class ValidationTest { + private ApplicationConfig application = new ApplicationConfig("validation-test"); + private RegistryConfig registryNA = new RegistryConfig("N/A"); + private ProtocolConfig protocolDubo29582 = new ProtocolConfig("dubbo", 29582); + + @BeforeEach + public void setUp() { + ConfigManager.getInstance().clear(); + } + + @AfterEach + public void tearDown() { + ConfigManager.getInstance().clear(); + } @Test public void testValidation() { ServiceConfig service = new ServiceConfig(); - service.setApplication(new ApplicationConfig("validation-provider")); - service.setRegistry(new RegistryConfig("N/A")); - service.setProtocol(new ProtocolConfig("dubbo", 29582)); + service.setApplication(application); + service.setRegistry(registryNA); + service.setProtocol(protocolDubo29582); service.setInterface(ValidationService.class.getName()); service.setRef(new ValidationServiceImpl()); service.setValidation(String.valueOf(true)); service.export(); try { ReferenceConfig reference = new ReferenceConfig(); - reference.setApplication(new ApplicationConfig("validation-consumer")); + reference.setApplication(application); reference.setInterface(ValidationService.class); reference.setUrl("dubbo://127.0.0.1:29582?scope=remote&validation=true"); ValidationService validationService = reference.get(); @@ -171,16 +187,16 @@ public void testValidation() { @Test public void testProviderValidation() { ServiceConfig service = new ServiceConfig(); - service.setApplication(new ApplicationConfig("validation-provider")); - service.setRegistry(new RegistryConfig("N/A")); - service.setProtocol(new ProtocolConfig("dubbo", 29582)); + service.setApplication(application); + service.setRegistry(registryNA); + service.setProtocol(protocolDubo29582); service.setInterface(ValidationService.class.getName()); service.setRef(new ValidationServiceImpl()); service.setValidation(String.valueOf(true)); service.export(); try { ReferenceConfig reference = new ReferenceConfig(); - reference.setApplication(new ApplicationConfig("validation-consumer")); + reference.setApplication(application); reference.setInterface(ValidationService.class); reference.setUrl("dubbo://127.0.0.1:29582"); ValidationService validationService = reference.get(); @@ -236,16 +252,16 @@ public void testProviderValidation() { @Test public void testGenericValidation() { ServiceConfig service = new ServiceConfig(); - service.setApplication(new ApplicationConfig("validation-provider")); - service.setRegistry(new RegistryConfig("N/A")); - service.setProtocol(new ProtocolConfig("dubbo", 29582)); + service.setApplication(application); + service.setRegistry(registryNA); + service.setProtocol(protocolDubo29582); service.setInterface(ValidationService.class.getName()); service.setRef(new ValidationServiceImpl()); service.setValidation(String.valueOf(true)); service.export(); try { ReferenceConfig reference = new ReferenceConfig(); - reference.setApplication(new ApplicationConfig("validation-consumer")); + reference.setApplication(application); reference.setInterface(ValidationService.class.getName()); reference.setUrl("dubbo://127.0.0.1:29582?scope=remote&validation=true&timeout=9000000"); reference.setGeneric(true); diff --git a/dubbo-rpc/dubbo-rpc-dubbo/src/test/resources/log4j.xml b/dubbo-rpc/dubbo-rpc-dubbo/src/test/resources/log4j.xml index 3c5d2ba218e..09dba05e6cc 100644 --- a/dubbo-rpc/dubbo-rpc-dubbo/src/test/resources/log4j.xml +++ b/dubbo-rpc/dubbo-rpc-dubbo/src/test/resources/log4j.xml @@ -21,6 +21,7 @@ + @@ -30,17 +31,8 @@ --> - - - - - - - - - \ No newline at end of file + diff --git a/dubbo-rpc/dubbo-rpc-hessian/pom.xml b/dubbo-rpc/dubbo-rpc-hessian/pom.xml index 2224a2ad374..0eed79d254a 100644 --- a/dubbo-rpc/dubbo-rpc-hessian/pom.xml +++ b/dubbo-rpc/dubbo-rpc-hessian/pom.xml @@ -19,7 +19,7 @@ org.apache.dubbo dubbo-rpc - 2.7.0-SNAPSHOT + 2.7.1-SNAPSHOT dubbo-rpc-hessian jar @@ -56,7 +56,6 @@ org.springframework spring-test - 5.1.3.RELEASE test diff --git a/dubbo-rpc/dubbo-rpc-http/pom.xml b/dubbo-rpc/dubbo-rpc-http/pom.xml index f98d062d373..5ab4d25d156 100644 --- a/dubbo-rpc/dubbo-rpc-http/pom.xml +++ b/dubbo-rpc/dubbo-rpc-http/pom.xml @@ -1,57 +1,57 @@ - - - 4.0.0 - - org.apache.dubbo - dubbo-rpc - 2.7.0-SNAPSHOT - - dubbo-rpc-http - jar - ${project.artifactId} - The http rpc module of dubbo project - - false - - - - org.apache.dubbo - dubbo-rpc-api - ${project.parent.version} - - - org.apache.dubbo - dubbo-remoting-http - ${project.parent.version} - - - org.springframework - spring-context - - - org.springframework - spring-web - - - org.apache.dubbo - dubbo-serialization-jdk - ${project.parent.version} - test - - + + + 4.0.0 + + org.apache.dubbo + dubbo-rpc + 2.7.1-SNAPSHOT + + dubbo-rpc-http + jar + ${project.artifactId} + The http rpc module of dubbo project + + false + + + + org.apache.dubbo + dubbo-rpc-api + ${project.parent.version} + + + org.apache.dubbo + dubbo-remoting-http + ${project.parent.version} + + + org.springframework + spring-context + + + org.springframework + spring-web + + + org.apache.dubbo + dubbo-serialization-jdk + ${project.parent.version} + test + + \ No newline at end of file diff --git a/dubbo-cluster/src/main/java/org/apache/dubbo/rpc/cluster/router/condition/config/model/BlackWhiteListRule.java b/dubbo-rpc/dubbo-rpc-http/src/main/java/com/alibaba/dubbo/rpc/protocol/http/HttpRemoteInvocation.java similarity index 65% rename from dubbo-cluster/src/main/java/org/apache/dubbo/rpc/cluster/router/condition/config/model/BlackWhiteListRule.java rename to dubbo-rpc/dubbo-rpc-http/src/main/java/com/alibaba/dubbo/rpc/protocol/http/HttpRemoteInvocation.java index d656aa74556..3e923b67a0b 100644 --- a/dubbo-cluster/src/main/java/org/apache/dubbo/rpc/cluster/router/condition/config/model/BlackWhiteListRule.java +++ b/dubbo-rpc/dubbo-rpc-http/src/main/java/com/alibaba/dubbo/rpc/protocol/http/HttpRemoteInvocation.java @@ -14,23 +14,15 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.apache.dubbo.rpc.cluster.router.condition.config.model; +package com.alibaba.dubbo.rpc.protocol.http; -import org.apache.dubbo.rpc.cluster.router.AbstractRouterRule; +import org.aopalliance.intercept.MethodInvocation; -import java.util.List; +@Deprecated +public class HttpRemoteInvocation extends org.apache.dubbo.rpc.protocol.http.HttpRemoteInvocation { + private static final long serialVersionUID = 1L; -/** - * - */ -public class BlackWhiteListRule extends AbstractRouterRule { - private List conditions; - - public List getConditions() { - return conditions; - } - - public void setConditions(List conditions) { - this.conditions = conditions; + public HttpRemoteInvocation(MethodInvocation methodInvocation) { + super(methodInvocation); } } diff --git a/dubbo-rpc/dubbo-rpc-http/src/main/java/org/apache/dubbo/rpc/protocol/http/HttpProtocol.java b/dubbo-rpc/dubbo-rpc-http/src/main/java/org/apache/dubbo/rpc/protocol/http/HttpProtocol.java index 2d837ba5edf..0188a0fe329 100644 --- a/dubbo-rpc/dubbo-rpc-http/src/main/java/org/apache/dubbo/rpc/protocol/http/HttpProtocol.java +++ b/dubbo-rpc/dubbo-rpc-http/src/main/java/org/apache/dubbo/rpc/protocol/http/HttpProtocol.java @@ -19,6 +19,7 @@ import org.apache.dubbo.common.Constants; import org.apache.dubbo.common.URL; import org.apache.dubbo.common.utils.StringUtils; +import org.apache.dubbo.common.Version; import org.apache.dubbo.remoting.http.HttpBinder; import org.apache.dubbo.remoting.http.HttpHandler; import org.apache.dubbo.remoting.http.HttpServer; @@ -117,7 +118,27 @@ protected T doRefer(final Class serviceType, final URL url) throws RpcExc httpProxyFactoryBean.setRemoteInvocationFactory(new RemoteInvocationFactory() { @Override public RemoteInvocation createRemoteInvocation(MethodInvocation methodInvocation) { - RemoteInvocation invocation = new HttpRemoteInvocation(methodInvocation); + RemoteInvocation invocation; + /* + package was renamed to 'org.apache.dubbo' in v2.7.0, so only provider versions after v2.7.0 can + recognize org.apache.xxx.HttpRemoteInvocation'. + */ + if (Version.isRelease270OrHigher(url.getParameter(Constants.RELEASE_KEY))) { + invocation = new HttpRemoteInvocation(methodInvocation); + } else { + /* + The customized 'com.alibaba.dubbo.rpc.protocol.http.HttpRemoteInvocation' was firstly introduced + in v2.6.3. The main purpose is to support transformation of attachments in HttpProtocol, see + https://github.com/apache/incubator-dubbo/pull/1827. To guarantee interoperability with lower + versions, we need to check if the provider is v2.6.3 or higher before sending customized + HttpRemoteInvocation. + */ + if (Version.isRelease263OrHigher(url.getParameter(Constants.DUBBO_VERSION_KEY))) { + invocation = new com.alibaba.dubbo.rpc.protocol.http.HttpRemoteInvocation(methodInvocation); + } else { + invocation = new RemoteInvocation(methodInvocation); + } + } if (isGeneric) { invocation.addAttribute(Constants.GENERIC_KEY, generic); } diff --git a/dubbo-rpc/dubbo-rpc-http/src/test/java/org/apache/dubbo/rpc/protocol/http/HttpProtocolTest.java b/dubbo-rpc/dubbo-rpc-http/src/test/java/org/apache/dubbo/rpc/protocol/http/HttpProtocolTest.java index a3f61ba8b73..009f01d1924 100644 --- a/dubbo-rpc/dubbo-rpc-http/src/test/java/org/apache/dubbo/rpc/protocol/http/HttpProtocolTest.java +++ b/dubbo-rpc/dubbo-rpc-http/src/test/java/org/apache/dubbo/rpc/protocol/http/HttpProtocolTest.java @@ -51,7 +51,7 @@ public void testHttpProtocol() { Assertions.assertFalse(server.isCalled()); ProxyFactory proxyFactory = ExtensionLoader.getExtensionLoader(ProxyFactory.class).getAdaptiveExtension(); Protocol protocol = ExtensionLoader.getExtensionLoader(Protocol.class).getAdaptiveExtension(); - URL url = URL.valueOf("http://127.0.0.1:5342/" + HttpService.class.getName() + "?version=1.0.0"); + URL url = URL.valueOf("http://127.0.0.1:5342/" + HttpService.class.getName() + "?release=2.7.0"); Exporter exporter = protocol.export(proxyFactory.getInvoker(server, HttpService.class, url)); Invoker invoker = protocol.refer(HttpService.class, url); HttpService client = proxyFactory.getProxy(invoker); @@ -68,7 +68,7 @@ public void testGenericInvoke() { Assertions.assertFalse(server.isCalled()); ProxyFactory proxyFactory = ExtensionLoader.getExtensionLoader(ProxyFactory.class).getAdaptiveExtension(); Protocol protocol = ExtensionLoader.getExtensionLoader(Protocol.class).getAdaptiveExtension(); - URL url = URL.valueOf("http://127.0.0.1:5342/" + HttpService.class.getName() + "?version=1.0.0"); + URL url = URL.valueOf("http://127.0.0.1:5342/" + HttpService.class.getName() + "?release=2.7.0"); Exporter exporter = protocol.export(proxyFactory.getInvoker(server, HttpService.class, url)); Invoker invoker = protocol.refer(GenericService.class, url); GenericService client = proxyFactory.getProxy(invoker, true); @@ -85,7 +85,7 @@ public void testGenericInvokeWithNativeJava() throws IOException, ClassNotFoundE Assertions.assertFalse(server.isCalled()); ProxyFactory proxyFactory = ExtensionLoader.getExtensionLoader(ProxyFactory.class).getAdaptiveExtension(); Protocol protocol = ExtensionLoader.getExtensionLoader(Protocol.class).getAdaptiveExtension(); - URL url = URL.valueOf("http://127.0.0.1:5342/" + HttpService.class.getName() + "?version=1.0.0&generic=nativejava"); + URL url = URL.valueOf("http://127.0.0.1:5342/" + HttpService.class.getName() + "?release=2.7.0&generic=nativejava"); Exporter exporter = protocol.export(proxyFactory.getInvoker(server, HttpService.class, url)); Invoker invoker = protocol.refer(GenericService.class, url); GenericService client = proxyFactory.getProxy(invoker); @@ -112,7 +112,7 @@ public void testGenericInvokeWithBean() { Assertions.assertFalse(server.isCalled()); ProxyFactory proxyFactory = ExtensionLoader.getExtensionLoader(ProxyFactory.class).getAdaptiveExtension(); Protocol protocol = ExtensionLoader.getExtensionLoader(Protocol.class).getAdaptiveExtension(); - URL url = URL.valueOf("http://127.0.0.1:5342/" + HttpService.class.getName() + "?version=1.0.0&generic=bean"); + URL url = URL.valueOf("http://127.0.0.1:5342/" + HttpService.class.getName() + "?release=2.7.0&generic=bean"); Exporter exporter = protocol.export(proxyFactory.getInvoker(server, HttpService.class, url)); Invoker invoker = protocol.refer(GenericService.class, url); GenericService client = proxyFactory.getProxy(invoker); @@ -132,7 +132,7 @@ public void testOverload() { Assertions.assertFalse(server.isCalled()); ProxyFactory proxyFactory = ExtensionLoader.getExtensionLoader(ProxyFactory.class).getAdaptiveExtension(); Protocol protocol = ExtensionLoader.getExtensionLoader(Protocol.class).getAdaptiveExtension(); - URL url = URL.valueOf("http://127.0.0.1:5342/" + HttpService.class.getName() + "?version=1.0.0&hessian.overload.method=true&hessian2.request=false"); + URL url = URL.valueOf("http://127.0.0.1:5342/" + HttpService.class.getName() + "?release=2.7.0&hessian.overload.method=true&hessian2.request=false"); Exporter exporter = protocol.export(proxyFactory.getInvoker(server, HttpService.class, url)); Invoker invoker = protocol.refer(HttpService.class, url); HttpService client = proxyFactory.getProxy(invoker); @@ -150,7 +150,7 @@ public void testSimpleClient() { Assertions.assertFalse(server.isCalled()); ProxyFactory proxyFactory = ExtensionLoader.getExtensionLoader(ProxyFactory.class).getAdaptiveExtension(); Protocol protocol = ExtensionLoader.getExtensionLoader(Protocol.class).getAdaptiveExtension(); - URL url = URL.valueOf("http://127.0.0.1:5342/" + HttpService.class.getName() + "?version=1.0.0&client=simple"); + URL url = URL.valueOf("http://127.0.0.1:5342/" + HttpService.class.getName() + "?release=2.7.0&client=simple"); Exporter exporter = protocol.export(proxyFactory.getInvoker(server, HttpService.class, url)); Invoker invoker = protocol.refer(HttpService.class, url); HttpService client = proxyFactory.getProxy(invoker); @@ -166,7 +166,7 @@ public void testTimeOut() { HttpServiceImpl server = new HttpServiceImpl(); ProxyFactory proxyFactory = ExtensionLoader.getExtensionLoader(ProxyFactory.class).getAdaptiveExtension(); Protocol protocol = ExtensionLoader.getExtensionLoader(Protocol.class).getAdaptiveExtension(); - URL url = URL.valueOf("http://127.0.0.1:5342/" + HttpService.class.getName() + "?version=1.0.0&timeout=10"); + URL url = URL.valueOf("http://127.0.0.1:5342/" + HttpService.class.getName() + "?release=2.7.0&timeout=10"); Exporter exporter = protocol.export(proxyFactory.getInvoker(server, HttpService.class, url)); Invoker invoker = protocol.refer(HttpService.class, url); HttpService client = proxyFactory.getProxy(invoker); @@ -187,7 +187,7 @@ public void testCustomException() { HttpServiceImpl server = new HttpServiceImpl(); ProxyFactory proxyFactory = ExtensionLoader.getExtensionLoader(ProxyFactory.class).getAdaptiveExtension(); Protocol protocol = ExtensionLoader.getExtensionLoader(Protocol.class).getAdaptiveExtension(); - URL url = URL.valueOf("http://127.0.0.1:5342/" + HttpService.class.getName() + "?version=1.0.0"); + URL url = URL.valueOf("http://127.0.0.1:5342/" + HttpService.class.getName() + "?release=2.7.0"); Exporter exporter = protocol.export(proxyFactory.getInvoker(server, HttpService.class, url)); Invoker invoker = protocol.refer(HttpService.class, url); HttpService client = proxyFactory.getProxy(invoker); diff --git a/dubbo-rpc/dubbo-rpc-injvm/pom.xml b/dubbo-rpc/dubbo-rpc-injvm/pom.xml index 15fb6bc04dc..9a3de8e080e 100644 --- a/dubbo-rpc/dubbo-rpc-injvm/pom.xml +++ b/dubbo-rpc/dubbo-rpc-injvm/pom.xml @@ -19,7 +19,7 @@ org.apache.dubbo dubbo-rpc - 2.7.0-SNAPSHOT + 2.7.1-SNAPSHOT dubbo-rpc-injvm jar diff --git a/dubbo-rpc/dubbo-rpc-injvm/src/main/java/org/apache/dubbo/rpc/protocol/injvm/InjvmProtocol.java b/dubbo-rpc/dubbo-rpc-injvm/src/main/java/org/apache/dubbo/rpc/protocol/injvm/InjvmProtocol.java index e6959d4bd1c..1181e899d71 100644 --- a/dubbo-rpc/dubbo-rpc-injvm/src/main/java/org/apache/dubbo/rpc/protocol/injvm/InjvmProtocol.java +++ b/dubbo-rpc/dubbo-rpc-injvm/src/main/java/org/apache/dubbo/rpc/protocol/injvm/InjvmProtocol.java @@ -93,27 +93,23 @@ public Invoker refer(Class serviceType, URL url) throws RpcException { } public boolean isInjvmRefer(URL url) { - final boolean isJvmRefer; String scope = url.getParameter(Constants.SCOPE_KEY); // Since injvm protocol is configured explicitly, we don't need to set any extra flag, use normal refer process. - if (Constants.LOCAL_PROTOCOL.toString().equals(url.getProtocol())) { - isJvmRefer = false; - } else if (Constants.SCOPE_LOCAL.equals(scope) || (url.getParameter(Constants.LOCAL_PROTOCOL, false))) { + if (Constants.SCOPE_LOCAL.equals(scope) || (url.getParameter(Constants.LOCAL_PROTOCOL, false))) { // if it's declared as local reference // 'scope=local' is equivalent to 'injvm=true', injvm will be deprecated in the future release - isJvmRefer = true; + return true; } else if (Constants.SCOPE_REMOTE.equals(scope)) { // it's declared as remote reference - isJvmRefer = false; + return false; } else if (url.getParameter(Constants.GENERIC_KEY, false)) { // generic invocation is not local reference - isJvmRefer = false; + return false; } else if (getExporter(exporterMap, url) != null) { // by default, go through local reference if there's the service exposed locally - isJvmRefer = true; + return true; } else { - isJvmRefer = false; + return false; } - return isJvmRefer; } } diff --git a/dubbo-rpc/dubbo-rpc-memcached/pom.xml b/dubbo-rpc/dubbo-rpc-memcached/pom.xml index 97573635f6b..6544e9c9a18 100644 --- a/dubbo-rpc/dubbo-rpc-memcached/pom.xml +++ b/dubbo-rpc/dubbo-rpc-memcached/pom.xml @@ -19,7 +19,7 @@ org.apache.dubbo dubbo-rpc - 2.7.0-SNAPSHOT + 2.7.1-SNAPSHOT dubbo-rpc-memcached jar diff --git a/dubbo-rpc/dubbo-rpc-redis/pom.xml b/dubbo-rpc/dubbo-rpc-redis/pom.xml index df5be049862..056b9013979 100644 --- a/dubbo-rpc/dubbo-rpc-redis/pom.xml +++ b/dubbo-rpc/dubbo-rpc-redis/pom.xml @@ -1,53 +1,53 @@ - - - 4.0.0 - - org.apache.dubbo - dubbo-rpc - 2.7.0-SNAPSHOT - - dubbo-rpc-redis - jar - ${project.artifactId} - The redis rpc module of dubbo project - - false - - - - org.apache.dubbo - dubbo-rpc-api - ${project.parent.version} - - - redis.clients - jedis - - - com.github.kstyrc - embedded-redis - test - - - org.apache.dubbo - dubbo-serialization-jdk - ${project.parent.version} - test - - + + + 4.0.0 + + org.apache.dubbo + dubbo-rpc + 2.7.1-SNAPSHOT + + dubbo-rpc-redis + jar + ${project.artifactId} + The redis rpc module of dubbo project + + false + + + + org.apache.dubbo + dubbo-rpc-api + ${project.parent.version} + + + redis.clients + jedis + + + com.github.kstyrc + embedded-redis + test + + + org.apache.dubbo + dubbo-serialization-jdk + ${project.parent.version} + test + + \ No newline at end of file diff --git a/dubbo-rpc/dubbo-rpc-redis/src/test/java/org/apache/dubbo/rpc/protocol/redis/RedisProtocolTest.java b/dubbo-rpc/dubbo-rpc-redis/src/test/java/org/apache/dubbo/rpc/protocol/redis/RedisProtocolTest.java index 720f4f657b3..9abada0a49e 100644 --- a/dubbo-rpc/dubbo-rpc-redis/src/test/java/org/apache/dubbo/rpc/protocol/redis/RedisProtocolTest.java +++ b/dubbo-rpc/dubbo-rpc-redis/src/test/java/org/apache/dubbo/rpc/protocol/redis/RedisProtocolTest.java @@ -55,7 +55,8 @@ public class RedisProtocolTest { @BeforeEach public void setUp(TestInfo testInfo) { int redisPort = NetUtils.getAvailablePort(); - if (testInfo.getTestMethod().equals("testAuthRedis") || testInfo.getTestMethod().equals("testWrongAuthRedis")) { + String methodName = testInfo.getTestMethod().get().getName(); + if ("testAuthRedis".equals(methodName) || ("testWrongAuthRedis".equals(methodName))) { String password = "123456"; this.redisServer = RedisServer.builder().port(redisPort).setting("requirepass " + password).build(); this.registryUrl = URL.valueOf("redis://username:" + password + "@localhost:" + redisPort + "?db.index=0"); @@ -135,7 +136,7 @@ public void testWrongRedis() { public void testExport() { Assertions.assertThrows(UnsupportedOperationException.class, () -> protocol.export(protocol.refer(IDemoService.class, registryUrl))); } - @Disabled + @Test public void testAuthRedis() { // default db.index=0 @@ -174,9 +175,7 @@ public void testAuthRedis() { // jedis gets the result comparison JedisPool pool = new JedisPool(new GenericObjectPoolConfig(), "localhost", registryUrl.getPort(), 2000, password, database, (String) null); - Jedis jedis = null; - try { - jedis = pool.getResource(); + try (Jedis jedis = pool.getResource()) { byte[] valueByte = jedis.get("key".getBytes()); Serialization serialization = ExtensionLoader.getExtensionLoader(Serialization.class).getExtension(this.registryUrl.getParameter(Constants.SERIALIZATION_KEY, "java")); ObjectInput oin = serialization.deserialize(this.registryUrl, new ByteArrayInputStream(valueByte)); @@ -185,9 +184,6 @@ public void testAuthRedis() { } catch (Exception e) { Assertions.fail("jedis gets the result comparison is error!"); } finally { - if (jedis != null) { - jedis.close(); - } pool.destroy(); } @@ -197,8 +193,8 @@ public void testAuthRedis() { refer.destroy(); } - @Disabled - //@Test + + @Test public void testWrongAuthRedis() { String password = "1234567"; this.registryUrl = this.registryUrl.setPassword(password); diff --git a/dubbo-rpc/dubbo-rpc-rest/pom.xml b/dubbo-rpc/dubbo-rpc-rest/pom.xml index 2ccefbcbb1f..126b26d3a0d 100644 --- a/dubbo-rpc/dubbo-rpc-rest/pom.xml +++ b/dubbo-rpc/dubbo-rpc-rest/pom.xml @@ -1,24 +1,25 @@ 4.0.0 org.apache.dubbo dubbo-rpc - 2.7.0-SNAPSHOT + 2.7.1-SNAPSHOT dubbo-rpc-rest jar diff --git a/dubbo-rpc/dubbo-rpc-rest/src/main/java/org/apache/dubbo/rpc/protocol/rest/RestProtocol.java b/dubbo-rpc/dubbo-rpc-rest/src/main/java/org/apache/dubbo/rpc/protocol/rest/RestProtocol.java index 6c24ca575ec..7f8bc79f401 100644 --- a/dubbo-rpc/dubbo-rpc-rest/src/main/java/org/apache/dubbo/rpc/protocol/rest/RestProtocol.java +++ b/dubbo-rpc/dubbo-rpc-rest/src/main/java/org/apache/dubbo/rpc/protocol/rest/RestProtocol.java @@ -90,7 +90,7 @@ public int getDefaultPort() { @Override protected Runnable doExport(T impl, Class type, URL url) throws RpcException { String addr = getAddr(url); - Class implClass = ApplicationModel.getProviderModel(url.getServiceKey()).getServiceInterfaceClass(); + Class implClass = ApplicationModel.getProviderModel(url.getServiceKey()).getServiceInstance().getClass(); RestServer server = servers.get(addr); if (server == null) { server = serverFactory.createServer(url.getParameter(Constants.SERVER_KEY, DEFAULT_SERVER)); diff --git a/dubbo-rpc/dubbo-rpc-rmi/pom.xml b/dubbo-rpc/dubbo-rpc-rmi/pom.xml index 60dd87bf4d7..bb5efb4ed33 100644 --- a/dubbo-rpc/dubbo-rpc-rmi/pom.xml +++ b/dubbo-rpc/dubbo-rpc-rmi/pom.xml @@ -19,7 +19,7 @@ org.apache.dubbo dubbo-rpc - 2.7.0-SNAPSHOT + 2.7.1-SNAPSHOT dubbo-rpc-rmi jar diff --git a/dubbo-rpc/dubbo-rpc-rmi/src/main/java/com/alibaba/dubbo/rpc/protocol/rmi/RmiRemoteInvocation.java b/dubbo-rpc/dubbo-rpc-rmi/src/main/java/com/alibaba/dubbo/rpc/protocol/rmi/RmiRemoteInvocation.java new file mode 100644 index 00000000000..04efd9ea52c --- /dev/null +++ b/dubbo-rpc/dubbo-rpc-rmi/src/main/java/com/alibaba/dubbo/rpc/protocol/rmi/RmiRemoteInvocation.java @@ -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 com.alibaba.dubbo.rpc.protocol.rmi; + +import org.aopalliance.intercept.MethodInvocation; + +/** + * + */ +@Deprecated +public class RmiRemoteInvocation extends org.apache.dubbo.rpc.protocol.rmi.RmiRemoteInvocation { + private static final long serialVersionUID = 1L; + /** + * executed on consumer side + * + * @param methodInvocation + */ + public RmiRemoteInvocation(MethodInvocation methodInvocation) { + super(methodInvocation); + } +} diff --git a/dubbo-rpc/dubbo-rpc-rmi/src/main/java/org/apache/dubbo/rpc/protocol/rmi/RmiProtocol.java b/dubbo-rpc/dubbo-rpc-rmi/src/main/java/org/apache/dubbo/rpc/protocol/rmi/RmiProtocol.java index 8a28cc02c9a..d3ba2e8fde0 100644 --- a/dubbo-rpc/dubbo-rpc-rmi/src/main/java/org/apache/dubbo/rpc/protocol/rmi/RmiProtocol.java +++ b/dubbo-rpc/dubbo-rpc-rmi/src/main/java/org/apache/dubbo/rpc/protocol/rmi/RmiProtocol.java @@ -18,7 +18,6 @@ import org.apache.dubbo.common.Constants; import org.apache.dubbo.common.URL; -import org.apache.dubbo.common.Version; import org.apache.dubbo.rpc.RpcException; import org.apache.dubbo.rpc.protocol.AbstractProxyProtocol; @@ -30,6 +29,9 @@ import java.net.SocketTimeoutException; import java.rmi.RemoteException; +import static org.apache.dubbo.common.Version.isRelease263OrHigher; +import static org.apache.dubbo.common.Version.isRelease270OrHigher; + /** * RmiProtocol. */ @@ -74,10 +76,19 @@ public void run() { @SuppressWarnings("unchecked") protected T doRefer(final Class serviceType, final URL url) throws RpcException { final RmiProxyFactoryBean rmiProxyFactoryBean = new RmiProxyFactoryBean(); - // RMI needs extra parameter since it uses customized remote invocation object - if (url.getParameter(Constants.DUBBO_VERSION_KEY, Version.getProtocolVersion()).equals(Version.getProtocolVersion())) { - // Check dubbo version on provider, this feature only support + /* + RMI needs extra parameter since it uses customized remote invocation object + + The customized RemoteInvocation was firstly introduced in v2.6.3; The package was renamed to 'org.apache.*' since v2.7.0 + Considering the above two conditions, we need to check before sending customized RemoteInvocation: + 1. if the provider version is v2.7.0 or higher, send 'org.apache.dubbo.rpc.protocol.rmi.RmiRemoteInvocation'. + 2. if the provider version is v2.6.3 or higher, send 'com.alibaba.dubbo.rpc.protocol.rmi.RmiRemoteInvocation'. + 3. if the provider version is lower than v2.6.3, does not use customized RemoteInvocation. + */ + if (isRelease270OrHigher(url.getParameter(Constants.RELEASE_KEY))) { rmiProxyFactoryBean.setRemoteInvocationFactory(RmiRemoteInvocation::new); + } else if (isRelease263OrHigher(url.getParameter(Constants.DUBBO_VERSION_KEY))) { + rmiProxyFactoryBean.setRemoteInvocationFactory(com.alibaba.dubbo.rpc.protocol.rmi.RmiRemoteInvocation::new); } rmiProxyFactoryBean.setServiceUrl(url.toIdentityString()); rmiProxyFactoryBean.setServiceInterface(serviceType); diff --git a/dubbo-rpc/dubbo-rpc-thrift/pom.xml b/dubbo-rpc/dubbo-rpc-thrift/pom.xml index 78e619b641d..5e106b2ba3c 100644 --- a/dubbo-rpc/dubbo-rpc-thrift/pom.xml +++ b/dubbo-rpc/dubbo-rpc-thrift/pom.xml @@ -19,7 +19,7 @@ org.apache.dubbo dubbo-rpc - 2.7.0-SNAPSHOT + 2.7.1-SNAPSHOT dubbo-rpc-thrift jar diff --git a/dubbo-rpc/dubbo-rpc-thrift/src/main/java/org/apache/dubbo/rpc/protocol/thrift/ThriftCodec.java b/dubbo-rpc/dubbo-rpc-thrift/src/main/java/org/apache/dubbo/rpc/protocol/thrift/ThriftCodec.java index d171ce12435..58058f4f64f 100644 --- a/dubbo-rpc/dubbo-rpc-thrift/src/main/java/org/apache/dubbo/rpc/protocol/thrift/ThriftCodec.java +++ b/dubbo-rpc/dubbo-rpc-thrift/src/main/java/org/apache/dubbo/rpc/protocol/thrift/ThriftCodec.java @@ -163,6 +163,7 @@ private Object decode(TProtocol protocol) // version String serviceName; + String path; long id; TMessage message; @@ -171,6 +172,7 @@ private Object decode(TProtocol protocol) protocol.readI16(); protocol.readByte(); serviceName = protocol.readString(); + path = protocol.readString(); id = protocol.readI64(); message = protocol.readMessageBegin(); } catch (TException e) { @@ -181,6 +183,7 @@ private Object decode(TProtocol protocol) RpcInvocation result = new RpcInvocation(); result.setAttachment(Constants.INTERFACE_KEY, serviceName); + result.setAttachment(Constants.PATH_KEY, path); result.setMethodName(message.name); String argsClassName = ExtensionLoader.getExtensionLoader(ClassNameGenerator.class) @@ -496,6 +499,8 @@ private void encodeRequest(Channel channel, ChannelBuffer buffer, Request reques protocol.writeByte(VERSION); // service name protocol.writeString(serviceName); + // path + protocol.writeString(inv.getAttachment(Constants.PATH_KEY)); // dubbo request id protocol.writeI64(request.getId()); protocol.getTransport().flush(); diff --git a/dubbo-rpc/dubbo-rpc-thrift/src/main/java/org/apache/dubbo/rpc/protocol/thrift/ThriftProtocol.java b/dubbo-rpc/dubbo-rpc-thrift/src/main/java/org/apache/dubbo/rpc/protocol/thrift/ThriftProtocol.java index 958d8e63234..055af6f8bb3 100644 --- a/dubbo-rpc/dubbo-rpc-thrift/src/main/java/org/apache/dubbo/rpc/protocol/thrift/ThriftProtocol.java +++ b/dubbo-rpc/dubbo-rpc-thrift/src/main/java/org/apache/dubbo/rpc/protocol/thrift/ThriftProtocol.java @@ -63,9 +63,9 @@ public CompletableFuture reply(ExchangeChannel channel, Object msg) thro if (msg instanceof Invocation) { Invocation inv = (Invocation) msg; - String serviceName = inv.getAttachments().get(Constants.INTERFACE_KEY); + String path = inv.getAttachments().get(Constants.PATH_KEY); String serviceKey = serviceKey(channel.getLocalAddress().getPort(), - serviceName, null, null); + path, null, null); DubboExporter exporter = (DubboExporter) exporterMap.get(serviceKey); if (exporter == null) { throw new RemotingException(channel, diff --git a/dubbo-rpc/dubbo-rpc-thrift/src/test/java/org/apache/dubbo/rpc/protocol/thrift/ThriftCodecTest.java b/dubbo-rpc/dubbo-rpc-thrift/src/test/java/org/apache/dubbo/rpc/protocol/thrift/ThriftCodecTest.java index c738a46a32a..c2277f7fba5 100644 --- a/dubbo-rpc/dubbo-rpc-thrift/src/test/java/org/apache/dubbo/rpc/protocol/thrift/ThriftCodecTest.java +++ b/dubbo-rpc/dubbo-rpc-thrift/src/test/java/org/apache/dubbo/rpc/protocol/thrift/ThriftCodecTest.java @@ -93,6 +93,8 @@ public void testEncodeRequest() throws Exception { Assertions.assertEquals(ThriftCodec.VERSION, protocol.readByte()); // service name Assertions.assertEquals(Demo.Iface.class.getName(), protocol.readString()); + // path + Assertions.assertEquals(Demo.Iface.class.getName(), protocol.readString()); // dubbo request id Assertions.assertEquals(request.getId(), protocol.readI64()); @@ -148,6 +150,8 @@ public void testDecodeReplyResponse() throws Exception { protocol.writeI16(Short.MAX_VALUE); protocol.writeByte(ThriftCodec.VERSION); protocol.writeString(Demo.Iface.class.getName()); + // path + protocol.writeString(Demo.Iface.class.getName()); protocol.writeI64(request.getId()); protocol.getTransport().flush(); headerLength = bos.size(); @@ -221,6 +225,8 @@ public void testDecodeExceptionResponse() throws Exception { protocol.writeI16(Short.MAX_VALUE); protocol.writeByte(ThriftCodec.VERSION); protocol.writeString(Demo.class.getName()); + // path + protocol.writeString(Demo.class.getName()); protocol.writeI64(request.getId()); protocol.getTransport().flush(); headerLength = bos.size(); @@ -396,6 +402,9 @@ public void testDecodeRequest() throws Exception { protocol.writeString( ((RpcInvocation) request.getData()) .getAttachment(Constants.INTERFACE_KEY)); + protocol.writeString( + ((RpcInvocation) request.getData()) + .getAttachment(Constants.PATH_KEY)); protocol.writeI64(request.getId()); protocol.getTransport().flush(); headerLength = bos.size(); @@ -448,6 +457,7 @@ private Request createRequest() { invocation.setParameterTypes(new Class[]{String.class}); invocation.setAttachment(Constants.INTERFACE_KEY, Demo.Iface.class.getName()); + invocation.setAttachment(Constants.PATH_KEY, Demo.Iface.class.getName()); Request request = new Request(1L); diff --git a/dubbo-rpc/dubbo-rpc-webservice/pom.xml b/dubbo-rpc/dubbo-rpc-webservice/pom.xml index 2722827c53a..a859b58546c 100644 --- a/dubbo-rpc/dubbo-rpc-webservice/pom.xml +++ b/dubbo-rpc/dubbo-rpc-webservice/pom.xml @@ -1,76 +1,76 @@ - - - 4.0.0 - - org.apache.dubbo - dubbo-rpc - 2.7.0-SNAPSHOT - - dubbo-rpc-webservice - jar - ${project.artifactId} - The webservice rpc module of dubbo project - - false - - - - org.apache.dubbo - dubbo-rpc-api - ${project.parent.version} - - - org.apache.dubbo - dubbo-remoting-http - ${project.parent.version} - - - javax.xml.bind - jaxb-api - - - com.sun.xml.bind - jaxb-impl - - - com.sun.xml.bind - jaxb-core - - - javax.activation - javax.activation-api - - - com.sun.activation - javax.activation - - - org.apache.cxf - cxf-rt-frontend-simple - - - org.apache.cxf - cxf-rt-transports-http - - - org.springframework - spring-context - - - + + + 4.0.0 + + org.apache.dubbo + dubbo-rpc + 2.7.1-SNAPSHOT + + dubbo-rpc-webservice + jar + ${project.artifactId} + The webservice rpc module of dubbo project + + false + + + + org.apache.dubbo + dubbo-rpc-api + ${project.parent.version} + + + org.apache.dubbo + dubbo-remoting-http + ${project.parent.version} + + + javax.xml.bind + jaxb-api + + + com.sun.xml.bind + jaxb-impl + + + com.sun.xml.bind + jaxb-core + + + javax.activation + javax.activation-api + + + com.sun.activation + javax.activation + + + org.apache.cxf + cxf-rt-frontend-simple + + + org.apache.cxf + cxf-rt-transports-http + + + org.springframework + spring-context + + + \ No newline at end of file diff --git a/dubbo-rpc/dubbo-rpc-webservice/src/test/java/org/apache/dubbo/rpc/protocol/webservice/WebserviceProtocolTest.java b/dubbo-rpc/dubbo-rpc-webservice/src/test/java/org/apache/dubbo/rpc/protocol/webservice/WebserviceProtocolTest.java index b2531b71798..8990edf9001 100644 --- a/dubbo-rpc/dubbo-rpc-webservice/src/test/java/org/apache/dubbo/rpc/protocol/webservice/WebserviceProtocolTest.java +++ b/dubbo-rpc/dubbo-rpc-webservice/src/test/java/org/apache/dubbo/rpc/protocol/webservice/WebserviceProtocolTest.java @@ -18,6 +18,7 @@ import org.apache.dubbo.common.URL; import org.apache.dubbo.common.extension.ExtensionLoader; +import org.apache.dubbo.rpc.Exporter; import org.apache.dubbo.rpc.Protocol; import org.apache.dubbo.rpc.ProxyFactory; @@ -37,9 +38,10 @@ public class WebserviceProtocolTest { @Test public void testDemoProtocol() throws Exception { DemoService service = new DemoServiceImpl(); - protocol.export(proxy.getInvoker(service, DemoService.class, URL.valueOf("webservice://127.0.0.1:9019/" + DemoService.class.getName() + "?codec=exchange"))); + Exporter exporter = protocol.export(proxy.getInvoker(service, DemoService.class, URL.valueOf("webservice://127.0.0.1:9019/" + DemoService.class.getName() + "?codec=exchange"))); service = proxy.getProxy(protocol.refer(DemoService.class, URL.valueOf("webservice://127.0.0.1:9019/" + DemoService.class.getName() + "?codec=exchange&timeout=3000"))); assertEquals(service.getSize(new String[]{"", "", ""}), 3); + exporter.unexport(); } @Test diff --git a/dubbo-rpc/pom.xml b/dubbo-rpc/pom.xml index 9a2cb64b038..03e5b9abf4b 100644 --- a/dubbo-rpc/pom.xml +++ b/dubbo-rpc/pom.xml @@ -19,7 +19,7 @@ org.apache.dubbo dubbo-parent - 2.7.0-SNAPSHOT + 2.7.1-SNAPSHOT dubbo-rpc pom diff --git a/dubbo-serialization/dubbo-serialization-api/pom.xml b/dubbo-serialization/dubbo-serialization-api/pom.xml index 486fc9d2b8e..cd1ff42939e 100644 --- a/dubbo-serialization/dubbo-serialization-api/pom.xml +++ b/dubbo-serialization/dubbo-serialization-api/pom.xml @@ -20,7 +20,7 @@ limitations under the License. org.apache.dubbo dubbo-serialization - 2.7.0-SNAPSHOT + 2.7.1-SNAPSHOT dubbo-serialization-api jar diff --git a/dubbo-serialization/dubbo-serialization-fastjson/pom.xml b/dubbo-serialization/dubbo-serialization-fastjson/pom.xml index d1221b348ec..92dbbec8820 100644 --- a/dubbo-serialization/dubbo-serialization-fastjson/pom.xml +++ b/dubbo-serialization/dubbo-serialization-fastjson/pom.xml @@ -20,7 +20,7 @@ limitations under the License. org.apache.dubbo dubbo-serialization - 2.7.0-SNAPSHOT + 2.7.1-SNAPSHOT dubbo-serialization-fastjson jar diff --git a/dubbo-serialization/dubbo-serialization-fst/pom.xml b/dubbo-serialization/dubbo-serialization-fst/pom.xml index ad73437c060..4332453a907 100644 --- a/dubbo-serialization/dubbo-serialization-fst/pom.xml +++ b/dubbo-serialization/dubbo-serialization-fst/pom.xml @@ -19,7 +19,7 @@ org.apache.dubbo dubbo-serialization - 2.7.0-SNAPSHOT + 2.7.1-SNAPSHOT dubbo-serialization-fst jar diff --git a/dubbo-serialization/dubbo-serialization-hessian2/pom.xml b/dubbo-serialization/dubbo-serialization-hessian2/pom.xml index 0f91b78bd97..b5ba85a2953 100644 --- a/dubbo-serialization/dubbo-serialization-hessian2/pom.xml +++ b/dubbo-serialization/dubbo-serialization-hessian2/pom.xml @@ -20,7 +20,7 @@ limitations under the License. org.apache.dubbo dubbo-serialization - 2.7.0-SNAPSHOT + 2.7.1-SNAPSHOT dubbo-serialization-hessian2 jar diff --git a/dubbo-serialization/dubbo-serialization-jdk/pom.xml b/dubbo-serialization/dubbo-serialization-jdk/pom.xml index 23b56a21e27..1f78b9a9c1b 100644 --- a/dubbo-serialization/dubbo-serialization-jdk/pom.xml +++ b/dubbo-serialization/dubbo-serialization-jdk/pom.xml @@ -20,7 +20,7 @@ limitations under the License. org.apache.dubbo dubbo-serialization - 2.7.0-SNAPSHOT + 2.7.1-SNAPSHOT dubbo-serialization-jdk jar diff --git a/dubbo-serialization/dubbo-serialization-kryo/pom.xml b/dubbo-serialization/dubbo-serialization-kryo/pom.xml index df29f2ad60c..4ebf59bea3d 100644 --- a/dubbo-serialization/dubbo-serialization-kryo/pom.xml +++ b/dubbo-serialization/dubbo-serialization-kryo/pom.xml @@ -20,7 +20,7 @@ limitations under the License. org.apache.dubbo dubbo-serialization - 2.7.0-SNAPSHOT + 2.7.1-SNAPSHOT dubbo-serialization-kryo jar diff --git a/dubbo-serialization/dubbo-serialization-protostuff/pom.xml b/dubbo-serialization/dubbo-serialization-protostuff/pom.xml index cd1b644000d..ab3a2a5f390 100644 --- a/dubbo-serialization/dubbo-serialization-protostuff/pom.xml +++ b/dubbo-serialization/dubbo-serialization-protostuff/pom.xml @@ -15,14 +15,12 @@ See the License for the specific language governing permissions and limitations under the License. --> - + 4.0.0 dubbo-serialization org.apache.dubbo - 2.7.0-SNAPSHOT + 2.7.1-SNAPSHOT dubbo-serialization-protostuff diff --git a/dubbo-serialization/dubbo-serialization-protostuff/src/main/java/org/apache/dubbo/common/serialize/protostuff/ProtostuffObjectInput.java b/dubbo-serialization/dubbo-serialization-protostuff/src/main/java/org/apache/dubbo/common/serialize/protostuff/ProtostuffObjectInput.java index 6284d6a6777..e8307748deb 100644 --- a/dubbo-serialization/dubbo-serialization-protostuff/src/main/java/org/apache/dubbo/common/serialize/protostuff/ProtostuffObjectInput.java +++ b/dubbo-serialization/dubbo-serialization-protostuff/src/main/java/org/apache/dubbo/common/serialize/protostuff/ProtostuffObjectInput.java @@ -17,17 +17,15 @@ package org.apache.dubbo.common.serialize.protostuff; -import org.apache.dubbo.common.serialize.ObjectInput; -import org.apache.dubbo.common.serialize.protostuff.utils.WrapperUtils; - -import io.protostuff.ProtobufIOUtil; +import io.protostuff.GraphIOUtil; import io.protostuff.Schema; import io.protostuff.runtime.RuntimeSchema; - import java.io.DataInputStream; import java.io.IOException; import java.io.InputStream; import java.lang.reflect.Type; +import org.apache.dubbo.common.serialize.ObjectInput; +import org.apache.dubbo.common.serialize.protostuff.utils.WrapperUtils; /** * Protostuff object input implementation @@ -63,12 +61,12 @@ public Object readObject() throws IOException, ClassNotFoundException { if (WrapperUtils.needWrapper(clazz)) { Schema schema = RuntimeSchema.getSchema(Wrapper.class); Wrapper wrapper = schema.newMessage(); - ProtobufIOUtil.mergeFrom(bytes, wrapper, schema); + GraphIOUtil.mergeFrom(bytes, wrapper, schema); result = wrapper.getData(); } else { Schema schema = RuntimeSchema.getSchema(clazz); result = schema.newMessage(); - ProtobufIOUtil.mergeFrom(bytes, result, schema); + GraphIOUtil.mergeFrom(bytes, result, schema); } return result; diff --git a/dubbo-serialization/dubbo-serialization-protostuff/src/main/java/org/apache/dubbo/common/serialize/protostuff/ProtostuffObjectOutput.java b/dubbo-serialization/dubbo-serialization-protostuff/src/main/java/org/apache/dubbo/common/serialize/protostuff/ProtostuffObjectOutput.java index 3e54282a6b4..f52c755d5d1 100644 --- a/dubbo-serialization/dubbo-serialization-protostuff/src/main/java/org/apache/dubbo/common/serialize/protostuff/ProtostuffObjectOutput.java +++ b/dubbo-serialization/dubbo-serialization-protostuff/src/main/java/org/apache/dubbo/common/serialize/protostuff/ProtostuffObjectOutput.java @@ -17,17 +17,15 @@ package org.apache.dubbo.common.serialize.protostuff; -import org.apache.dubbo.common.serialize.ObjectOutput; -import org.apache.dubbo.common.serialize.protostuff.utils.WrapperUtils; - +import io.protostuff.GraphIOUtil; import io.protostuff.LinkedBuffer; -import io.protostuff.ProtobufIOUtil; import io.protostuff.Schema; import io.protostuff.runtime.RuntimeSchema; - import java.io.DataOutputStream; import java.io.IOException; import java.io.OutputStream; +import org.apache.dubbo.common.serialize.ObjectOutput; +import org.apache.dubbo.common.serialize.protostuff.utils.WrapperUtils; /** * Protostuff object output implementation @@ -52,11 +50,11 @@ public void writeObject(Object obj) throws IOException { if (WrapperUtils.needWrapper(obj)) { Schema schema = RuntimeSchema.getSchema(Wrapper.class); Wrapper wrapper = new Wrapper(obj); - bytes = ProtobufIOUtil.toByteArray(wrapper, schema, buffer); + bytes = GraphIOUtil.toByteArray(wrapper, schema, buffer); classNameBytes = Wrapper.class.getName().getBytes(); } else { Schema schema = RuntimeSchema.getSchema(obj.getClass()); - bytes = ProtobufIOUtil.toByteArray(obj, schema, buffer); + bytes = GraphIOUtil.toByteArray(obj, schema, buffer); classNameBytes = obj.getClass().getName().getBytes(); } } finally { diff --git a/dubbo-serialization/dubbo-serialization-test/pom.xml b/dubbo-serialization/dubbo-serialization-test/pom.xml index 4776b3cf360..392dc335d7d 100644 --- a/dubbo-serialization/dubbo-serialization-test/pom.xml +++ b/dubbo-serialization/dubbo-serialization-test/pom.xml @@ -15,13 +15,11 @@ limitations under the License. --> - + dubbo-serialization org.apache.dubbo - 2.7.0-SNAPSHOT + 2.7.1-SNAPSHOT 4.0.0 diff --git a/dubbo-serialization/dubbo-serialization-test/src/test/java/org/apache/dubbo/common/serialize/protostuff/ProtostuffSerializationTest.java b/dubbo-serialization/dubbo-serialization-test/src/test/java/org/apache/dubbo/common/serialize/protostuff/ProtostuffSerializationTest.java index fb99d0e9274..02c278e00b0 100644 --- a/dubbo-serialization/dubbo-serialization-test/src/test/java/org/apache/dubbo/common/serialize/protostuff/ProtostuffSerializationTest.java +++ b/dubbo-serialization/dubbo-serialization-test/src/test/java/org/apache/dubbo/common/serialize/protostuff/ProtostuffSerializationTest.java @@ -25,9 +25,4 @@ public class ProtostuffSerializationTest extends AbstractSerializationTest { serialization = new ProtostuffSerialization(); } - @Override - @Test - public void test_LoopReference() throws Exception { - // FIXME: cannot make this test pass on protostuff - } } diff --git a/dubbo-serialization/dubbo-serialization-test/src/test/resources/log4j.xml b/dubbo-serialization/dubbo-serialization-test/src/test/resources/log4j.xml index f71c5535c14..3c5e376bebd 100644 --- a/dubbo-serialization/dubbo-serialization-test/src/test/resources/log4j.xml +++ b/dubbo-serialization/dubbo-serialization-test/src/test/resources/log4j.xml @@ -18,6 +18,7 @@ + diff --git a/dubbo-serialization/pom.xml b/dubbo-serialization/pom.xml index 5183895692e..9cfb7d72da5 100644 --- a/dubbo-serialization/pom.xml +++ b/dubbo-serialization/pom.xml @@ -19,7 +19,7 @@ org.apache.dubbo dubbo-parent - 2.7.0-SNAPSHOT + 2.7.1-SNAPSHOT dubbo-serialization pom diff --git a/dubbo-test/dubbo-test-compatibility/dubbo-test-spring3/pom.xml b/dubbo-test/dubbo-test-compatibility/dubbo-test-spring3/pom.xml index f0701542bc1..db01ae3917d 100644 --- a/dubbo-test/dubbo-test-compatibility/dubbo-test-spring3/pom.xml +++ b/dubbo-test/dubbo-test-compatibility/dubbo-test-spring3/pom.xml @@ -19,7 +19,7 @@ dubbo-test-compatibility org.apache.dubbo - 2.7.0-SNAPSHOT + 2.7.1-SNAPSHOT 4.0.0 diff --git a/dubbo-test/dubbo-test-compatibility/pom.xml b/dubbo-test/dubbo-test-compatibility/pom.xml index d80907ef5c3..c6d2e1ee550 100644 --- a/dubbo-test/dubbo-test-compatibility/pom.xml +++ b/dubbo-test/dubbo-test-compatibility/pom.xml @@ -1,17 +1,18 @@ 4.0.0 @@ -21,7 +22,7 @@ org.apache.dubbo dubbo-test - 2.7.0-SNAPSHOT + 2.7.1-SNAPSHOT dubbo-test-compatibility pom diff --git a/dubbo-test/dubbo-test-integration/pom.xml b/dubbo-test/dubbo-test-integration/pom.xml index 214a3988fb4..51552d47e8d 100644 --- a/dubbo-test/dubbo-test-integration/pom.xml +++ b/dubbo-test/dubbo-test-integration/pom.xml @@ -19,7 +19,7 @@ org.apache.dubbo dubbo-test - 2.7.0-SNAPSHOT + 2.7.1-SNAPSHOT dubbo-test-integration jar diff --git a/dubbo-test/pom.xml b/dubbo-test/pom.xml index 934afb5d600..0cdf2a68fab 100644 --- a/dubbo-test/pom.xml +++ b/dubbo-test/pom.xml @@ -1,215 +1,215 @@ - - - 4.0.0 - - org.apache.dubbo - dubbo-parent - 2.7.0-SNAPSHOT - - dubbo-test - pom - ${project.artifactId} - The test module of dubbo project - - true - - - dubbo-test-compatibility - dubbo-test-integration - - - - - - org.apache.dubbo - dubbo-bom - ${project.parent.version} - pom - import - - - - - - - org.apache.dubbo - dubbo-cluster - - - org.apache.dubbo - dubbo-common - - - org.apache.dubbo - dubbo-config-api - - - org.apache.dubbo - dubbo-config-spring - - - org.apache.dubbo - dubbo-filter-cache - - - org.apache.dubbo - dubbo-filter-validation - - - org.apache.dubbo - dubbo-remoting-netty - - - org.apache.dubbo - dubbo-remoting-netty4 - - - org.apache.dubbo - dubbo-remoting-mina - - - org.apache.dubbo - dubbo-remoting-grizzly - - - org.apache.dubbo - dubbo-remoting-p2p - - - org.apache.dubbo - dubbo-remoting-http - - - org.apache.dubbo - dubbo-rpc-dubbo - - - org.apache.dubbo - dubbo-rpc-injvm - - - org.apache.dubbo - dubbo-rpc-rmi - - - org.apache.dubbo - dubbo-rpc-hessian - - - org.apache.dubbo - dubbo-rpc-http - - - org.apache.dubbo - dubbo-rpc-webservice - - - org.apache.dubbo - dubbo-rpc-thrift - - - org.apache.dubbo - dubbo-rpc-memcached - - - org.apache.dubbo - dubbo-rpc-redis - - - org.apache.dubbo - dubbo-rpc-rest - - - org.apache.dubbo - dubbo-registry-default - - - org.apache.dubbo - dubbo-registry-multicast - - - org.apache.dubbo - dubbo-registry-zookeeper - - - org.apache.dubbo - dubbo-registry-redis - - - org.apache.dubbo - dubbo-monitor-api - - - org.apache.dubbo - dubbo-monitor-default - - - org.apache.dubbo - dubbo-container-spring - - - org.apache.dubbo - dubbo-container-log4j - - - org.apache.dubbo - dubbo-container-logback - - - org.apache.dubbo - dubbo-qos - - - com.alibaba - hessian-lite - - - org.apache.dubbo - dubbo-serialization-api - - - org.apache.dubbo - dubbo-serialization-hessian2 - - - org.apache.dubbo - dubbo-serialization-fst - - - org.apache.dubbo - dubbo-serialization-fastjson - - - org.apache.dubbo - dubbo-serialization-kryo - - - org.apache.dubbo - dubbo-serialization-jdk - 2.7.0-SNAPSHOT - - - org.hibernate - hibernate-validator - - - org.glassfish - javax.el - - - + + + 4.0.0 + + org.apache.dubbo + dubbo-parent + 2.7.1-SNAPSHOT + + dubbo-test + pom + ${project.artifactId} + The test module of dubbo project + + true + + + dubbo-test-compatibility + dubbo-test-integration + + + + + + org.apache.dubbo + dubbo-bom + ${project.parent.version} + pom + import + + + + + + + org.apache.dubbo + dubbo-cluster + + + org.apache.dubbo + dubbo-common + + + org.apache.dubbo + dubbo-config-api + + + org.apache.dubbo + dubbo-config-spring + + + org.apache.dubbo + dubbo-filter-cache + + + org.apache.dubbo + dubbo-filter-validation + + + org.apache.dubbo + dubbo-remoting-netty + + + org.apache.dubbo + dubbo-remoting-netty4 + + + org.apache.dubbo + dubbo-remoting-mina + + + org.apache.dubbo + dubbo-remoting-grizzly + + + org.apache.dubbo + dubbo-remoting-p2p + + + org.apache.dubbo + dubbo-remoting-http + + + org.apache.dubbo + dubbo-rpc-dubbo + + + org.apache.dubbo + dubbo-rpc-injvm + + + org.apache.dubbo + dubbo-rpc-rmi + + + org.apache.dubbo + dubbo-rpc-hessian + + + org.apache.dubbo + dubbo-rpc-http + + + org.apache.dubbo + dubbo-rpc-webservice + + + org.apache.dubbo + dubbo-rpc-thrift + + + org.apache.dubbo + dubbo-rpc-memcached + + + org.apache.dubbo + dubbo-rpc-redis + + + org.apache.dubbo + dubbo-rpc-rest + + + org.apache.dubbo + dubbo-registry-default + + + org.apache.dubbo + dubbo-registry-multicast + + + org.apache.dubbo + dubbo-registry-zookeeper + + + org.apache.dubbo + dubbo-registry-redis + + + org.apache.dubbo + dubbo-monitor-api + + + org.apache.dubbo + dubbo-monitor-default + + + org.apache.dubbo + dubbo-container-spring + + + org.apache.dubbo + dubbo-container-log4j + + + org.apache.dubbo + dubbo-container-logback + + + org.apache.dubbo + dubbo-qos + + + com.alibaba + hessian-lite + + + org.apache.dubbo + dubbo-serialization-api + + + org.apache.dubbo + dubbo-serialization-hessian2 + + + org.apache.dubbo + dubbo-serialization-fst + + + org.apache.dubbo + dubbo-serialization-fastjson + + + org.apache.dubbo + dubbo-serialization-kryo + + + org.apache.dubbo + dubbo-serialization-jdk + 2.7.1-SNAPSHOT + + + org.hibernate + hibernate-validator + + + org.glassfish + javax.el + + + diff --git a/pom.xml b/pom.xml index a6c351ff6d2..8f1a39b7201 100644 --- a/pom.xml +++ b/pom.xml @@ -27,7 +27,7 @@ org.apache.dubbo dubbo-parent - 2.7.0-SNAPSHOT + 2.7.1-SNAPSHOT pom ${project.artifactId} @@ -154,7 +154,7 @@ org.apache.dubbo dubbo-dependencies-bom - 2.7.0-SNAPSHOT + 2.7.1-SNAPSHOT pom import @@ -300,7 +300,6 @@ jar - none org.apache.logging.log4j @@ -322,8 +321,9 @@ UTF-8 UTF-8 - http://docs.oracle.com/javase/7/docs/api + http://docs.oracle.com/javase/8/docs/api + none @@ -493,15 +493,6 @@ **/org/apache/dubbo/common/threadlocal/InternalThreadLocal.java **/org/apache/dubbo/common/threadlocal/InternalThreadLocalMap.java - - **/org/apache/dubbo/common/time/DateParser.java - **/org/apache/dubbo/common/time/DatePrinter.java - **/org/apache/dubbo/common/time/FastDateFormat.java - **/org/apache/dubbo/common/time/FastDateParser.java - **/org/apache/dubbo/common/time/FastDatePrinter.java - **/org/apache/dubbo/common/time/FastTimeZone.java - **/org/apache/dubbo/common/time/FormatCache.java - **/org/apache/dubbo/common/time/GmtTimeZone.java