/* * Copyright (c) 2002-2012 Alibaba Group Holding Limited. * All rights reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package com.alibaba.citrus.service.pull.impl; import static com.alibaba.citrus.springext.util.DomUtil.*; import static com.alibaba.citrus.springext.util.SpringExtUtil.*; import static com.alibaba.citrus.util.Assert.*; import static com.alibaba.citrus.util.BasicConstant.*; import static com.alibaba.citrus.util.StringUtil.*; import java.util.Map; import java.util.regex.Pattern; import com.alibaba.citrus.springext.ConfigurationPoint; import com.alibaba.citrus.springext.Contribution; import com.alibaba.citrus.springext.ContributionAware; import com.alibaba.citrus.springext.support.parser.AbstractNamedBeanDefinitionParser; import com.alibaba.citrus.util.StringUtil; 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.config.RuntimeBeanReference; import org.springframework.beans.factory.support.BeanDefinitionBuilder; import org.springframework.beans.factory.xml.ParserContext; import org.w3c.dom.Element; public class PullServiceDefinitionParser extends AbstractNamedBeanDefinitionParser<PullServiceImpl> implements ContributionAware { private final static Logger log = LoggerFactory.getLogger(PullServiceDefinitionParser.class); private final static Pattern ID_PATTERN = Pattern.compile("\\w+"); private final static String[] CLASS_NAME_SUFFIXES = { "Tool", "ToolFactory", "ToolSet", "ToolSetFactory" }; private final static String[] ELEMENT_NAME_SUFFIXES = { "-tool", "-tool-factory", "-tool-set", "-tool-set-factory" }; private ConfigurationPoint pullToolsConfigurationPoint; public void setContribution(Contribution contrib) { this.pullToolsConfigurationPoint = getSiblingConfigurationPoint("services/pull/factories", contrib); } @Override protected void doParse(Element element, ParserContext parserContext, BeanDefinitionBuilder builder) { parseBeanDefinitionAttributes(element, parserContext, builder); Map<Object, Object> factories = createManagedMap(element, parserContext); for (Element subElement : subElements(element)) { doParseTool(subElement, parserContext, builder, factories); } log.debug("Totally {} tools are registered.", factories.size()); builder.addPropertyValue("toolFactories", factories); // parent String parentRef = trimToNull(element.getAttribute("parentRef")); if (parentRef != null) { builder.addPropertyValue("parent", new RuntimeBeanReference(parentRef)); } } private void doParseTool(Element element, ParserContext parserContext, BeanDefinitionBuilder builder, Map<Object, Object> factories) { BeanDefinitionHolder bean = parseConfigurationPointBean(element, pullToolsConfigurationPoint, parserContext, builder); if (bean == null) { return; } String refName = trimToNull(element.getAttribute("ref")); String toolName = getToolName(bean, refName, element); // 根据id, ref, element name或class name取得tool name assertNotNull(toolName, "missing id for tool: %s", bean); assertTrue(!factories.containsKey(toolName), "duplicated tool or tool-set ID: %s", toolName); factories.put(toolName, bean); if (log.isDebugEnabled()) { String targetBeanClass = bean.getBeanDefinition().getBeanClassName(); if (refName != null) { log.debug("Registered tool reference: {}={}", toolName, refName); } else { log.debug("Registered tool: {}={}", toolName, targetBeanClass); } } } private String getToolName(BeanDefinitionHolder bean, String refName, Element element) { // 依次尝试: // 1. id attribute String toolName = bean.getBeanName(); if (!ID_PATTERN.matcher(toolName).matches()) { toolName = null; } // 2. 取refName if (toolName == null) { toolName = refName; } // 3. 取class attribute if (toolName == null) { String classAttr = trimToNull(element.getAttribute("class")); if (classAttr != null) { toolName = className2ToolName(classAttr); } } // 4. 根据element名称生成 String elementName = element.getLocalName(); if (toolName == null && elementName != null && !elementName.equals("factory")) { toolName = dropSuffix(elementName, ELEMENT_NAME_SUFFIXES); toolName = trimToNull(StringUtil.toCamelCase(toolName.replace('-', '_'))); } // 5. 根据className生成 if (toolName == null) { BeanDefinition bd = bean.getBeanDefinition(); String className = bd.getBeanClassName(); if (className != null) { toolName = className2ToolName(className); } } return toolName; } private String className2ToolName(String className) { String toolName; toolName = className.substring(className.lastIndexOf(".") + 1); toolName = dropSuffix(toolName, CLASS_NAME_SUFFIXES); toolName = StringUtil.toCamelCase(toolName.substring(toolName.lastIndexOf("$") + 1)); return toolName; } private String dropSuffix(String name, String[] suffixes) { String tmp = EMPTY_STRING; for (String suffix : suffixes) { if (name.endsWith(suffix)) { tmp = name.substring(0, name.length() - suffix.length()); } } return tmp.length() > 0 ? tmp : name; } @Override protected String getDefaultName() { return "pullService"; } }