This is an automated email from the ASF dual-hosted git repository. liujun pushed a commit to branch dev-metadata in repository https://gitbox.apache.org/repos/asf/incubator-dubbo.git
commit dbca54ca237b16e157ada4aa2b98eb29117fb2ba Merge: d11b876 38a6511 Author: ken.lj <[email protected]> AuthorDate: Thu Nov 15 11:33:24 2018 +0800 Merge branch 'master' into dev-metadata # Conflicts: # dubbo-all/pom.xml # dubbo-bootstrap/pom.xml # dubbo-bootstrap/src/main/java/org/apache/dubbo/bootstrap/DubboBootstrap.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/AbstractInterfaceConfig.java # dubbo-config/dubbo-config-api/src/main/java/org/apache/dubbo/config/ProtocolConfig.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-spring/src/main/java/org/apache/dubbo/config/spring/ServiceBean.java # dubbo-config/dubbo-config-spring/src/main/java/org/apache/dubbo/config/spring/context/annotation/DubboConfigConfiguration.java # dubbo-config/dubbo-config-spring/src/test/java/org/apache/dubbo/config/spring/initializer/DubboApplicationListenerTest.java # dubbo-demo/dubbo-demo-consumer/src/main/java/org/apache/dubbo/demo/consumer/Consumer.java README.md | 2 + codestyle/checkstyle.xml | 6 + codestyle/dubbo_codestyle_for_idea.xml | 2 - dubbo-bom/pom.xml | 5 - .../apache/dubbo/config/AbstractConfigTest.java | 3 +- .../dubbo/config/AbstractInterfaceConfigTest.java | 27 ++-- .../dubbo/config/AbstractMethodConfigTest.java | 7 + .../org/apache/dubbo/config/ServiceConfigTest.java | 12 ++ .../java/org/apache/dubbo/common/Constants.java | 17 +++ .../org/apache/dubbo/common/compiler/Compiler.java | 1 - .../common/compiler/support/AdaptiveCompiler.java | 1 - .../dubbo/common/extension/DisableInject.java | 16 ++- .../dubbo/common/extension/ExtensionLoader.java | 21 ++- .../apache/dubbo/common/logger/jcl/JclLogger.java | 1 + .../dubbo/common/logger/jcl/JclLoggerAdapter.java | 1 + .../support/eager/EagerThreadPoolExecutor.java | 2 +- .../dubbo/common/timer/HashedWheelTimer.java | 13 +- .../java/org/apache/dubbo/common/timer/Timer.java | 7 + .../Compiler.java => utils/ArrayUtils.java} | 84 ++++++------ .../org/apache/dubbo/common/utils/StringUtils.java | 118 +++++++++++------ .../common/extension/ExtensionLoaderTest.java | 13 +- .../common/extension/injection/InjectExt.java | 13 +- .../extension/injection/impl/InjectExtImpl.java | 60 +++++++++ .../apache/dubbo/common/utils/ArrayUtilsTest.java | 38 +++--- .../apache/dubbo/common/utils/StringUtilsTest.java | 30 ++++- ...ache.dubbo.common.extension.injection.InjectExt | 1 + .../main/java/com/alibaba/dubbo/common/URL.java | 103 ++++++++++++++- .../alibaba/dubbo/common/status/StatusChecker.java | 1 + .../spring/context/annotation/EnableDubbo.java | 1 + .../java/com/alibaba/dubbo/monitor/Monitor.java | 1 + .../java/com/alibaba/dubbo/registry/Registry.java | 1 + .../java/com/alibaba/dubbo/remoting/Channel.java | 2 + .../main/java/com/alibaba/dubbo/rpc/Exporter.java | 1 + .../main/java/com/alibaba/dubbo/rpc/Filter.java | 1 + .../java/com/alibaba/dubbo/rpc/Invocation.java | 2 + .../main/java/com/alibaba/dubbo/rpc/Invoker.java | 2 + .../com/alibaba/dubbo/rpc/cluster/Directory.java | 5 +- .../java/com/alibaba/dubbo/rpc/cluster/Router.java | 1 + ...atibleReferenceAnnotationBeanPostProcessor.java | 4 +- .../annotation/CompatibleReferenceBeanBuilder.java | 4 +- ...mpatibleServiceAnnotationBeanPostProcessor.java | 4 +- .../CompatibleDubboComponentScanRegistrar.java | 1 + .../CompatibleAnnotationBeanDefinitionParser.java | 3 +- .../org/apache/dubbo/config/AbstractConfig.java | 5 +- .../dubbo/config/AbstractInterfaceConfig.java | 51 +++++--- .../apache/dubbo/config/AbstractMethodConfig.java | 23 +++- .../org/apache/dubbo/config/ProtocolConfig.java | 2 +- .../org/apache/dubbo/config/ReferenceConfig.java | 3 +- .../org/apache/dubbo/config/ServiceConfig.java | 13 +- dubbo-config/dubbo-config-spring/pom.xml | 7 +- .../apache/dubbo/config/spring/AnnotationBean.java | 24 ++-- .../apache/dubbo/config/spring/ReferenceBean.java | 1 + .../apache/dubbo/config/spring/ServiceBean.java | 29 +---- .../AbstractAnnotationConfigBeanBuilder.java | 1 + .../DubboConfigBindingBeanPostProcessor.java | 1 + .../ReferenceAnnotationBeanPostProcessor.java | 9 +- .../factory/annotation/ReferenceBeanBuilder.java | 1 + .../ServiceAnnotationBeanPostProcessor.java | 5 +- .../context/annotation/DubboComponentScan.java | 1 + .../annotation/DubboComponentScanRegistrar.java | 1 + .../annotation/DubboConfigBindingRegistrar.java | 1 + .../annotation/DubboConfigBindingsRegistrar.java | 1 + .../DubboConfigConfigurationSelector.java | 1 + .../spring/context/annotation/EnableDubbo.java | 1 + .../context/annotation/EnableDubboConfig.java | 1 + .../annotation/EnableDubboConfigBinding.java | 1 + .../properties/DefaultDubboConfigBinder.java | 1 + .../context/properties/DubboConfigBinder.java | 1 + .../converter/StringArrayToMapConverter.java | 1 + .../spring/extension/SpringExtensionFactory.java | 33 ++++- .../DubboApplicationContextInitializer.java | 39 ------ .../initializer/DubboApplicationListener.java | 49 ------- .../spring/initializer/DubboContextListener.java | 72 ---------- .../schema/AnnotationBeanDefinitionParser.java | 1 + .../spring/schema/DubboNamespaceHandler.java | 1 + .../spring/status/DataSourceStatusChecker.java | 1 + .../config/spring/status/SpringStatusChecker.java | 1 + .../dubbo/config/spring/util/BeanFactoryUtils.java | 28 ++++ .../src/main/resources/META-INF/compat/dubbo.xsd | 10 ++ .../src/main/resources/META-INF/dubbo.xsd | 10 ++ .../src/main/resources/META-INF/web-fragment.xml | 22 ---- .../org/apache/dubbo/config/spring/ConfigTest.java | 33 +++++ .../annotation/provider/HelloServiceImpl.java | 2 +- .../DubboApplicationContextInitializerTest.java | 88 ------------- .../initializer/DubboApplicationListenerTest.java | 59 --------- dubbo-container/dubbo-container-spring/pom.xml | 7 +- .../dubbo/container/spring/SpringContainer.java | 6 +- dubbo-distribution/pom.xml | 5 - .../org/apache/dubbo/cache/filter/CacheFilter.java | 4 +- .../dubbo/cache/support/expiring/ExpiringMap.java | 2 +- .../cache/support/jcache/JCacheFactoryTest.java | 2 +- .../org/apache/dubbo/metrics/MetricRegistry.java | 1 - .../dubbo/qos/protocol/QosProtocolWrapper.java | 9 +- .../java/org/apache/dubbo/qos/server/Server.java | 1 + .../qos/server/handler/HttpProcessHandler.java | 1 + .../qos/server/handler/LocalHostPermitHandler.java | 1 - .../qos/server/handler/TelnetProcessHandler.java | 1 - .../java/org/apache/dubbo/qos/textui/TTable.java | 6 +- .../java/org/apache/dubbo/qos/textui/TTree.java | 2 +- .../registry/support/FailbackRegistryTest.java | 23 ++++ .../exchange/support/header/AbstractTimerTask.java | 87 +++++++++++++ .../support/header/HeaderExchangeClient.java | 67 +++++----- .../support/header/HeaderExchangeServer.java | 76 +++++------ .../exchange/support/header/HeartBeatTask.java | 97 -------------- .../support/header/HeartbeatTimerTask.java | 62 +++++++++ .../support/header/ReconnectTimerTask.java | 61 +++++++++ .../telnet/support/command/LogTelnetHandler.java | 1 - .../transport/dispatcher/ChannelHandlers.java | 1 - .../exchange/support/header/HeartBeatTaskTest.java | 29 +++-- .../support/header/HeartbeatHandlerTest.java | 8 +- .../transport/netty/NettyClientToServerTest.java | 11 +- .../transport/netty4/NettyBackedChannelBuffer.java | 1 + .../transport/netty4/NettyClientHandler.java | 4 +- .../transport/netty4/NettyServerHandler.java | 2 +- .../transport/netty4/logging/MessageFormatter.java | 1 - .../transport/netty4/NettyClientToServerTest.java | 11 +- .../zookeeper/zkclient/ZkClientWrapper.java | 7 +- .../alibaba/dubbo/rpc/service/GenericService.java | 1 + .../java/org/apache/dubbo/rpc/AbstractResult.java | 1 + .../org/apache/dubbo/rpc/AsyncContextImpl.java | 1 + .../java/org/apache/dubbo/rpc/AsyncRpcResult.java | 1 + .../apache/dubbo/rpc/filter/AccessLogFilter.java | 3 +- .../dubbo/rpc/proxy/AbstractProxyFactory.java | 4 +- .../org/apache/dubbo/rpc/support/MockInvoker.java | 145 +++++++++++++-------- .../rpc/protocol/dubbo/filter/TraceFilter.java | 1 + .../protocol/dubbo/telnet/InvokeTelnetHandler.java | 1 + .../protocol/dubbo/telnet/LogTelnetHandler.java | 1 - .../rpc/protocol/dubbo/DubboProtocolTest.java | 9 +- .../dubbo/ReferenceCountExchangeClientTest.java | 7 + .../hessian/DubboHessianURLConnectionFactory.java | 1 + .../rpc/protocol/hessian/HessianProtocol.java | 2 +- .../dubbo/rpc/protocol/http/HttpProtocol.java | 1 + .../rpc/protocol/http/HttpRemoteInvocation.java | 1 + .../dubbo/rpc/protocol/rest/RpcContextFilter.java | 1 + .../swagger/DubboSwaggerApiListingResource.java | 7 +- .../integration/swagger/DubboSwaggerService.java | 2 +- .../rpc/protocol/rmi/RmiRemoteInvocation.java | 1 + .../dubbo/rpc/protocol/thrift/ThriftCodec.java | 1 - .../serialize/fastjson/FastJsonObjectOutput.java | 1 + .../dubbo/common/serialize/fst/FstFactory.java | 1 + .../serialize/hessian2/Hessian2ObjectInput.java | 3 +- .../serialize/hessian2/Hessian2ObjectOutput.java | 3 +- .../common/serialize/java/JavaObjectOutput.java | 1 - .../common/serialize/kryo/CompatibleKryo.java | 7 +- .../serialize/kryo/utils/AbstractKryoFactory.java | 5 +- .../protostuff/ProtostuffObjectInput.java | 5 +- .../protostuff/ProtostuffObjectOutput.java | 5 +- .../serialize/protostuff/utils/WrapperUtils.java | 5 +- .../dubbo/test/Spring3CompatibilityTest.java | 1 + .../dubbo/test/consumer/ConsumerConfiguration.java | 1 + .../dubbo/test/provider/ProviderConfiguration.java | 1 + pom.xml | 1 - 152 files changed, 1224 insertions(+), 878 deletions(-) diff --cc dubbo-common/src/main/java/org/apache/dubbo/common/extension/ExtensionLoader.java index 3552f4d,31f72e6..d69b6aa --- 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 @@@ -542,10 -532,13 +542,16 @@@ public class ExtensionLoader<T> if (method.getName().startsWith("set") && method.getParameterTypes().length == 1 && Modifier.isPublic(method.getModifiers())) { + /** + * Check {@link DisableInject} to see if we need auto injection for this property + */ + if (method.getAnnotation(DisableInject.class) != null) { + continue; + } Class<?> pt = method.getParameterTypes()[0]; + if (ReflectUtils.isPrimitives(pt)) { + continue; + } try { String property = method.getName().length() > 3 ? method.getName().substring(3, 4).toLowerCase() + method.getName().substring(4) : ""; Object object = objectFactory.getExtension(pt, property); diff --cc dubbo-config/dubbo-config-api/src/main/java/org/apache/dubbo/config/AbstractConfig.java index 243e8d2,fada00e..5af184d --- 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,627 -1,535 +1,628 @@@ -/* - * 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.extension.ExtensionLoader; -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.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.regex.Matcher; -import java.util.regex.Pattern; - -/** - * 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; - - 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; - } - - 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())) { - 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; - } - 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())) { - 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); - } - 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); - } - return value; - } - - 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."); - } - } - } - - @Parameter(excluded = true) - public String getId() { - return id; - } - - public void setId(String id) { - this.id = id; - } - - 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); - } - } - } - } - - @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); - 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(); - } - } - -} +/* + * 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.CompositeConfiguration; +import org.apache.dubbo.common.config.Configuration; +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.CollectionUtils; +import org.apache.dubbo.common.utils.ReflectUtils; +import org.apache.dubbo.common.utils.StringUtils; +import org.apache.dubbo.config.context.Environment; +import org.apache.dubbo.config.support.Parameter; +import org.apache.dubbo.config.utils.ConfigConverter; +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.regex.Matcher; +import java.util.regex.Pattern; + +/** + * 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("[:*,/\\-._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"}; + + private boolean init; + private volatile Map<String, String> metaData; + + 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"); + } + + protected String id; + + 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; + } + } + tag = tag.toLowerCase(); + return tag; + } + + 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())) { + 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; + } + 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())) { + 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); + } + 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); + } + return value; + } + + 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."); + } + } + } + + @Parameter(excluded = true) + public String getId() { + return id; + } + + public void setId(String id) { + this.id = id; + } + + 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. + * + * @return + */ + public Map<String, String> getMetaData() { + 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 + && isPrimitive(method.getReturnType())) { + int i = name.startsWith("get") ? 3 : 2; + String prop = StringUtils.camelToSplitName(name.substring(i, i + 1).toLowerCase() + name.substring(i + 1), "."); + String key; + Parameter parameter = method.getAnnotation(Parameter.class); + if (parameter != null && parameter.key().length() > 0) { + key = parameter.key(); + } else { + key = prop; + } + if (method.getReturnType() == Object.class || parameter != null && parameter.excluded()) { + metaData.put(key, null); + continue; + } + Object value = method.invoke(this); + 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 = 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) { + System.out.println(this.getClass().getName()); + System.out.println(method.getName()); + throw new IllegalStateException(e.getMessage(), e); + } + } + return metaData; + } + + @Parameter(excluded = true) + public String getPrefix() { + return Constants.DUBBO + "." + getTagName(this.getClass()); + } + + /** + * 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() { + if (init) { + return; + } + init = true; + + try { + Configuration configuration = ConfigConverter.toConfiguration(this); + CompositeConfiguration compositeConfiguration = Environment.getInstance().getStartupCompositeConf(getPrefix(), getId()); + int index = 3; + if (!Environment.getInstance().isConfigCenterFirst()) { + index = 1; + } + compositeConfiguration.addConfiguration(index, configuration); + // loop methods, get override value and set the new value back to method + Method[] methods = getClass().getMethods(); + for (Method method : methods) { + if (isSetter(method)) { + try { + String value = compositeConfiguration.getString(extractPropertyName(method)); + if (value != null) { + method.invoke(this, convertPrimitive(method.getParameterTypes()[0], value)); + } + } catch (NoSuchMethodException e) { + logger.warn("Failed to override the property " + method.getName() + " in " + this.getClass().getSimpleName() + ", please make sure every property has a getter/setter pair.", e); + } + } + } + } catch (Exception e) { + logger.error("Failed to override ", e); + } + } + + private static boolean isSetter(Method method) { + if (method.getName().startsWith("set") + && !"set".equals(method.getName()) + && Modifier.isPublic(method.getModifiers()) + && method.getParameterCount() == 1 + && isPrimitive(method.getParameterTypes()[0])) { + return true; + } + return false; + } + + public String extractPropertyName(Method setter) throws Exception { + String propertyName = setter.getName().substring("set".length()); + Method getter = null; + try { + getter = getClass().getMethod("get" + propertyName); + } catch (NoSuchMethodException e) { + getter = getClass().getMethod("is" + propertyName); + } + Parameter parameter = getter.getAnnotation(Parameter.class); + if (parameter != null && StringUtils.isNotEmpty(parameter.key()) && parameter.propertyKey()) { + propertyName = parameter.key(); + } else { + propertyName = propertyName.toLowerCase(); + } + return propertyName; + } + + @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")) - && !"getClass".equals(name) && !"get".equals(name) && !"is".equals(name) ++ && !"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); + 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/ProtocolConfig.java index 7e45e4c,7582169..3e9fdcd --- 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 @@@ -471,9 -470,4 +471,9 @@@ public class ProtocolConfig extends Abs ExtensionLoader.getExtensionLoader(Protocol.class).getExtension(name).destroy(); } } + + @Override + public boolean isValid() { + return StringUtils.isNotEmpty(name); + } - } + } diff --cc dubbo-config/dubbo-config-api/src/main/java/org/apache/dubbo/config/ReferenceConfig.java index f98d8c1,c39f3b6..2512839 --- 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 @@@ -218,45 -244,8 +218,46 @@@ public class ReferenceConfig<T> extend } } checkApplication(); + checkMetadataReport(); + checkRegistryDataConfig(); + } + + public synchronized T get() { + checkAndUpdateSubConfigs(); + + if (destroyed) { + throw new IllegalStateException("Already destroyed!"); + } + if (ref == null) { + init(); + } + return ref; + } + + public synchronized void destroy() { + if (ref == null) { + return; + } + if (destroyed) { + return; + } + destroyed = true; + try { + invoker.destroy(); + } catch (Throwable t) { + logger.warn("Unexpected err when destroy invoker of ReferenceConfig(" + url + ").", t); + } + invoker = null; + ref = null; + } + + private void init() { + if (initialized) { + return; + } + initialized = true; - checkStubAndMock(interfaceClass); + checkStub(interfaceClass); + checkMock(interfaceClass); Map<String, String> map = new HashMap<String, String>(); resolveAsyncInterface(interfaceClass, map); diff --cc dubbo-config/dubbo-config-api/src/main/java/org/apache/dubbo/config/ServiceConfig.java index 394a8f6,66e8d7f..0133b01 --- 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 @@@ -284,45 -305,12 +284,46 @@@ public class ServiceConfig<T> extends A throw new IllegalStateException("The stub implementation class " + stubClass.getName() + " not implement interface " + interfaceName); } } - checkStubAndMock(interfaceClass); - 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); + } 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-spring/src/main/java/org/apache/dubbo/config/spring/schema/DubboNamespaceHandler.java index df0415b,035c3f9..afbc26b --- 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 @@@ -24,9 -24,9 +24,10 @@@ import org.apache.dubbo.config.MonitorC import org.apache.dubbo.config.ProtocolConfig; import org.apache.dubbo.config.ProviderConfig; import org.apache.dubbo.config.RegistryConfig; +import org.apache.dubbo.config.spring.ConfigCenterBean; import org.apache.dubbo.config.spring.ReferenceBean; import org.apache.dubbo.config.spring.ServiceBean; + import org.springframework.beans.factory.xml.NamespaceHandlerSupport; /**
