package krpc.rpc.bootstrap.spring; import krpc.rpc.bootstrap.*; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.beans.factory.config.BeanDefinition; import org.springframework.beans.factory.config.BeanDefinitionHolder; import org.springframework.beans.factory.support.BeanDefinitionBuilder; import org.springframework.beans.factory.support.ManagedList; import org.springframework.beans.factory.support.RootBeanDefinition; import org.springframework.beans.factory.xml.BeanDefinitionParser; import org.springframework.beans.factory.xml.NamespaceHandlerSupport; import org.springframework.beans.factory.xml.ParserContext; import org.w3c.dom.Element; import org.w3c.dom.Node; import org.w3c.dom.NodeList; import java.lang.reflect.Field; import java.util.ArrayList; import java.util.List; public class Parsers extends NamespaceHandlerSupport { @Override public void init() { registerBeanDefinitionParser("application", new ApplicationConfigBeanParser()); registerBeanDefinitionParser("registry", new RegistryConfigBeanParser()); registerBeanDefinitionParser("monitor", new MonitorConfigBeanParser()); registerBeanDefinitionParser("server", new ServerConfigBeanParser()); registerBeanDefinitionParser("webserver", new WebServerConfigBeanParser()); registerBeanDefinitionParser("client", new ClientConfigBeanParser()); registerBeanDefinitionParser("service", new ServiceConfigBeanParser()); registerBeanDefinitionParser("referer", new RefererConfigBeanParser()); } } class BaseParser<T> implements BeanDefinitionParser { static RootBeanDefinition rpcAppBeanDefinition; static List<String> beanIds = new ArrayList<>(); Class<T> beanClass; String[] attributes; boolean hasMethods = false; boolean hasPlugins = false; String idValue; String beanId; public void init(Class<?> cls) { Field[] fields = cls.getDeclaredFields(); List<String> attrs = new ArrayList<>(); for (Field f : fields) { String name = f.getName(); if (name.equals("methods")) { hasMethods = true; } else if (name.equals("pluginParams")) { hasPlugins = true; } else { attrs.add(name); } } attributes = attrs.toArray(new String[0]); } public BeanDefinition parse(Element root, ParserContext parserContext) { RootBeanDefinition bd = new RootBeanDefinition(); bd.setBeanClass(beanClass); bd.setLazyInit(false); idValue = root.getAttribute("id"); if (this instanceof RefererConfigBeanParser) beanId = generateBeanId(null, parserContext); // idValue will be used by referer proxy else beanId = generateBeanId(idValue, parserContext); parserContext.getRegistry().registerBeanDefinition(beanId, bd); beanIds.add(beanId); if (rpcAppBeanDefinition == null) { rpcAppBeanDefinition = new RootBeanDefinition(); rpcAppBeanDefinition.setBeanClass(RpcAppFactory.class); rpcAppBeanDefinition.setLazyInit(false); rpcAppBeanDefinition.setInitMethodName("init"); rpcAppBeanDefinition.setDestroyMethodName("close"); parserContext.getRegistry().registerBeanDefinition("rpcApp", rpcAppBeanDefinition); } rpcAppBeanDefinition.setDependsOn(beanIds.toArray(new String[0])); if (attributes != null) { for (String name : attributes) { String value = root.getAttribute(name); if (value != null && value.length() > 0) bd.getPropertyValues().addPropertyValue(name, value); } } if (hasMethods) parseMethod(root, parserContext, bd); if (hasPlugins) parsePlugin(root, parserContext, bd); return bd; } String generateBeanId(String initValue, ParserContext parserContext) { String id = initValue; if (id == null || id.isEmpty()) { id = beanClass.getName(); int counter = 2; while (parserContext.getRegistry().containsBeanDefinition(id)) { id = beanClass.getName() + (counter++); } } return id; } @SuppressWarnings({"rawtypes", "unchecked"}) void parseMethod(Element root, ParserContext parserContext, RootBeanDefinition bd) { NodeList nodeList = root.getChildNodes(); if (nodeList == null || nodeList.getLength() == 0) return; MethodConfigBeanParser methodParser = new MethodConfigBeanParser(); ManagedList methods = new ManagedList(); for (int i = 0; i < nodeList.getLength(); i++) { Node node = nodeList.item(i); if (node instanceof Element) { Element element = (Element) node; if ("method".equals(node.getNodeName()) || "method".equals(node.getLocalName())) { String pattern = element.getAttribute("pattern"); if (pattern == null || pattern.isEmpty()) { throw new RuntimeException("method pattern must be specified"); } BeanDefinition methodBeanDefinition = methodParser.parse(element, parserContext); String name = beanId + "." + pattern; BeanDefinitionHolder methodBeanDefinitionHolder = new BeanDefinitionHolder(methodBeanDefinition, name); methods.add(methodBeanDefinitionHolder); } } } if (methods.size() > 0) { bd.getPropertyValues().addPropertyValue("methods", methods); } } void parsePlugin(Element root, ParserContext parserContext, RootBeanDefinition bd) { NodeList nodeList = root.getChildNodes(); if (nodeList == null || nodeList.getLength() == 0) return; ArrayList<String> plugins = new ArrayList<>(); for (int i = 0; i < nodeList.getLength(); i++) { Node node = nodeList.item(i); if (node instanceof Element) { Element element = (Element) node; if ("plugin".equals(node.getNodeName()) || "plugin".equals(node.getLocalName())) { String params = element.getAttribute("params"); if (params == null || params.isEmpty()) { throw new RuntimeException("plugin params must be specified"); } plugins.add(params); } } } if (plugins.size() > 0) { bd.getPropertyValues().addPropertyValue("pluginParams", plugins); } } } class ApplicationConfigBeanParser extends BaseParser<ApplicationConfigBean> { ApplicationConfigBeanParser() { beanClass = ApplicationConfigBean.class; init(ApplicationConfig.class); } } class ClientConfigBeanParser extends BaseParser<ClientConfigBean> { ClientConfigBeanParser() { beanClass = ClientConfigBean.class; init(ClientConfig.class); } } class ServerConfigBeanParser extends BaseParser<ServerConfigBean> { ServerConfigBeanParser() { beanClass = ServerConfigBean.class; init(ServerConfig.class); } } class WebServerConfigBeanParser extends BaseParser<WebServerConfigBean> { WebServerConfigBeanParser() { beanClass = WebServerConfigBean.class; init(WebServerConfig.class); } } class RegistryConfigBeanParser extends BaseParser<RegistryConfigBean> { RegistryConfigBeanParser() { beanClass = RegistryConfigBean.class; init(RegistryConfig.class); } } class ServiceConfigBeanParser extends BaseParser<ServiceConfigBean> { ServiceConfigBeanParser() { beanClass = ServiceConfigBean.class; init(ServiceConfig.class); } } class RefererConfigBeanParser extends BaseParser<RefererConfigBean> { static Logger log = LoggerFactory.getLogger(Parsers.class); RefererConfigBeanParser() { beanClass = RefererConfigBean.class; init(RefererConfig.class); } public BeanDefinition parse(Element root, ParserContext parserContext) { BeanDefinition bd = super.parse(root, parserContext); String interfaceName = bd.getPropertyValues().getPropertyValue("interfaceName").getValue().toString(); registerReferer(idValue, interfaceName, parserContext); return bd; } void registerReferer(String id, String interfaceName, ParserContext parserContext) { String beanName = generateBeanName(id, interfaceName); //log.info("register referer "+interfaceName+", beanName="+beanName); BeanDefinitionBuilder beanDefinitionBuilder = BeanDefinitionBuilder.genericBeanDefinition(RefererFactory.class); beanDefinitionBuilder.addConstructorArgValue(beanName); beanDefinitionBuilder.addConstructorArgValue(interfaceName); beanDefinitionBuilder.addDependsOn("rpcApp"); beanDefinitionBuilder.setLazyInit(true); parserContext.getRegistry().registerBeanDefinition(beanName, beanDefinitionBuilder.getRawBeanDefinition()); registerAsyncReferer(beanName + "Async", interfaceName + "Async", parserContext); } void registerAsyncReferer(String beanName, String interfaceName, ParserContext parserContext) { //log.info("register referer "+interfaceName+", beanName="+beanName); BeanDefinitionBuilder beanDefinitionBuilder = BeanDefinitionBuilder.genericBeanDefinition(RefererFactory.class); beanDefinitionBuilder.addConstructorArgValue(beanName); beanDefinitionBuilder.addConstructorArgValue(interfaceName); beanDefinitionBuilder.addDependsOn("rpcApp"); beanDefinitionBuilder.setLazyInit(true); parserContext.getRegistry().registerBeanDefinition(beanName, beanDefinitionBuilder.getRawBeanDefinition()); } String generateBeanName(String id, String interfaceName) { if (id != null && !id.isEmpty()) return id; int p = interfaceName.lastIndexOf("."); String name = interfaceName.substring(p + 1); name = name.substring(0, 1).toLowerCase() + name.substring(1); return name; } } class MonitorConfigBeanParser extends BaseParser<MonitorConfigBean> { MonitorConfigBeanParser() { beanClass = MonitorConfigBean.class; init(MonitorConfig.class); } } class MethodConfigBeanParser extends BaseParser<MethodConfig> { MethodConfigBeanParser() { beanClass = MethodConfig.class; init(MethodConfig.class); } }