This is an automated email from the ASF dual-hosted git repository. liujun pushed a commit to branch master in repository https://gitbox.apache.org/repos/asf/incubator-dubbo.git
commit b1324511d13aad36d14adee7bce71cdbe65a872a Merge: 678cdb4 5184416 Author: ken.lj <[email protected]> AuthorDate: Sun Dec 23 20:29:38 2018 +0800 Merge branch 'dev-metadata' # Conflicts: # dubbo-cluster/src/main/java/org/apache/dubbo/rpc/cluster/Router.java # dubbo-cluster/src/main/java/org/apache/dubbo/rpc/cluster/router/condition/ConditionRouter.java # dubbo-cluster/src/main/java/org/apache/dubbo/rpc/cluster/router/mock/MockInvokersSelector.java # dubbo-cluster/src/main/java/org/apache/dubbo/rpc/cluster/router/script/ScriptRouter.java # dubbo-cluster/src/main/java/org/apache/dubbo/rpc/cluster/router/tag/TagRouter.java # dubbo-cluster/src/main/java/org/apache/dubbo/rpc/cluster/support/AbstractClusterInvoker.java # dubbo-config/dubbo-config-api/src/main/java/org/apache/dubbo/config/AbstractConfig.java # dubbo-config/dubbo-config-api/src/main/java/org/apache/dubbo/config/ReferenceConfig.java # dubbo-config/dubbo-config-api/src/main/java/org/apache/dubbo/config/ServiceConfig.java # dubbo-config/dubbo-config-api/src/test/resources/log4j.xml # dubbo-config/dubbo-config-spring/src/main/java/org/apache/dubbo/config/spring/schema/DubboBeanDefinitionParser.java # dubbo-registry/dubbo-registry-api/src/main/java/org/apache/dubbo/registry/integration/RegistryDirectory.java # dubbo-registry/dubbo-registry-api/src/main/java/org/apache/dubbo/registry/support/ProviderConsumerRegTable.java # dubbo-rpc/dubbo-rpc-api/src/main/java/org/apache/dubbo/rpc/model/ApplicationModel.java # dubbo-rpc/dubbo-rpc-api/src/test/java/org/apache/dubbo/rpc/support/RuntimeExceptionInvoker.java # dubbo-rpc/dubbo-rpc-dubbo/src/test/java/org/apache/dubbo/rpc/protocol/dubbo/DubboInvokerAvilableTest.java # dubbo-rpc/dubbo-rpc-dubbo/src/test/java/org/apache/dubbo/rpc/service/GenericServiceTest.java # dubbo-rpc/dubbo-rpc-dubbo/src/test/java/org/apache/dubbo/rpc/validation/ValidationParameter.java # dubbo-rpc/dubbo-rpc-dubbo/src/test/java/org/apache/dubbo/rpc/validation/ValidationService.java # dubbo-rpc/dubbo-rpc-dubbo/src/test/java/org/apache/dubbo/rpc/validation/ValidationTest.java codestyle/checkstyle.xml | 10 +- dubbo-all/pom.xml | 57 +++ dubbo-bom/pom.xml | 35 ++ dubbo-cluster/pom.xml | 20 + ...rFactory.java => AbstractAppRouterFactory.java} | 24 +- ...uterFactory.java => AbstractRouterFactory.java} | 19 +- .../org/apache/dubbo/rpc/cluster/Configurator.java | 48 +++ .../java/org/apache/dubbo/rpc/cluster/Router.java | 45 ++- .../org/apache/dubbo/rpc/cluster/RouterChain.java | 156 ++++++++ .../apache/dubbo/rpc/cluster/RouterFactory.java | 7 +- .../cluster/configurator/AbstractConfigurator.java | 75 +++- .../cluster/configurator/parser/ConfigParser.java | 201 ++++++++++ .../configurator/parser/model/ConfigItem.java | 103 +++++ .../parser/model/ConfiguratorConfig.java | 74 ++++ .../rpc/cluster/directory/AbstractDirectory.java | 55 +-- .../rpc/cluster/directory/StaticDirectory.java | 35 +- .../dubbo/rpc/cluster/router/AbstractRouter.java | 101 +++++ .../rpc/cluster/router/AbstractRouterRule.java | 105 +++++ .../cluster/router/condition/ConditionRouter.java | 46 ++- .../config/AbstractConfigConditionRouter.java | 145 +++++++ .../condition/config/AppConfigConditionRouter.java | 28 +- .../config/AppConfigConditionRouterFactory.java} | 19 +- .../config/ServiceConfigConditionRouter.java | 28 +- .../ServiceConfigConditionRouterFactory.java} | 19 +- .../condition/config/model/BlackWhiteListRule.java | 73 ++-- .../config/model/ConditionRouterRule.java | 99 +++-- .../config/model/ConditionRuleParser.java | 57 +++ .../router/{ => mock}/MockInvokersSelector.java | 214 +++++----- .../MockRouterFactory.java} | 16 +- .../rpc/cluster/router/script/ScriptRouter.java | 32 +- .../dubbo/rpc/cluster/router/tag/TagRouter.java | 217 ++++++++-- .../rpc/cluster/router/tag/TagRouterFactory.java | 14 +- .../dubbo/rpc/cluster/router/tag/model/Tag.java | 80 ++-- .../cluster/router/tag/model/TagRouterRule.java | 86 ++++ .../cluster/router/tag/model/TagRuleParser.java | 45 +++ .../cluster/support/AbstractClusterInvoker.java | 2 +- .../dubbo/rpc/cluster/support/ClusterUtils.java | 15 +- .../cluster/support/MergeableClusterInvoker.java | 29 +- .../rpc/cluster/support/RegistryAwareCluster.java | 25 +- .../support/RegistryAwareClusterInvoker.java | 59 +++ .../internal/org.apache.dubbo.rpc.cluster.Cluster | 3 +- .../org.apache.dubbo.rpc.cluster.RouterFactory | 5 +- .../configurator/parser/ConfigParserTest.java | 167 ++++++++ .../loadbalance/RoundRobinLoadBalanceTest.java | 32 +- .../cluster/router/ConfigConditionRouterTest.java | 134 +++++++ .../dubbo/rpc/cluster/router/TagRouterTest.java | 67 ++++ .../cluster/router/file/FileRouterEngineTest.java | 14 +- .../rpc/cluster/router/tag/TagRouterTest.java | 170 -------- .../support/AbstractClusterInvokerTest.java | 10 +- .../support/wrapper/MockClusterInvokerTest.java | 22 +- .../src/test/resources/AppAnyServices.yml | 32 ++ .../src/test/resources/AppMultiServices.yml | 32 ++ dubbo-cluster/src/test/resources/AppNoService.yml | 32 ++ dubbo-cluster/src/test/resources/ConditionRule.yml | 56 +++ .../test/resources/ConsumerSpecificProviders.yml | 34 ++ .../src/test/resources/ServiceGroupVersion.yml | 29 ++ .../src/test/resources/ServiceMultiApps.yml | 30 ++ dubbo-cluster/src/test/resources/ServiceNoApp.yml | 29 ++ dubbo-cluster/src/test/resources/ServiceNoRule.yml | 28 ++ dubbo-cluster/src/test/resources/TagRule.yml | 31 ++ .../java/org/apache/dubbo/common/Constants.java | 89 ++++- .../src/main/java/org/apache/dubbo/common/URL.java | 62 ++- .../dubbo/common/config/AbstractConfiguration.java | 91 +++++ .../common/config/AbstractPrefixConfiguration.java | 52 +++ .../common/config/CompositeConfiguration.java | 82 ++++ .../apache/dubbo/common/config/Configuration.java | 82 ++++ .../dubbo/common/config/ConfigurationUtils.java | 59 +++ .../apache/dubbo/common/config/Environment.java | 199 ++++++++++ .../common/config/EnvironmentConfiguration.java | 22 +- .../dubbo/common/config/InmemoryConfiguration.java | 67 ++++ .../common/config/PropertiesConfiguration.java | 28 +- .../dubbo/common/config/SystemConfiguration.java | 27 +- .../dubbo/common/extension/ExtensionLoader.java | 20 +- .../org/apache/dubbo/common/utils/ClassHelper.java | 70 ++++ .../org/apache/dubbo/common/utils/ConfigUtils.java | 40 +- .../org/apache/dubbo/common/utils/UrlUtils.java | 11 +- .../config/AbstractPrefixConfigurationTest.java | 46 +-- .../common/config/CompositeConfigurationTest.java | 46 +-- .../dubbo/common/config/EnvironmentTest.java | 46 +-- .../apache/dubbo/common/utils/ConfigUtilsTest.java | 27 -- dubbo-compatible/pom.xml | 7 +- .../java/com/alibaba/dubbo/rpc/cluster/Router.java | 34 +- .../dubbo/config/RegistryDataConfigTest.java | 87 ++++ .../apache/dubbo/generic/GenericServiceTest.java | 181 ++++++++- .../apache/dubbo/rpc/cluster/CompatibleRouter.java | 88 +++-- .../org/apache/dubbo/service/ComplexObject.java | 282 +++++++++++++ .../java/org/apache/dubbo/service/DemoService.java | 8 +- .../org/apache/dubbo/service/DemoServiceImpl.java | 15 +- dubbo-config/dubbo-config-api/pom.xml | 5 + .../org/apache/dubbo/config/AbstractConfig.java | 323 +++++++++------ .../dubbo/config/AbstractInterfaceConfig.java | 297 ++++++++++---- .../apache/dubbo/config/AbstractMethodConfig.java | 16 +- .../apache/dubbo/config/AbstractServiceConfig.java | 36 +- .../org/apache/dubbo/config/ApplicationConfig.java | 29 +- .../apache/dubbo/config/ConfigCenterConfig.java | 313 +++++++++++++++ .../org/apache/dubbo/config/ConsumerConfig.java | 8 +- .../org/apache/dubbo/config/DubboShutdownHook.java | 9 +- ...onitorConfig.java => MetadataReportConfig.java} | 280 ++++++------- .../java/org/apache/dubbo/config/MethodConfig.java | 37 ++ .../java/org/apache/dubbo/config/ModuleConfig.java | 8 +- .../org/apache/dubbo/config/MonitorConfig.java | 13 +- .../org/apache/dubbo/config/ProtocolConfig.java | 11 +- .../org/apache/dubbo/config/ReferenceConfig.java | 121 +++--- .../org/apache/dubbo/config/RegistryConfig.java | 49 ++- .../apache/dubbo/config/RegistryDataConfig.java | 86 ++++ .../org/apache/dubbo/config/ServiceConfig.java | 177 ++++++--- .../invoker/DelegateProviderMetaDataInvoker.java | 2 +- .../org/apache/dubbo/config/support/Parameter.java | 2 + .../apache/dubbo/config/AbstractConfigTest.java | 280 ++++++++++++- .../dubbo/config/AbstractInterfaceConfigTest.java | 5 +- .../dubbo/config/AbstractReferenceConfigTest.java | 1 + .../dubbo/config/AbstractServiceConfigTest.java | 1 + .../apache/dubbo/config/ApplicationConfigTest.java | 1 + .../org/apache/dubbo/config/MethodConfigTest.java | 1 + .../apache/dubbo/config/ProtocolConfigTest.java | 1 + .../apache/dubbo/config/ReferenceConfigTest.java | 6 + .../apache/dubbo/config/RegistryConfigTest.java | 2 + .../org/apache/dubbo/config/ServiceConfigTest.java | 6 +- .../org/apache/dubbo/config/api/DemoException.java | 84 ++-- .../org/apache/dubbo/config/api/DemoService.java | 72 ++-- .../java/org/apache/dubbo/config/api/User.java | 130 +++--- .../apache/dubbo/config/cache/CacheService.java | 52 +-- .../dubbo/config/cache/CacheServiceImpl.java | 64 +-- .../org/apache/dubbo/config/cache/CacheTest.java | 238 +++++------ .../config/consumer/DemoActionByAnnotation.java | 68 ++-- .../dubbo/config/consumer/DemoActionBySetter.java | 70 ++-- .../dubbo/config/consumer/DemoInterceptor.java | 60 +-- .../DelegateProviderMetaDataInvokerTest.java | 3 +- .../dubbo/config/mock/MockExporterListener.java | 2 +- .../org/apache/dubbo/config/mock/MockRegistry.java | 16 +- .../dubbo/config/mock/MockRegistryFactory.java | 2 +- .../apache/dubbo/config/mock/MockThreadPool.java | 2 +- .../apache/dubbo/config/mock/MockTransporter.java | 1 + .../config/provider/impl/DemoServiceImpl.java | 100 ++--- .../org.apache.dubbo.registry.RegistryFactory | 4 +- .../src/test/resources/dubbo.properties | 2 + .../dubbo-config-api/src/test/resources/log4j.xml | 54 +-- .../dubbo/config/spring/ConfigCenterBean.java | 154 ++++++++ .../apache/dubbo/config/spring/ReferenceBean.java | 57 ++- .../apache/dubbo/config/spring/ServiceBean.java | 76 +++- .../annotation/DubboConfigConfiguration.java | 12 +- .../spring/schema/DubboBeanDefinitionParser.java | 46 +-- .../spring/schema/DubboNamespaceHandler.java | 2 + .../src/main/resources/META-INF/compat/dubbo.xsd | 137 ++++++- .../src/main/resources/META-INF/dubbo.xsd | 128 ++++++ .../dubbo-configcenter-api}/pom.xml | 14 +- .../configcenter/AbstractDynamicConfiguration.java | 127 ++++++ .../AbstractDynamicConfigurationFactory.java | 26 +- .../dubbo/configcenter/ConfigChangeEvent.java | 63 +++ .../dubbo/configcenter/ConfigChangeType.java | 63 +-- .../dubbo/configcenter/ConfigurationListener.java | 57 +-- .../dubbo/configcenter/DynamicConfiguration.java | 106 +++++ .../configcenter/DynamicConfigurationFactory.java | 56 +-- .../support/nop/NopDynamicConfiguration.java | 66 ++++ .../nop/NopDynamicConfigurationFactory.java | 17 +- ....dubbo.configcenter.DynamicConfigurationFactory | 1 + .../mock/AbstractDynamicConfigurationTest.java | 47 +++ .../mock/MockDynamicConfiguration.java | 64 +++ .../mock/MockDynamicConfigurationFactory.java | 17 +- ....dubbo.configcenter.DynamicConfigurationFactory | 1 + .../dubbo-configcenter-apollo}/pom.xml | 16 +- .../support/apollo/ApolloDynamicConfiguration.java | 191 +++++++++ .../apollo/ApolloDynamicConfigurationFactory.java | 18 +- ....dubbo.configcenter.DynamicConfigurationFactory | 1 + .../dubbo-configcenter-zookeeper}/pom.xml | 43 +- .../support/zookeeper/CacheListener.java | 119 ++++++ .../zookeeper/ZookeeperDynamicConfiguration.java | 162 ++++++++ .../ZookeeperDynamicConfigurationFactory.java | 20 +- ....dubbo.configcenter.DynamicConfigurationFactory | 1 + .../ZookeeperDynamicConfigurationTest.java | 151 +++++++ {dubbo-cluster => dubbo-configcenter}/pom.xml | 22 +- dubbo-container/dubbo-container-log4j/pom.xml | 5 + .../dubbo/container/log4j/Log4jContainer.java | 8 +- .../java/org/apache/dubbo/demo/DemoService.java | 4 + dubbo-demo/dubbo-demo-consumer/pom.xml | 14 +- .../org/apache/dubbo/demo/consumer/Consumer.java | 8 + .../dubbo/demo/consumer/DemoServiceMock.java | 24 +- .../META-INF/spring/dubbo-demo-consumer.xml | 8 +- dubbo-demo/dubbo-demo-provider/pom.xml | 18 +- .../dubbo/demo/provider/DemoServiceImpl.java | 12 + .../META-INF/spring/dubbo-demo-provider.xml | 86 ++-- dubbo-dependencies-bom/pom.xml | 54 ++- .../dubbo-metadata-definition}/pom.xml | 27 +- .../definition/ServiceDefinitionBuilder.java | 107 +++++ .../metadata/definition/TypeDefinitionBuilder.java | 79 ++++ .../definition/builder/ArrayTypeBuilder.java | 119 +++--- .../definition/builder/CollectionTypeBuilder.java | 79 ++++ .../definition/builder/DefaultTypeBuilder.java | 70 ++++ .../definition/builder/EnumTypeBuilder.java | 63 +++ .../definition/builder/MapTypeBuilder.java | 76 ++++ .../metadata/definition/builder/TypeBuilder.java | 82 ++-- .../definition/model/FullServiceDefinition.java | 30 +- .../definition/model/MethodDefinition.java | 92 +++++ .../definition/model/ServiceDefinition.java | 96 +++++ .../metadata/definition/model/TypeDefinition.java | 124 ++++++ .../dubbo/metadata/definition/util/ClassUtils.java | 111 ++++++ .../definition/util/JaketConfigurationUtils.java | 100 +++++ .../dubbo/metadata/definition/MetadataTest.java | 143 +++++++ .../dubbo/metadata/definition/MetadataUtils.java | 75 ++++ .../definition/ServiceDefinitionBuildderTest.java | 98 +++++ .../definition/common/ClassExtendsMap.java | 19 +- .../metadata/definition/common/ColorEnum.java | 45 ++- .../metadata/definition/common/OuterClass.java | 72 ++-- .../common/ResultWithRawCollections.java | 96 +++-- .../metadata/definition/common/TestService.java | 98 +++-- .../metadata/definition/service/ComplexObject.java | 296 ++++++++++++++ .../metadata/definition/service}/DemoService.java | 67 ++-- .../dubbo-metadata-report-api}/pom.xml | 53 ++- .../metadata/identifier/MetadataIdentifier.java | 125 ++++++ .../integration/MetadataReportService.java | 103 +++++ .../dubbo/metadata/store/MetadataReport.java | 73 ++-- .../metadata/store/MetadataReportFactory.java | 56 +-- .../metadata/support/AbstractMetadataReport.java | 407 +++++++++++++++++++ .../support/AbstractMetadataReportFactory.java | 64 +++ .../integration/InterfaceNameTestService.java | 48 +-- .../integration/InterfaceNameTestService2.java | 48 +-- .../integration/MetadataReportServiceTest.java | 137 +++++++ .../metadata/integration/RetryTestService.java | 53 +-- .../store/test/JTestMetadataReport4Test.java | 69 ++++ .../test/JTestMetadataReportFactory4Test.java | 25 +- .../support/AbstractMetadataReportFactoryTest.java | 94 +++++ .../support/AbstractMetadataReportTest.java | 323 +++++++++++++++ ...ache.dubbo.metadata.store.MetadataReportFactory | 1 + .../dubbo-metadata-report-redis}/pom.xml | 35 +- .../metadata/store/redis/RedisMetadataReport.java | 63 +++ .../store/redis/RedisMetadataReportFactory.java | 17 +- ...ache.dubbo.metadata.store.MetadataReportFactory | 1 + .../store/redis/RedisMetadata4TstService.java | 12 + .../store/redis/RedisMetadataReportTest.java | 130 ++++++ .../dubbo-metadata-report-zookeeper}/pom.xml | 29 +- .../store/zookeeper/ZookeeperMetadataReport.java | 94 +++++ .../zookeeper/ZookeeperMetadataReportFactory.java | 25 +- ...ache.dubbo.metadata.store.MetadataReportFactory | 1 + .../ZookeeperMetadataReport4TstService.java | 11 + .../zookeeper/ZookeeperMetadataReportTest.java | 125 ++++++ {dubbo-cluster => dubbo-metadata-report}/pom.xml | 35 +- dubbo-plugin/dubbo-qos/pom.xml | 2 +- dubbo-registry/dubbo-registry-api/pom.xml | 23 +- .../integration/AbstractConfiguratorListener.java | 71 ++++ .../registry/integration/RegistryDirectory.java | 439 +++++++++++++-------- .../registry/integration/RegistryProtocol.java | 317 +++++++++++---- .../registry/support/ProviderConsumerRegTable.java | 48 ++- .../registry/support/ProviderInvokerWrapper.java | 9 + .../java/org/apache/dubbo/registry/ZKTools.java | 307 ++++++++++++++ dubbo-registry/dubbo-registry-default/pom.xml | 5 + .../registry/dubbo/RegistryDirectoryTest.java | 18 +- .../dubbo/registry/dubbo/RegistryProtocolTest.java | 1 - .../registry/integration/RegistryProtocolTest.java | 23 ++ .../dubbo/remoting/zookeeper/ZookeeperClient.java | 4 + .../zookeeper/curator/CuratorZookeeperClient.java | 40 ++ .../zookeeper/support/AbstractZookeeperClient.java | 28 ++ .../zookeeper/zkclient/ZkClientWrapper.java | 15 + .../zkclient/ZkclientZookeeperClient.java | 25 ++ .../curator/CuratorZookeeperClientTest.java | 30 +- .../zkclient/ZkclientZookeeperClientTest.java | 30 +- .../java/org/apache/dubbo/rpc/AsyncContext.java | 1 + .../java/org/apache/dubbo/rpc/AsyncRpcResult.java | 4 +- .../main/java/org/apache/dubbo/rpc/RpcContext.java | 5 +- .../java/org/apache/dubbo/rpc/RpcException.java | 5 + .../org/apache/dubbo/rpc/filter/ContextFilter.java | 1 - .../apache/dubbo/rpc/model/ApplicationModel.java | 10 + dubbo-rpc/dubbo-rpc-dubbo/pom.xml | 5 + .../dubbo/rpc/protocol/dubbo/DubboInvoker.java | 4 +- .../dubbo/rpc/protocol/dubbo/DubboProtocol.java | 8 +- .../protocol/dubbo/DubboInvokerAvilableTest.java | 3 +- .../dubbo/rpc/protocol/thrift/ThriftProtocol.java | 4 +- .../webservice/WebserviceProtocolTest.java | 4 +- .../dubbo/test/provider/DefaultDemoService.java | 10 + pom.xml | 2 + 269 files changed, 13777 insertions(+), 3060 deletions(-) diff --cc dubbo-cluster/src/main/java/org/apache/dubbo/rpc/cluster/directory/AbstractDirectory.java index f650b6e,20b0a0e..f44c398 --- 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 @@@ -16,24 -16,18 +16,20 @@@ */ package org.apache.dubbo.rpc.cluster.directory; - import org.apache.dubbo.common.Constants; import org.apache.dubbo.common.URL; - import org.apache.dubbo.common.extension.ExtensionLoader; import org.apache.dubbo.common.logger.Logger; import org.apache.dubbo.common.logger.LoggerFactory; +import org.apache.dubbo.common.utils.StringUtils; import org.apache.dubbo.rpc.Invocation; import org.apache.dubbo.rpc.Invoker; import org.apache.dubbo.rpc.RpcException; import org.apache.dubbo.rpc.cluster.Directory; import org.apache.dubbo.rpc.cluster.Router; - import org.apache.dubbo.rpc.cluster.RouterFactory; - import org.apache.dubbo.rpc.cluster.router.MockInvokersSelector; + import org.apache.dubbo.rpc.cluster.RouterChain; import java.util.ArrayList; - import java.util.Collections; import java.util.List; +import java.util.Map; /** * Abstract implementation of Directory: Invoker list returned from this Directory's list method have been filtered by Routers @@@ -64,16 -58,9 +60,16 @@@ public abstract class AbstractDirectory if (url == null) { throw new IllegalArgumentException("url == null"); } - this.url = url; + + if (url.getProtocol().equals(Constants.REGISTRY_PROTOCOL)) { + Map<String, String> queryMap = StringUtils.parseQueryString(url.getParameterAndDecoded(Constants.REFER_KEY)); + this.url = url.clearParameters().addParameters(queryMap).removeParameter(Constants.MONITOR_KEY); + } else { + this.url = url; + } + this.consumerUrl = consumerUrl; - setRouters(routers); + setRouterChain(routerChain); } @Override diff --cc dubbo-cluster/src/main/java/org/apache/dubbo/rpc/cluster/router/script/ScriptRouter.java index 7c3070a,05815df..f95573c --- 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 @@@ -40,9 -40,10 +40,9 @@@ import java.util.concurrent.ConcurrentH /** * ScriptRouter - * */ - public class ScriptRouter implements Router { - + public class ScriptRouter extends AbstractRouter { + public static final String NAME = "SCRIPT_ROUTER"; private static final Logger logger = LoggerFactory.getLogger(ScriptRouter.class); private static final Map<String, ScriptEngine> engines = new ConcurrentHashMap<String, ScriptEngine>(); diff --cc dubbo-cluster/src/main/java/org/apache/dubbo/rpc/cluster/support/AbstractClusterInvoker.java index 2d3602a,14e9f07..63486aa --- 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 @@@ -256,8 -257,8 +256,8 @@@ public abstract class AbstractClusterIn } protected void checkInvokers(List<Invoker<T>> invokers, Invocation invocation) { - if (invokers == null || invokers.isEmpty()) { + if (CollectionUtils.isEmpty(invokers)) { - throw new RpcException("Failed to invoke the method " + throw new RpcException(RpcException.NO_INVOKER_AVAILABLE_AFTER_FILTER, "Failed to invoke the method " + invocation.getMethodName() + " in the service " + getInterface().getName() + ". No provider available for the service " + directory.getUrl().getServiceKey() + " from registry " + directory.getUrl().getAddress() diff --cc dubbo-common/src/main/java/org/apache/dubbo/common/Constants.java index c6f8b1f,5c1006b..1750e31 --- a/dubbo-common/src/main/java/org/apache/dubbo/common/Constants.java +++ b/dubbo-common/src/main/java/org/apache/dubbo/common/Constants.java @@@ -671,11 -715,41 +725,42 @@@ public class Constants public static final String MULTICAST = "multicast"; - public static final String TAG_KEY = "tag"; + public static final String TAG_KEY = "dubbo.tag"; + + public static final String FORCE_USE_TAG = "dubbo.force.tag"; + + public static final String HOST_KEY = "host"; + + public static final String ADDRESS_KEY = "address"; + + public static final String RETRY_TIMES_KEY = "retry.times"; + + public static final String RETRY_PERIOD_KEY = "retry.period"; + + public static final String SYNC_REPORT_KEY = "sync.report"; + + public static final String CYCLE_REPORT_KEY = "cycle.report"; + + public static final String CONFIG_VERSION_KEY = "configVersion"; + + 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 OVERRIDE_PROVIDERS_KEY = "providerAddreses"; + + public static final String PROTOCOLS_SUFFIX = "dubbo.protocols."; + + public static final String PROTOCOL_SUFFIX = "dubbo.protocol."; + + 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}; - public static final String REQUEST_TAG_KEY = "request.tag"; + public static final String[] DEFAULT_REGISTER_CONSUMER_KEYS = {APPLICATION_KEY, VERSION_KEY, GROUP_KEY, DUBBO_VERSION_KEY, SPECIFICATION_VERSION_KEY}; + public static final String TELNET = "telnet"; /* * private Constants(){ } */ diff --cc dubbo-config/dubbo-config-api/src/main/java/org/apache/dubbo/config/AbstractConfig.java index 7cddb97,a64c73e..952853d --- 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 @@@ -1,535 -1,606 +1,606 @@@ -/* - * 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.config.Configuration; -import org.apache.dubbo.common.config.Environment; -import org.apache.dubbo.common.extension.ExtensionLoader; -import org.apache.dubbo.common.logger.Logger; -import org.apache.dubbo.common.logger.LoggerFactory; -import org.apache.dubbo.common.utils.ClassHelper; -import org.apache.dubbo.common.utils.CollectionUtils; -import org.apache.dubbo.common.utils.ReflectUtils; -import org.apache.dubbo.common.utils.StringUtils; -import org.apache.dubbo.config.support.Parameter; -import org.apache.dubbo.rpc.model.ConsumerMethodModel; - -import java.io.Serializable; -import java.lang.reflect.Method; -import java.lang.reflect.Modifier; -import java.util.HashMap; -import java.util.Map; -import java.util.Set; -import java.util.regex.Matcher; -import java.util.regex.Pattern; -import java.util.stream.Collectors; - -/** - * Utility methods and public methods for parsing configuration - * - * @export - */ -public abstract class AbstractConfig implements Serializable { - - protected static final Logger logger = LoggerFactory.getLogger(AbstractConfig.class); - private static final long serialVersionUID = 4267533505537413570L; - private static final int MAX_LENGTH = 200; - - private static final int MAX_PATH_LENGTH = 200; - - private static final Pattern PATTERN_NAME = Pattern.compile("[\\-._0-9a-zA-Z]+"); - - private static final Pattern PATTERN_MULTI_NAME = Pattern.compile("[,\\-._0-9a-zA-Z]+"); - - private static final Pattern PATTERN_METHOD_NAME = Pattern.compile("[a-zA-Z][0-9a-zA-Z]*"); - - private static final Pattern PATTERN_PATH = Pattern.compile("[/\\-$._0-9a-zA-Z]+"); - - private static final Pattern PATTERN_NAME_HAS_SYMBOL = Pattern.compile("[:*,\\s/\\-._0-9a-zA-Z]+"); - - private static final Pattern PATTERN_KEY = Pattern.compile("[*,\\-._0-9a-zA-Z]+"); - private static final Map<String, String> legacyProperties = new HashMap<String, String>(); - private static final String[] SUFFIXES = new String[]{"Config", "Bean"}; - - static { - legacyProperties.put("dubbo.protocol.name", "dubbo.service.protocol"); - legacyProperties.put("dubbo.protocol.host", "dubbo.service.server.host"); - legacyProperties.put("dubbo.protocol.port", "dubbo.service.server.port"); - legacyProperties.put("dubbo.protocol.threads", "dubbo.service.max.thread.pool.size"); - legacyProperties.put("dubbo.consumer.timeout", "dubbo.service.invoke.timeout"); - legacyProperties.put("dubbo.consumer.retries", "dubbo.service.max.retry.providers"); - legacyProperties.put("dubbo.consumer.check", "dubbo.service.allow.no.provider"); - legacyProperties.put("dubbo.service.url", "dubbo.service.address"); - - // this is only for compatibility - Runtime.getRuntime().addShutdownHook(DubboShutdownHook.getDubboShutdownHook()); - } - - protected String id; - protected String prefix; - - private static String convertLegacyValue(String key, String value) { - if (value != null && value.length() > 0) { - if ("dubbo.service.max.retry.providers".equals(key)) { - return String.valueOf(Integer.parseInt(value) - 1); - } else if ("dubbo.service.allow.no.provider".equals(key)) { - return String.valueOf(!Boolean.parseBoolean(value)); - } - } - return value; - } - - private static String getTagName(Class<?> cls) { - String tag = cls.getSimpleName(); - for (String suffix : SUFFIXES) { - if (tag.endsWith(suffix)) { - tag = tag.substring(0, tag.length() - suffix.length()); - break; - } - } - return tag.substring(0, 1).toLowerCase() + tag.substring(1); - } - - protected static void appendParameters(Map<String, String> parameters, Object config) { - appendParameters(parameters, config, null); - } - - @SuppressWarnings("unchecked") - protected static void appendParameters(Map<String, String> parameters, Object config, String prefix) { - if (config == null) { - return; - } - Method[] methods = config.getClass().getMethods(); - for (Method method : methods) { - try { - String name = method.getName(); - if (ClassHelper.isGetter(method)) { - Parameter parameter = method.getAnnotation(Parameter.class); - if (method.getReturnType() == Object.class || parameter != null && parameter.excluded()) { - continue; - } - String key; - if (parameter != null && parameter.key().length() > 0) { - key = parameter.key(); - } else { - key = calculatePropertyFromGetter(name); - } - Object value = method.invoke(config); - String str = String.valueOf(value).trim(); - if (value != null && str.length() > 0) { - if (parameter != null && parameter.escaped()) { - str = URL.encode(str); - } - if (parameter != null && parameter.append()) { - String pre = parameters.get(Constants.DEFAULT_KEY + "." + key); - if (pre != null && pre.length() > 0) { - str = pre + "," + str; - } - pre = parameters.get(key); - if (pre != null && pre.length() > 0) { - str = pre + "," + str; - } - } - if (prefix != null && prefix.length() > 0) { - key = prefix + "." + key; - } - parameters.put(key, str); - } else if (parameter != null && parameter.required()) { - throw new IllegalStateException(config.getClass().getSimpleName() + "." + key + " == null"); - } - } else if ("getParameters".equals(name) - && Modifier.isPublic(method.getModifiers()) - && method.getParameterTypes().length == 0 - && method.getReturnType() == Map.class) { - Map<String, String> map = (Map<String, String>) method.invoke(config, new Object[0]); - if (map != null && map.size() > 0) { - String pre = (prefix != null && prefix.length() > 0 ? prefix + "." : ""); - for (Map.Entry<String, String> entry : map.entrySet()) { - parameters.put(pre + entry.getKey().replace('-', '.'), entry.getValue()); - } - } - } - } catch (Exception e) { - throw new IllegalStateException(e.getMessage(), e); - } - } - } - - protected static void appendAttributes(Map<String, Object> parameters, Object config) { - appendAttributes(parameters, config, null); - } - - protected static void appendAttributes(Map<String, Object> parameters, Object config, String prefix) { - if (config == null) { - return; - } - Method[] methods = config.getClass().getMethods(); - for (Method method : methods) { - try { - Parameter parameter = method.getAnnotation(Parameter.class); - if (parameter == null || !parameter.attribute()) { - continue; - } - String name = method.getName(); - if (ClassHelper.isGetter(method)) { - String key; - if (parameter.key().length() > 0) { - key = parameter.key(); - } else { - key = calculateAttributeFromGetter(name); - } - Object value = method.invoke(config); - if (value != null) { - if (prefix != null && prefix.length() > 0) { - key = prefix + "." + key; - } - parameters.put(key, value); - } - } - } catch (Exception e) { - throw new IllegalStateException(e.getMessage(), e); - } - } - } - - protected static ConsumerMethodModel.AsyncMethodInfo convertMethodConfig2AyncInfo(MethodConfig methodConfig) { - if (methodConfig == null || (methodConfig.getOninvoke() == null && methodConfig.getOnreturn() == null && methodConfig.getOnthrow() == null)) { - return null; - } - - //check config conflict - if (Boolean.FALSE.equals(methodConfig.isReturn()) && (methodConfig.getOnreturn() != null || methodConfig.getOnthrow() != null)) { - throw new IllegalStateException("method config error : return attribute must be set true when onreturn or onthrow has been set."); - } - - ConsumerMethodModel.AsyncMethodInfo asyncMethodInfo = new ConsumerMethodModel.AsyncMethodInfo(); - - asyncMethodInfo.setOninvokeInstance(methodConfig.getOninvoke()); - asyncMethodInfo.setOnreturnInstance(methodConfig.getOnreturn()); - asyncMethodInfo.setOnthrowInstance(methodConfig.getOnthrow()); - - try { - String oninvokeMethod = methodConfig.getOninvokeMethod(); - if (StringUtils.isNotEmpty(oninvokeMethod)) { - asyncMethodInfo.setOninvokeMethod(getMethodByName(methodConfig.getOninvoke().getClass(), oninvokeMethod)); - } - - String onreturnMethod = methodConfig.getOnreturnMethod(); - if (StringUtils.isNotEmpty(onreturnMethod)) { - asyncMethodInfo.setOnreturnMethod(getMethodByName(methodConfig.getOnreturn().getClass(), onreturnMethod)); - } - - String onthrowMethod = methodConfig.getOnthrowMethod(); - if (StringUtils.isNotEmpty(onthrowMethod)) { - asyncMethodInfo.setOnthrowMethod(getMethodByName(methodConfig.getOnthrow().getClass(), onthrowMethod)); - } - } catch (Exception e) { - throw new IllegalStateException(e.getMessage(), e); - } - - return asyncMethodInfo; - } - - private static Method getMethodByName(Class<?> clazz, String methodName) { - try { - return ReflectUtils.findMethodByMethodName(clazz, methodName); - } catch (Exception e) { - throw new IllegalStateException(e); - } - } - - /** - * We only check boolean value at this moment. - * - * @param type - * @param value - * @return - */ - private static boolean isTypeMatch(Class<?> type, String value) { - if ((type == boolean.class || type == Boolean.class) - && !("true".equals(value) || "false".equals(value))) { - return false; - } - return true; - } - - protected static void checkExtension(Class<?> type, String property, String value) { - checkName(property, value); - if (value != null && value.length() > 0 - && !ExtensionLoader.getExtensionLoader(type).hasExtension(value)) { - throw new IllegalStateException("No such extension " + value + " for " + property + "/" + type.getName()); - } - } - - protected static void checkMultiExtension(Class<?> type, String property, String value) { - checkMultiName(property, value); - if (value != null && value.length() > 0) { - String[] values = value.split("\\s*[,]+\\s*"); - for (String v : values) { - if (v.startsWith(Constants.REMOVE_VALUE_PREFIX)) { - v = v.substring(1); - } - if (Constants.DEFAULT_KEY.equals(v)) { - continue; - } - if (!ExtensionLoader.getExtensionLoader(type).hasExtension(v)) { - throw new IllegalStateException("No such extension " + v + " for " + property + "/" + type.getName()); - } - } - } - } - - protected static void checkLength(String property, String value) { - checkProperty(property, value, MAX_LENGTH, null); - } - - protected static void checkPathLength(String property, String value) { - checkProperty(property, value, MAX_PATH_LENGTH, null); - } - - protected static void checkName(String property, String value) { - checkProperty(property, value, MAX_LENGTH, PATTERN_NAME); - } - - protected static void checkNameHasSymbol(String property, String value) { - checkProperty(property, value, MAX_LENGTH, PATTERN_NAME_HAS_SYMBOL); - } - - protected static void checkKey(String property, String value) { - checkProperty(property, value, MAX_LENGTH, PATTERN_KEY); - } - - protected static void checkMultiName(String property, String value) { - checkProperty(property, value, MAX_LENGTH, PATTERN_MULTI_NAME); - } - - protected static void checkPathName(String property, String value) { - checkProperty(property, value, MAX_PATH_LENGTH, PATTERN_PATH); - } - - protected static void checkMethodName(String property, String value) { - checkProperty(property, value, MAX_LENGTH, PATTERN_METHOD_NAME); - } - - protected static void checkParameterName(Map<String, String> parameters) { - if (parameters == null || parameters.size() == 0) { - return; - } - for (Map.Entry<String, String> entry : parameters.entrySet()) { - checkNameHasSymbol(entry.getKey(), entry.getValue()); - } - } - - protected static void checkProperty(String property, String value, int maxlength, Pattern pattern) { - if (value == null || value.length() == 0) { - return; - } - if (value.length() > maxlength) { - throw new IllegalStateException("Invalid " + property + "=\"" + value + "\" is longer than " + maxlength); - } - if (pattern != null) { - Matcher matcher = pattern.matcher(value); - if (!matcher.matches()) { - throw new IllegalStateException("Invalid " + property + "=\"" + value + "\" contains illegal " + - "character, only digit, letter, '-', '_' or '.' is legal."); - } - } - } - - protected static Set<String> getSubProperties(Map<String, String> properties, String prefix) { - return properties.keySet().stream().filter(k -> k.contains(prefix)).map(k -> { - k = k.substring(prefix.length()); - return k.substring(0, k.indexOf(".")); - }).collect(Collectors.toSet()); - } - - private static String extractPropertyName(Class<?> clazz, Method setter) throws Exception { - String propertyName = setter.getName().substring("set".length()); - Method getter = null; - try { - getter = clazz.getMethod("get" + propertyName); - } catch (NoSuchMethodException e) { - getter = clazz.getMethod("is" + propertyName); - } - Parameter parameter = getter.getAnnotation(Parameter.class); - if (parameter != null && StringUtils.isNotEmpty(parameter.key()) && parameter.useKeyAsProperty()) { - propertyName = parameter.key(); - } else { - propertyName = propertyName.substring(0, 1).toLowerCase() + propertyName.substring(1); - } - return propertyName; - } - - private static String calculatePropertyFromGetter(String name) { - int i = name.startsWith("get") ? 3 : 2; - return StringUtils.camelToSplitName(name.substring(i, i + 1).toLowerCase() + name.substring(i + 1), "."); - } - - private static String calculateAttributeFromGetter(String getter) { - int i = getter.startsWith("get") ? 3 : 2; - return getter.substring(i, i + 1).toLowerCase() + getter.substring(i + 1); - } - - @Parameter(excluded = true) - public String getId() { - return id; - } - - public void setId(String id) { - this.id = id; - } - - public void updateIdIfAbsent(String value) { - if (StringUtils.isNotEmpty(value) && StringUtils.isEmpty(id)) { - this.id = value; - } - } - - protected void appendAnnotation(Class<?> annotationClass, Object annotation) { - Method[] methods = annotationClass.getMethods(); - for (Method method : methods) { - if (method.getDeclaringClass() != Object.class - && method.getReturnType() != void.class - && method.getParameterTypes().length == 0 - && Modifier.isPublic(method.getModifiers()) - && !Modifier.isStatic(method.getModifiers())) { - try { - String property = method.getName(); - if ("interfaceClass".equals(property) || "interfaceName".equals(property)) { - property = "interface"; - } - String setter = "set" + property.substring(0, 1).toUpperCase() + property.substring(1); - Object value = method.invoke(annotation); - if (value != null && !value.equals(method.getDefaultValue())) { - Class<?> parameterType = ReflectUtils.getBoxedClass(method.getReturnType()); - if ("filter".equals(property) || "listener".equals(property)) { - parameterType = String.class; - value = StringUtils.join((String[]) value, ","); - } else if ("parameters".equals(property)) { - parameterType = Map.class; - value = CollectionUtils.toStringMap((String[]) value); - } - try { - Method setterMethod = getClass().getMethod(setter, parameterType); - setterMethod.invoke(this, value); - } catch (NoSuchMethodException e) { - // ignore - } - } - } catch (Throwable e) { - logger.error(e.getMessage(), e); - } - } - } - } - - /** - * Should be called after Config was fully initialized. - * // FIXME: this method should be completely replaced by appendParameters - * - * @return - * @see AbstractConfig#appendParameters(Map, Object, String) - * <p> - * Notice! This method should include all properties in the returning map, treat @Parameter differently compared to appendParameters. - */ - public Map<String, String> getMetaData() { - Map<String, String> metaData = new HashMap<>(); - Method[] methods = this.getClass().getMethods(); - for (Method method : methods) { - try { - String name = method.getName(); - if ((name.startsWith("get") || name.startsWith("is")) - && !name.equals("get") - && !"getClass".equals(name) - && Modifier.isPublic(method.getModifiers()) - && method.getParameterTypes().length == 0 - && ClassHelper.isPrimitive(method.getReturnType())) { - String prop = calculateAttributeFromGetter(name); - String key; - Parameter parameter = method.getAnnotation(Parameter.class); - if (parameter != null && parameter.key().length() > 0 && parameter.useKeyAsProperty()) { - key = parameter.key(); - } else { - key = prop; - } - // treat url and configuration differently, the value should always present in configuration though it may not need to present in url. - //if (method.getReturnType() == Object.class || parameter != null && parameter.excluded()) { - if (method.getReturnType() == Object.class) { - metaData.put(key, null); - continue; - } - Object value = method.invoke(this); - String str = String.valueOf(value).trim(); - if (value != null && str.length() > 0) { - // ignore escape, keep the original value. - /*if (parameter != null && parameter.escaped()) { - str = URL.encode(str); - }*/ - if (parameter != null && parameter.append()) { - String pre = String.valueOf(metaData.get(Constants.DEFAULT_KEY + "." + key)); - if (pre != null && pre.length() > 0) { - str = pre + "," + str; - } - pre = String.valueOf(metaData.get(key)); - if (pre != null && pre.length() > 0) { - str = pre + "," + str; - } - } - /* if (prefix != null && prefix.length() > 0) { - key = prefix + "." + key; - }*/ - metaData.put(key, str); - } else { - metaData.put(key, null); - } - // TODO check required somewhere else. - /*else if (parameter != null && parameter.required()) { - throw new IllegalStateException(this.getClass().getSimpleName() + "." + key + " == null"); - }*/ - } else if ("getParameters".equals(name) - && Modifier.isPublic(method.getModifiers()) - && method.getParameterTypes().length == 0 - && method.getReturnType() == Map.class) { - Map<String, String> map = (Map<String, String>) method.invoke(this, new Object[0]); - if (map != null && map.size() > 0) { -// String pre = (prefix != null && prefix.length() > 0 ? prefix + "." : ""); - for (Map.Entry<String, String> entry : map.entrySet()) { - metaData.put(entry.getKey().replace('-', '.'), entry.getValue()); - } - } - } - } catch (Exception e) { - throw new IllegalStateException(e.getMessage(), e); - } - } - return metaData; - } - - @Parameter(excluded = true) - public String getPrefix() { - return StringUtils.isNotEmpty(prefix) ? prefix : (Constants.DUBBO + "." + getTagName(this.getClass())); - } - - public void setPrefix(String prefix) { - this.prefix = prefix; - } - - /** - * TODO: Currently, only support overriding of properties explicitly defined in Config class, doesn't support - * overriding of customized parameters stored in 'parameters'. - */ - public void refresh() { - try { - Environment env = Environment.getInstance(); - env.addAppConfig(getPrefix(), getId(), getMetaData()); - Configuration configuration = env.getConfiguration(getPrefix(), getId()); - - // loop methods, get override value and set the new value back to method - Method[] methods = getClass().getMethods(); - for (Method method : methods) { - if (ClassHelper.isSetter(method)) { - try { - String value = configuration.getString(extractPropertyName(getClass(), method)); - // isTypeMatch() is called to avoid duplicate and incorrect update, for example, we have two 'setGeneric' methods in ReferenceConfig. - if (value != null && ClassHelper.isTypeMatch(method.getParameterTypes()[0], value)) { - method.invoke(this, ClassHelper.convertPrimitive(method.getParameterTypes()[0], value)); - } - } catch (NoSuchMethodException e) { - logger.info("Failed to override the property " + method.getName() + " in " + - this.getClass().getSimpleName() + - ", please make sure every property has getter/setter method provided."); - } - } - } - } catch (Exception e) { - logger.error("Failed to override ", e); - } - } - - @Override - public String toString() { - try { - StringBuilder buf = new StringBuilder(); - buf.append("<dubbo:"); - buf.append(getTagName(getClass())); - Method[] methods = getClass().getMethods(); - for (Method method : methods) { - try { - if (ClassHelper.isGetter(method)) { - String name = method.getName(); - String key = calculateAttributeFromGetter(name); - Object value = method.invoke(this); - if (value != null) { - buf.append(" "); - buf.append(key); - buf.append("=\""); - buf.append(value); - buf.append("\""); - } - } - } catch (Exception e) { - logger.warn(e.getMessage(), e); - } - } - buf.append(" />"); - return buf.toString(); - } catch (Throwable t) { - logger.warn(t.getMessage(), t); - return super.toString(); - } - } - - /** - * FIXME check @Parameter(required=true) and any conditions that need to match. - */ - @Parameter(excluded = true) - public boolean isValid() { - return true; - } - -} +/* + * 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.config.Configuration; ++import org.apache.dubbo.common.config.Environment; +import org.apache.dubbo.common.extension.ExtensionLoader; +import org.apache.dubbo.common.logger.Logger; +import org.apache.dubbo.common.logger.LoggerFactory; ++import org.apache.dubbo.common.utils.ClassHelper; +import org.apache.dubbo.common.utils.CollectionUtils; - import org.apache.dubbo.common.utils.ConfigUtils; +import org.apache.dubbo.common.utils.ReflectUtils; +import org.apache.dubbo.common.utils.StringUtils; +import org.apache.dubbo.config.support.Parameter; +import org.apache.dubbo.rpc.model.ConsumerMethodModel; + +import java.io.Serializable; +import java.lang.reflect.Method; +import java.lang.reflect.Modifier; +import java.util.HashMap; +import java.util.Map; ++import java.util.Set; +import java.util.regex.Matcher; +import java.util.regex.Pattern; ++import java.util.stream.Collectors; + +/** + * Utility methods and public methods for parsing configuration + * + * @export + */ +public abstract class AbstractConfig implements Serializable { + + protected static final Logger logger = LoggerFactory.getLogger(AbstractConfig.class); + private static final long serialVersionUID = 4267533505537413570L; + private static final int MAX_LENGTH = 200; + + private static final int MAX_PATH_LENGTH = 200; + + private static final Pattern PATTERN_NAME = Pattern.compile("[\\-._0-9a-zA-Z]+"); + + private static final Pattern PATTERN_MULTI_NAME = Pattern.compile("[,\\-._0-9a-zA-Z]+"); + + private static final Pattern PATTERN_METHOD_NAME = Pattern.compile("[a-zA-Z][0-9a-zA-Z]*"); + + private static final Pattern PATTERN_PATH = Pattern.compile("[/\\-$._0-9a-zA-Z]+"); + + private static final Pattern PATTERN_NAME_HAS_SYMBOL = Pattern.compile("[:*,\\s/\\-._0-9a-zA-Z]+"); + + private static final Pattern PATTERN_KEY = Pattern.compile("[*,\\-._0-9a-zA-Z]+"); + private static final Map<String, String> legacyProperties = new HashMap<String, String>(); + private static final String[] SUFFIXES = new String[]{"Config", "Bean"}; + + static { + legacyProperties.put("dubbo.protocol.name", "dubbo.service.protocol"); + legacyProperties.put("dubbo.protocol.host", "dubbo.service.server.host"); + legacyProperties.put("dubbo.protocol.port", "dubbo.service.server.port"); + legacyProperties.put("dubbo.protocol.threads", "dubbo.service.max.thread.pool.size"); + legacyProperties.put("dubbo.consumer.timeout", "dubbo.service.invoke.timeout"); + legacyProperties.put("dubbo.consumer.retries", "dubbo.service.max.retry.providers"); + legacyProperties.put("dubbo.consumer.check", "dubbo.service.allow.no.provider"); + legacyProperties.put("dubbo.service.url", "dubbo.service.address"); + + // this is only for compatibility + DubboShutdownHook.getDubboShutdownHook().register(); + } + + protected String id; ++ protected String prefix; + + private static String convertLegacyValue(String key, String value) { + if (value != null && value.length() > 0) { + if ("dubbo.service.max.retry.providers".equals(key)) { + return String.valueOf(Integer.parseInt(value) - 1); + } else if ("dubbo.service.allow.no.provider".equals(key)) { + return String.valueOf(!Boolean.parseBoolean(value)); + } + } + return value; + } + - protected static void appendProperties(AbstractConfig config) { - if (config == null) { - return; - } - String prefix = "dubbo." + getTagName(config.getClass()) + "."; - Method[] methods = config.getClass().getMethods(); - for (Method method : methods) { - try { - String name = method.getName(); - if (name.length() > 3 && name.startsWith("set") && Modifier.isPublic(method.getModifiers()) - && method.getParameterTypes().length == 1 && isPrimitive(method.getParameterTypes()[0])) { - String property = StringUtils.camelToSplitName(name.substring(3, 4).toLowerCase() + name.substring(4), "."); - - String value = null; - if (config.getId() != null && config.getId().length() > 0) { - String pn = prefix + config.getId() + "." + property; - value = System.getProperty(pn); - if (!StringUtils.isBlank(value)) { - logger.info("Use System Property " + pn + " to config dubbo"); - } - } - if (value == null || value.length() == 0) { - String pn = prefix + property; - value = System.getProperty(pn); - if (!StringUtils.isBlank(value)) { - logger.info("Use System Property " + pn + " to config dubbo"); - } - } - if (value == null || value.length() == 0) { - Method getter; - try { - getter = config.getClass().getMethod("get" + name.substring(3)); - } catch (NoSuchMethodException e) { - try { - getter = config.getClass().getMethod("is" + name.substring(3)); - } catch (NoSuchMethodException e2) { - getter = null; - } - } - if (getter != null) { - if (getter.invoke(config) == null) { - if (config.getId() != null && config.getId().length() > 0) { - value = ConfigUtils.getProperty(prefix + config.getId() + "." + property); - } - if (value == null || value.length() == 0) { - value = ConfigUtils.getProperty(prefix + property); - } - if (value == null || value.length() == 0) { - String legacyKey = legacyProperties.get(prefix + property); - if (legacyKey != null && legacyKey.length() > 0) { - value = convertLegacyValue(legacyKey, ConfigUtils.getProperty(legacyKey)); - } - } - - } - } - } - if (value != null && value.length() > 0) { - method.invoke(config, convertPrimitive(method.getParameterTypes()[0], value)); - } - } - } catch (Exception e) { - logger.error(e.getMessage(), e); - } - } - } - + private static String getTagName(Class<?> cls) { + String tag = cls.getSimpleName(); + for (String suffix : SUFFIXES) { + if (tag.endsWith(suffix)) { + tag = tag.substring(0, tag.length() - suffix.length()); + break; + } + } - tag = tag.toLowerCase(); - return tag; ++ return tag.substring(0, 1).toLowerCase() + tag.substring(1); + } + + protected static void appendParameters(Map<String, String> parameters, Object config) { + appendParameters(parameters, config, null); + } + + @SuppressWarnings("unchecked") + protected static void appendParameters(Map<String, String> parameters, Object config, String prefix) { + if (config == null) { + return; + } + Method[] methods = config.getClass().getMethods(); + for (Method method : methods) { + try { + String name = method.getName(); - if ((name.startsWith("get") || name.startsWith("is")) - && !"getClass".equals(name) - && Modifier.isPublic(method.getModifiers()) - && method.getParameterTypes().length == 0 - && isPrimitive(method.getReturnType())) { ++ if (ClassHelper.isGetter(method)) { + Parameter parameter = method.getAnnotation(Parameter.class); + if (method.getReturnType() == Object.class || parameter != null && parameter.excluded()) { + continue; + } - int i = name.startsWith("get") ? 3 : 2; - String prop = StringUtils.camelToSplitName(name.substring(i, i + 1).toLowerCase() + name.substring(i + 1), "."); + String key; + if (parameter != null && parameter.key().length() > 0) { + key = parameter.key(); + } else { - key = prop; ++ key = calculatePropertyFromGetter(name); + } + Object value = method.invoke(config); + String str = String.valueOf(value).trim(); + if (value != null && str.length() > 0) { + if (parameter != null && parameter.escaped()) { + str = URL.encode(str); + } + if (parameter != null && parameter.append()) { + String pre = parameters.get(Constants.DEFAULT_KEY + "." + key); + if (pre != null && pre.length() > 0) { + str = pre + "," + str; + } + pre = parameters.get(key); + if (pre != null && pre.length() > 0) { + str = pre + "," + str; + } + } + if (prefix != null && prefix.length() > 0) { + key = prefix + "." + key; + } + parameters.put(key, str); + } else if (parameter != null && parameter.required()) { + throw new IllegalStateException(config.getClass().getSimpleName() + "." + key + " == null"); + } + } else if ("getParameters".equals(name) + && Modifier.isPublic(method.getModifiers()) + && method.getParameterTypes().length == 0 + && method.getReturnType() == Map.class) { + Map<String, String> map = (Map<String, String>) method.invoke(config, new Object[0]); + if (map != null && map.size() > 0) { + String pre = (prefix != null && prefix.length() > 0 ? prefix + "." : ""); + for (Map.Entry<String, String> entry : map.entrySet()) { + parameters.put(pre + entry.getKey().replace('-', '.'), entry.getValue()); + } + } + } + } catch (Exception e) { + throw new IllegalStateException(e.getMessage(), e); + } + } + } + + protected static void appendAttributes(Map<String, Object> parameters, Object config) { + appendAttributes(parameters, config, null); + } + + protected static void appendAttributes(Map<String, Object> parameters, Object config, String prefix) { + if (config == null) { + return; + } + Method[] methods = config.getClass().getMethods(); + for (Method method : methods) { + try { + Parameter parameter = method.getAnnotation(Parameter.class); + if (parameter == null || !parameter.attribute()) { + continue; + } + String name = method.getName(); - if ((name.startsWith("get") || name.startsWith("is")) - && !"getClass".equals(name) - && Modifier.isPublic(method.getModifiers()) - && method.getParameterTypes().length == 0 - && isPrimitive(method.getReturnType())) { ++ if (ClassHelper.isGetter(method)) { + String key; + if (parameter.key().length() > 0) { + key = parameter.key(); + } else { - int i = name.startsWith("get") ? 3 : 2; - key = name.substring(i, i + 1).toLowerCase() + name.substring(i + 1); ++ key = calculateAttributeFromGetter(name); + } + Object value = method.invoke(config); + if (value != null) { + if (prefix != null && prefix.length() > 0) { + key = prefix + "." + key; + } + parameters.put(key, value); + } + } + } catch (Exception e) { + throw new IllegalStateException(e.getMessage(), e); + } + } + } + + protected static ConsumerMethodModel.AsyncMethodInfo convertMethodConfig2AyncInfo(MethodConfig methodConfig) { + if (methodConfig == null || (methodConfig.getOninvoke() == null && methodConfig.getOnreturn() == null && methodConfig.getOnthrow() == null)) { + return null; + } + + //check config conflict + if (Boolean.FALSE.equals(methodConfig.isReturn()) && (methodConfig.getOnreturn() != null || methodConfig.getOnthrow() != null)) { + throw new IllegalStateException("method config error : return attribute must be set true when onreturn or onthrow has been set."); + } + + ConsumerMethodModel.AsyncMethodInfo asyncMethodInfo = new ConsumerMethodModel.AsyncMethodInfo(); + + asyncMethodInfo.setOninvokeInstance(methodConfig.getOninvoke()); + asyncMethodInfo.setOnreturnInstance(methodConfig.getOnreturn()); + asyncMethodInfo.setOnthrowInstance(methodConfig.getOnthrow()); + + try { + String oninvokeMethod = methodConfig.getOninvokeMethod(); + if (StringUtils.isNotEmpty(oninvokeMethod)) { + asyncMethodInfo.setOninvokeMethod(getMethodByName(methodConfig.getOninvoke().getClass(), oninvokeMethod)); + } + + String onreturnMethod = methodConfig.getOnreturnMethod(); + if (StringUtils.isNotEmpty(onreturnMethod)) { + asyncMethodInfo.setOnreturnMethod(getMethodByName(methodConfig.getOnreturn().getClass(), onreturnMethod)); + } + + String onthrowMethod = methodConfig.getOnthrowMethod(); + if (StringUtils.isNotEmpty(onthrowMethod)) { + asyncMethodInfo.setOnthrowMethod(getMethodByName(methodConfig.getOnthrow().getClass(), onthrowMethod)); + } + } catch (Exception e) { + throw new IllegalStateException(e.getMessage(), e); + } + + return asyncMethodInfo; + } + + private static Method getMethodByName(Class<?> clazz, String methodName) { + try { + return ReflectUtils.findMethodByMethodName(clazz, methodName); + } catch (Exception e) { + throw new IllegalStateException(e); + } + } + - private static boolean isPrimitive(Class<?> type) { - return type.isPrimitive() - || type == String.class - || type == Character.class - || type == Boolean.class - || type == Byte.class - || type == Short.class - || type == Integer.class - || type == Long.class - || type == Float.class - || type == Double.class - || type == Object.class; - } - - private static Object convertPrimitive(Class<?> type, String value) { - if (type == char.class || type == Character.class) { - return value.length() > 0 ? value.charAt(0) : '\0'; - } else if (type == boolean.class || type == Boolean.class) { - return Boolean.valueOf(value); - } else if (type == byte.class || type == Byte.class) { - return Byte.valueOf(value); - } else if (type == short.class || type == Short.class) { - return Short.valueOf(value); - } else if (type == int.class || type == Integer.class) { - return Integer.valueOf(value); - } else if (type == long.class || type == Long.class) { - return Long.valueOf(value); - } else if (type == float.class || type == Float.class) { - return Float.valueOf(value); - } else if (type == double.class || type == Double.class) { - return Double.valueOf(value); ++ /** ++ * We only check boolean value at this moment. ++ * ++ * @param type ++ * @param value ++ * @return ++ */ ++ private static boolean isTypeMatch(Class<?> type, String value) { ++ if ((type == boolean.class || type == Boolean.class) ++ && !("true".equals(value) || "false".equals(value))) { ++ return false; + } - return value; ++ return true; + } + + protected static void checkExtension(Class<?> type, String property, String value) { + checkName(property, value); + if (value != null && value.length() > 0 + && !ExtensionLoader.getExtensionLoader(type).hasExtension(value)) { + throw new IllegalStateException("No such extension " + value + " for " + property + "/" + type.getName()); + } + } + + protected static void checkMultiExtension(Class<?> type, String property, String value) { + checkMultiName(property, value); + if (value != null && value.length() > 0) { + String[] values = value.split("\\s*[,]+\\s*"); + for (String v : values) { + if (v.startsWith(Constants.REMOVE_VALUE_PREFIX)) { + v = v.substring(1); + } + if (Constants.DEFAULT_KEY.equals(v)) { + continue; + } + if (!ExtensionLoader.getExtensionLoader(type).hasExtension(v)) { + throw new IllegalStateException("No such extension " + v + " for " + property + "/" + type.getName()); + } + } + } + } + + protected static void checkLength(String property, String value) { + checkProperty(property, value, MAX_LENGTH, null); + } + + protected static void checkPathLength(String property, String value) { + checkProperty(property, value, MAX_PATH_LENGTH, null); + } + + protected static void checkName(String property, String value) { + checkProperty(property, value, MAX_LENGTH, PATTERN_NAME); + } + + protected static void checkNameHasSymbol(String property, String value) { + checkProperty(property, value, MAX_LENGTH, PATTERN_NAME_HAS_SYMBOL); + } + + protected static void checkKey(String property, String value) { + checkProperty(property, value, MAX_LENGTH, PATTERN_KEY); + } + + protected static void checkMultiName(String property, String value) { + checkProperty(property, value, MAX_LENGTH, PATTERN_MULTI_NAME); + } + + protected static void checkPathName(String property, String value) { + checkProperty(property, value, MAX_PATH_LENGTH, PATTERN_PATH); + } + + protected static void checkMethodName(String property, String value) { + checkProperty(property, value, MAX_LENGTH, PATTERN_METHOD_NAME); + } + + protected static void checkParameterName(Map<String, String> parameters) { + if (parameters == null || parameters.size() == 0) { + return; + } + for (Map.Entry<String, String> entry : parameters.entrySet()) { + checkNameHasSymbol(entry.getKey(), entry.getValue()); + } + } + + protected static void checkProperty(String property, String value, int maxlength, Pattern pattern) { + if (value == null || value.length() == 0) { + return; + } + if (value.length() > maxlength) { + throw new IllegalStateException("Invalid " + property + "=\"" + value + "\" is longer than " + maxlength); + } + if (pattern != null) { + Matcher matcher = pattern.matcher(value); + if (!matcher.matches()) { + throw new IllegalStateException("Invalid " + property + "=\"" + value + "\" contains illegal " + + "character, only digit, letter, '-', '_' or '.' is legal."); + } + } + } + ++ protected static Set<String> getSubProperties(Map<String, String> properties, String prefix) { ++ return properties.keySet().stream().filter(k -> k.contains(prefix)).map(k -> { ++ k = k.substring(prefix.length()); ++ return k.substring(0, k.indexOf(".")); ++ }).collect(Collectors.toSet()); ++ } ++ ++ private static String extractPropertyName(Class<?> clazz, Method setter) throws Exception { ++ String propertyName = setter.getName().substring("set".length()); ++ Method getter = null; ++ try { ++ getter = clazz.getMethod("get" + propertyName); ++ } catch (NoSuchMethodException e) { ++ getter = clazz.getMethod("is" + propertyName); ++ } ++ Parameter parameter = getter.getAnnotation(Parameter.class); ++ if (parameter != null && StringUtils.isNotEmpty(parameter.key()) && parameter.useKeyAsProperty()) { ++ propertyName = parameter.key(); ++ } else { ++ propertyName = propertyName.substring(0, 1).toLowerCase() + propertyName.substring(1); ++ } ++ return propertyName; ++ } ++ ++ private static String calculatePropertyFromGetter(String name) { ++ int i = name.startsWith("get") ? 3 : 2; ++ return StringUtils.camelToSplitName(name.substring(i, i + 1).toLowerCase() + name.substring(i + 1), "."); ++ } ++ ++ private static String calculateAttributeFromGetter(String getter) { ++ int i = getter.startsWith("get") ? 3 : 2; ++ return getter.substring(i, i + 1).toLowerCase() + getter.substring(i + 1); ++ } ++ + @Parameter(excluded = true) + public String getId() { + return id; + } + + public void setId(String id) { + this.id = id; + } + ++ public void updateIdIfAbsent(String value) { ++ if (StringUtils.isNotEmpty(value) && StringUtils.isEmpty(id)) { ++ this.id = value; ++ } ++ } ++ + protected void appendAnnotation(Class<?> annotationClass, Object annotation) { + Method[] methods = annotationClass.getMethods(); + for (Method method : methods) { + if (method.getDeclaringClass() != Object.class + && method.getReturnType() != void.class + && method.getParameterTypes().length == 0 + && Modifier.isPublic(method.getModifiers()) + && !Modifier.isStatic(method.getModifiers())) { + try { + String property = method.getName(); + if ("interfaceClass".equals(property) || "interfaceName".equals(property)) { + property = "interface"; + } + String setter = "set" + property.substring(0, 1).toUpperCase() + property.substring(1); + Object value = method.invoke(annotation); + if (value != null && !value.equals(method.getDefaultValue())) { + Class<?> parameterType = ReflectUtils.getBoxedClass(method.getReturnType()); + if ("filter".equals(property) || "listener".equals(property)) { + parameterType = String.class; + value = StringUtils.join((String[]) value, ","); + } else if ("parameters".equals(property)) { + parameterType = Map.class; + value = CollectionUtils.toStringMap((String[]) value); + } + try { + Method setterMethod = getClass().getMethod(setter, parameterType); + setterMethod.invoke(this, value); + } catch (NoSuchMethodException e) { + // ignore + } + } + } catch (Throwable e) { + logger.error(e.getMessage(), e); + } + } + } + } + ++ /** ++ * Should be called after Config was fully initialized. ++ * // FIXME: this method should be completely replaced by appendParameters ++ * ++ * @return ++ * @see AbstractConfig#appendParameters(Map, Object, String) ++ * <p> ++ * Notice! This method should include all properties in the returning map, treat @Parameter differently compared to appendParameters. ++ */ ++ public Map<String, String> getMetaData() { ++ Map<String, String> metaData = new HashMap<>(); ++ Method[] methods = this.getClass().getMethods(); ++ for (Method method : methods) { ++ try { ++ String name = method.getName(); ++ if ((name.startsWith("get") || name.startsWith("is")) ++ && !name.equals("get") ++ && !"getClass".equals(name) ++ && Modifier.isPublic(method.getModifiers()) ++ && method.getParameterTypes().length == 0 ++ && ClassHelper.isPrimitive(method.getReturnType())) { ++ String prop = calculateAttributeFromGetter(name); ++ String key; ++ Parameter parameter = method.getAnnotation(Parameter.class); ++ if (parameter != null && parameter.key().length() > 0 && parameter.useKeyAsProperty()) { ++ key = parameter.key(); ++ } else { ++ key = prop; ++ } ++ // treat url and configuration differently, the value should always present in configuration though it may not need to present in url. ++ //if (method.getReturnType() == Object.class || parameter != null && parameter.excluded()) { ++ if (method.getReturnType() == Object.class) { ++ metaData.put(key, null); ++ continue; ++ } ++ Object value = method.invoke(this); ++ String str = String.valueOf(value).trim(); ++ if (value != null && str.length() > 0) { ++ // ignore escape, keep the original value. ++ /*if (parameter != null && parameter.escaped()) { ++ str = URL.encode(str); ++ }*/ ++ if (parameter != null && parameter.append()) { ++ String pre = String.valueOf(metaData.get(Constants.DEFAULT_KEY + "." + key)); ++ if (pre != null && pre.length() > 0) { ++ str = pre + "," + str; ++ } ++ pre = String.valueOf(metaData.get(key)); ++ if (pre != null && pre.length() > 0) { ++ str = pre + "," + str; ++ } ++ } ++ /* if (prefix != null && prefix.length() > 0) { ++ key = prefix + "." + key; ++ }*/ ++ metaData.put(key, str); ++ } else { ++ metaData.put(key, null); ++ } ++ // TODO check required somewhere else. ++ /*else if (parameter != null && parameter.required()) { ++ throw new IllegalStateException(this.getClass().getSimpleName() + "." + key + " == null"); ++ }*/ ++ } else if ("getParameters".equals(name) ++ && Modifier.isPublic(method.getModifiers()) ++ && method.getParameterTypes().length == 0 ++ && method.getReturnType() == Map.class) { ++ Map<String, String> map = (Map<String, String>) method.invoke(this, new Object[0]); ++ if (map != null && map.size() > 0) { ++// String pre = (prefix != null && prefix.length() > 0 ? prefix + "." : ""); ++ for (Map.Entry<String, String> entry : map.entrySet()) { ++ metaData.put(entry.getKey().replace('-', '.'), entry.getValue()); ++ } ++ } ++ } ++ } catch (Exception e) { ++ throw new IllegalStateException(e.getMessage(), e); ++ } ++ } ++ return metaData; ++ } ++ ++ @Parameter(excluded = true) ++ public String getPrefix() { ++ return StringUtils.isNotEmpty(prefix) ? prefix : (Constants.DUBBO + "." + getTagName(this.getClass())); ++ } ++ ++ public void setPrefix(String prefix) { ++ this.prefix = prefix; ++ } ++ ++ /** ++ * TODO: Currently, only support overriding of properties explicitly defined in Config class, doesn't support ++ * overriding of customized parameters stored in 'parameters'. ++ */ ++ public void refresh() { ++ try { ++ Environment env = Environment.getInstance(); ++ env.addAppConfig(getPrefix(), getId(), getMetaData()); ++ Configuration configuration = env.getConfiguration(getPrefix(), getId()); ++ ++ // loop methods, get override value and set the new value back to method ++ Method[] methods = getClass().getMethods(); ++ for (Method method : methods) { ++ if (ClassHelper.isSetter(method)) { ++ try { ++ String value = configuration.getString(extractPropertyName(getClass(), method)); ++ // isTypeMatch() is called to avoid duplicate and incorrect update, for example, we have two 'setGeneric' methods in ReferenceConfig. ++ if (value != null && ClassHelper.isTypeMatch(method.getParameterTypes()[0], value)) { ++ method.invoke(this, ClassHelper.convertPrimitive(method.getParameterTypes()[0], value)); ++ } ++ } catch (NoSuchMethodException e) { ++ logger.info("Failed to override the property " + method.getName() + " in " + ++ this.getClass().getSimpleName() + ++ ", please make sure every property has getter/setter method provided."); ++ } ++ } ++ } ++ } catch (Exception e) { ++ logger.error("Failed to override ", e); ++ } ++ } ++ + @Override + public String toString() { + try { + StringBuilder buf = new StringBuilder(); + buf.append("<dubbo:"); + buf.append(getTagName(getClass())); + Method[] methods = getClass().getMethods(); + for (Method method : methods) { + try { - String name = method.getName(); - if ((name.startsWith("get") || name.startsWith("is")) - && !"get".equals(name) && !"is".equals(name) - && !"getClass".equals(name) && !"getObject".equals(name) - && Modifier.isPublic(method.getModifiers()) - && method.getParameterTypes().length == 0 - && isPrimitive(method.getReturnType())) { - int i = name.startsWith("get") ? 3 : 2; - String key = name.substring(i, i + 1).toLowerCase() + name.substring(i + 1); ++ if (ClassHelper.isGetter(method)) { ++ String name = method.getName(); ++ String key = calculateAttributeFromGetter(name); + Object value = method.invoke(this); + if (value != null) { + buf.append(" "); + buf.append(key); + buf.append("=\""); + buf.append(value); + buf.append("\""); + } + } + } catch (Exception e) { + logger.warn(e.getMessage(), e); + } + } + buf.append(" />"); + return buf.toString(); + } catch (Throwable t) { + logger.warn(t.getMessage(), t); + return super.toString(); + } + } + ++ /** ++ * FIXME check @Parameter(required=true) and any conditions that need to match. ++ */ ++ @Parameter(excluded = true) ++ public boolean isValid() { ++ return true; ++ } ++ +} diff --cc dubbo-config/dubbo-config-api/src/main/java/org/apache/dubbo/config/DubboShutdownHook.java index 57535ac,06c9e12..22d50dd --- a/dubbo-config/dubbo-config-api/src/main/java/org/apache/dubbo/config/DubboShutdownHook.java +++ b/dubbo-config/dubbo-config-api/src/main/java/org/apache/dubbo/config/DubboShutdownHook.java @@@ -35,24 -35,20 +35,23 @@@ public class DubboShutdownHook extends private static final Logger logger = LoggerFactory.getLogger(DubboShutdownHook.class); private static final DubboShutdownHook dubboShutdownHook = new DubboShutdownHook("DubboShutdownHook"); - - public static DubboShutdownHook getDubboShutdownHook() { - return dubboShutdownHook; - } - /** + * Has it already been registered or not? + */ + private final AtomicBoolean registered = new AtomicBoolean(false); + /** * Has it already been destroyed or not? */ - private final AtomicBoolean destroyed; + private final AtomicBoolean destroyed= new AtomicBoolean(false); private DubboShutdownHook(String name) { super(name); - this.destroyed = new AtomicBoolean(false); } + public static DubboShutdownHook getDubboShutdownHook() { + return dubboShutdownHook; + } + @Override public void run() { if (logger.isInfoEnabled()) { diff --cc dubbo-config/dubbo-config-api/src/main/java/org/apache/dubbo/config/ReferenceConfig.java index 7ec277d,2389b33..5144fc2 --- 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 @@@ -490,46 -552,10 +513,52 @@@ public class ReferenceConfig<T> extend return buf.toString(); } + @Override + @Parameter(excluded = true) + public String getPrefix() { + return Constants.DUBBO + ".reference." + interfaceName; + } + + private void resolveFile() { + String resolve = System.getProperty(interfaceName); + String resolveFile = null; + if (resolve == null || resolve.length() == 0) { + resolveFile = System.getProperty("dubbo.resolve.file"); + if (resolveFile == null || resolveFile.length() == 0) { + File userResolveFile = new File(new File(System.getProperty("user.home")), "dubbo-resolve.properties"); + if (userResolveFile.exists()) { + resolveFile = userResolveFile.getAbsolutePath(); + } + } + if (resolveFile != null && resolveFile.length() > 0) { + Properties properties = new Properties(); + FileInputStream fis = null; + try { + fis = new FileInputStream(new File(resolveFile)); + properties.load(fis); + } catch (IOException e) { + throw new IllegalStateException("Unload " + resolveFile + ", cause: " + e.getMessage(), e); + } finally { + try { + if (null != fis) { + fis.close(); + } + } catch (IOException e) { + logger.warn(e.getMessage(), e); + } + } + resolve = properties.getProperty(interfaceName); + } + } + if (resolve != null && resolve.length() > 0) { + url = resolve; + if (logger.isWarnEnabled()) { + if (resolveFile != null) { + logger.warn("Using default dubbo resolve file " + resolveFile + " replace " + interfaceName + "" + resolve + " to p2p invoke remote service."); + } else { + logger.warn("Using -D" + interfaceName + "=" + resolve + " to p2p invoke remote service."); + } + } + } + } } diff --cc dubbo-config/dubbo-config-api/src/main/java/org/apache/dubbo/config/ServiceConfig.java index 37539eb,fc5d251..1d20a57 --- 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 @@@ -301,12 -285,46 +286,41 @@@ public class ServiceConfig<T> extends A throw new IllegalStateException("The stub implementation class " + stubClass.getName() + " not implement interface " + interfaceName); } } - checkApplication(); - checkRegistry(); - checkProtocol(); - appendProperties(this); checkStub(interfaceClass); checkMock(interfaceClass); + } + + public synchronized void export() { + checkAndUpdateSubConfigs(); + + if (provider != null) { + if (export == null) { + export = provider.getExport(); + } + if (delay == null) { + delay = provider.getDelay(); + } + } + if (export != null && !export) { + return; + } + + if (delay != null && delay > 0) { - delayExportExecutor.schedule(new Runnable() { - @Override - public void run() { - doExport(); - } - }, delay, TimeUnit.MILLISECONDS); ++ delayExportExecutor.schedule(this::doExport, delay, TimeUnit.MILLISECONDS); + } else { + doExport(); + } + } + + protected synchronized void doExport() { + if (unexported) { + throw new IllegalStateException("Already unexported!"); + } + if (exported) { + return; + } + exported = true; + if (path == null || path.length() == 0) { path = interfaceName; } diff --cc dubbo-config/dubbo-config-api/src/test/resources/log4j.xml index 5007dd1,8607f5d..bfc37a8 --- a/dubbo-config/dubbo-config-api/src/test/resources/log4j.xml +++ b/dubbo-config/dubbo-config-api/src/test/resources/log4j.xml @@@ -1,28 -1,28 +1,28 @@@ - <!-- - Licensed to the Apache Software Foundation (ASF) under one or more - contributor license agreements. See the NOTICE file distributed with - this work for additional information regarding copyright ownership. - The ASF licenses this file to You under the Apache License, Version 2.0 - (the "License"); you may not use this file except in compliance with - the License. You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - - Unless required by applicable law or agreed to in writing, software - distributed under the License is distributed on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - See the License for the specific language governing permissions and - limitations under the License. - --> - <!DOCTYPE log4j:configuration SYSTEM "log4j.dtd"> - <log4j:configuration xmlns:log4j="http://jakarta.apache.org/log4j/" debug="false"> - <appender name="CONSOLE" class="org.apache.log4j.ConsoleAppender"> - <layout class="org.apache.log4j.PatternLayout"> - <param name="ConversionPattern" value="[%d{dd/MM/yy HH:mm:ss:SSS z}] %t %5p %c{2}: %m%n"/> - </layout> - </appender> - <root> - <level value="INFO"/> - <appender-ref ref="CONSOLE"/> - </root> + <!-- + 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. + --> + <!DOCTYPE log4j:configuration SYSTEM "log4j.dtd"> + <log4j:configuration xmlns:log4j="http://jakarta.apache.org/log4j/" debug="false"> + <appender name="CONSOLE" class="org.apache.log4j.ConsoleAppender"> + <layout class="org.apache.log4j.PatternLayout"> - <param name="ConversionPattern" value="[%d{dd/MM/yy hh:mm:ss:sss z}] %t %5p %c{2}: %m%n"/> ++ <param name="ConversionPattern" value="[%d{dd/MM/yy HH:mm:ss:SSS z}] %t %5p %c{2}: %m%n"/> + </layout> + </appender> + <root> + <level value="INFO"/> + <appender-ref ref="CONSOLE"/> + </root> </log4j:configuration> diff --cc dubbo-registry/dubbo-registry-api/src/main/java/org/apache/dubbo/registry/support/ProviderConsumerRegTable.java index 5149760,3f3f018..620c534 --- a/dubbo-registry/dubbo-registry-api/src/main/java/org/apache/dubbo/registry/support/ProviderConsumerRegTable.java +++ b/dubbo-registry/dubbo-registry-api/src/main/java/org/apache/dubbo/registry/support/ProviderConsumerRegTable.java @@@ -23,10 -22,10 +22,12 @@@ import org.apache.dubbo.registry.integr import org.apache.dubbo.rpc.Invoker; import java.util.Collections; +import java.util.Map; +import java.util.Objects; + import java.util.HashSet; import java.util.Set; import java.util.concurrent.ConcurrentHashMap; + import java.util.concurrent.ConcurrentMap; /** * @date 2017/11/23 diff --cc dubbo-registry/dubbo-registry-default/src/test/java/org/apache/dubbo/registry/dubbo/RegistryDirectoryTest.java index 8c8b8ea,3a65eb9..b271773 --- a/dubbo-registry/dubbo-registry-default/src/test/java/org/apache/dubbo/registry/dubbo/RegistryDirectoryTest.java +++ b/dubbo-registry/dubbo-registry-default/src/test/java/org/apache/dubbo/registry/dubbo/RegistryDirectoryTest.java @@@ -29,12 -29,10 +29,10 @@@ import org.apache.dubbo.rpc.Invoker import org.apache.dubbo.rpc.Protocol; import org.apache.dubbo.rpc.RpcException; import org.apache.dubbo.rpc.RpcInvocation; - import org.apache.dubbo.rpc.cluster.Router; import org.apache.dubbo.rpc.cluster.loadbalance.LeastActiveLoadBalance; import org.apache.dubbo.rpc.cluster.loadbalance.RoundRobinLoadBalance; - import org.apache.dubbo.rpc.cluster.router.script.ScriptRouter; import org.apache.dubbo.rpc.cluster.router.script.ScriptRouterFactory; - +import org.apache.dubbo.rpc.cluster.support.wrapper.MockClusterInvoker; import org.junit.Assert; import org.junit.Before; import org.junit.Test; diff --cc dubbo-rpc/dubbo-rpc-api/src/main/java/org/apache/dubbo/rpc/model/ApplicationModel.java index 26669ce,7c63bc7..cfad21c --- a/dubbo-rpc/dubbo-rpc-api/src/main/java/org/apache/dubbo/rpc/model/ApplicationModel.java +++ b/dubbo-rpc/dubbo-rpc-api/src/main/java/org/apache/dubbo/rpc/model/ApplicationModel.java @@@ -73,11 -75,11 +75,19 @@@ public class ApplicationModel } } + public static String getApplication() { + return application; + } + + public static void setApplication(String application) { + ApplicationModel.application = application; + } ++ + /** + * For unit test + */ + public static void reset() { + providedServices.clear(); + consumedServices.clear(); + } } diff --cc dubbo-rpc/dubbo-rpc-dubbo/src/test/java/org/apache/dubbo/rpc/protocol/dubbo/DubboInvokerAvilableTest.java index 14ab124,4addbf3..08444f7 --- a/dubbo-rpc/dubbo-rpc-dubbo/src/test/java/org/apache/dubbo/rpc/protocol/dubbo/DubboInvokerAvilableTest.java +++ b/dubbo-rpc/dubbo-rpc-dubbo/src/test/java/org/apache/dubbo/rpc/protocol/dubbo/DubboInvokerAvilableTest.java @@@ -97,7 -92,7 +97,6 @@@ public class DubboInvokerAvilableTest try{ System.setProperty(Constants.SHUTDOWN_WAIT_KEY, "2000"); - System.out.println("------------ConfigUtils.getServerShutdownTimeout(): " + ConfigUtils.getServerShutdownTimeout()); - System.out.println("------------ConfigUtils.getServerShutdownTimeout(): " + ConfigurationUtils.getServerShutdownTimeout()); protocol.destroy(); }finally { System.getProperties().remove(Constants.SHUTDOWN_WAIT_KEY);
