All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.github.markusbernhardt.springcontexttemplate.ImportBeanDefinitionParser Maven / Gradle / Ivy

There is a newer version: 1.0.4
Show newest version
package com.github.markusbernhardt.springcontexttemplate;

import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.UUID;

import org.springframework.beans.factory.BeanCreationException;
import org.springframework.beans.factory.BeanDefinitionStoreException;
import org.springframework.beans.factory.config.BeanDefinition;
import org.springframework.beans.factory.config.BeanDefinitionVisitor;
import org.springframework.beans.factory.parsing.BeanComponentDefinition;
import org.springframework.beans.factory.parsing.CompositeComponentDefinition;
import org.springframework.beans.factory.support.AbstractBeanDefinition;
import org.springframework.beans.factory.support.BeanDefinitionRegistry;
import org.springframework.beans.factory.support.DefaultListableBeanFactory;
import org.springframework.beans.factory.xml.AbstractBeanDefinitionParser;
import org.springframework.beans.factory.xml.ParserContext;
import org.springframework.beans.factory.xml.XmlBeanDefinitionReader;
import org.springframework.core.env.ConfigurableEnvironment;
import org.springframework.util.StringValueResolver;
import org.springframework.util.xml.DomUtils;
import org.w3c.dom.Element;

public class ImportBeanDefinitionParser extends AbstractBeanDefinitionParser {

	/**
	 * Central template method to actually parse the supplied {@link Element}
	 * into one or more {@link BeanDefinition BeanDefinitions}.
	 * 
	 * @param element
	 *            the element that is to be parsed into one or more
	 *            {@link BeanDefinition BeanDefinitions}
	 * @param parserContext
	 *            the object encapsulating the current state of the parsing
	 *            process; provides access to a
	 *            {@link org.springframework.beans.factory.support.BeanDefinitionRegistry}
	 * @return the primary {@link BeanDefinition} resulting from the parsing of
	 *         the supplied {@link Element}
	 * @see #parse(org.w3c.dom.Element, ParserContext)
	 * @see #postProcessComponentDefinition(org.springframework.beans.factory.parsing.BeanComponentDefinition)
	 */
	@Override
	protected AbstractBeanDefinition parseInternal(Element element, ParserContext parserContext) {
		Map variables = getVariables(element);
		ConfigurableEnvironment environment = (ConfigurableEnvironment) parserContext.getDelegate().getEnvironment();
		StringValueResolver resolver = new ImportStringValueResolver(variables, environment);
		BeanDefinitionVisitor visitor = new ImportBeanDefinitionVisitor(resolver);
		Map beanDefinitions = loadBeanDefinitions(element, visitor, resolver);
		registerBeans(element, parserContext, beanDefinitions);
		return null;
	}

	/**
	 * Return a map of all defined variables
	 * 
	 * @param element
	 *            the import XML DOM element
	 * @return the created map
	 * @throws BeanCreationException
	 *             in case of specifying no, ambiguous or invalid variables
	 */
	protected Map getVariables(Element element) {
		Map map = new HashMap();

		String attributeName = element.getAttribute("name");
		String attributeValue = element.getAttribute("value");
		if (attributeName.length() != 0 || attributeValue.length() != 0) {
			if (attributeName.length() == 0) {
				throw new BeanCreationException("Missing attribute 'name'");
			}
			if (attributeValue.length() == 0) {
				throw new BeanCreationException("Missing attribute 'value'");
			}
			map.put(attributeName, attributeValue);
		}

		List elements = DomUtils.getChildElementsByTagName(element, "variable");
		for (Element variable : elements) {
			attributeName = variable.getAttribute("name");
			attributeValue = variable.getAttribute("value");
			if (map.containsKey(attributeName)) {
				throw new BeanCreationException(String.format("Ambiguous declaration of varaible '%s'", attributeName));
			}
			map.put(attributeName, attributeValue);
		}

		if (map.size() == 0) {
			throw new BeanCreationException("No variable defined");
		}
		return map;
	}

	/**
	 * Load bean definitions from the specified resource.
	 * 
	 * @param element
	 *            the import XML DOM element containing the resource
	 * @param visitor
	 *            the visitor to resolve the template variables
	 * @param valueResolver
	 *            the resolver to resolve the bean names
	 * @return the loaded and resolved beans
	 * @throws BeanCreationException
	 *             in case of loading non template beans
	 * @throws BeanDefinitionStoreException
	 *             in case of loading or parsing errors
	 */
	protected Map loadBeanDefinitions(Element element, BeanDefinitionVisitor visitor,
			StringValueResolver valueResolver) {
		// load bean definitions to the registry
		BeanDefinitionRegistry registry = new DefaultListableBeanFactory();
		XmlBeanDefinitionReader reader = new XmlBeanDefinitionReader(registry);
		reader.loadBeanDefinitions(element.getAttribute("resource"));

		// resolve bean names
		Map beans = new HashMap();
		for (String beanName : registry.getBeanDefinitionNames()) {
			BeanDefinition beanDefinition = registry.getBeanDefinition(beanName);
			visitor.visitBeanDefinition(beanDefinition);
			String resolvedBeanName = valueResolver.resolveStringValue(beanName);

			if (resolvedBeanName.matches("^.*#\\d+$")) {
				/**
				 * If it's anonymous bean, then generate unique name for it.
				 */
				resolvedBeanName += "--" + UUID.randomUUID().toString();
			}
			if (resolvedBeanName.equals(beanName)) {
				throw new BeanCreationException(String.format("The bean '%s' is not a template", beanName));
			}
			beans.put(resolvedBeanName, beanDefinition);
		}
		return beans;
	}

	/**
	 * Register the given beans to the parser context
	 * 
	 * @param element
	 *            the import XML DOM element
	 * @param parserContext
	 *            the parser context
	 * @param beanDefinitions
	 *            the loaded bean definitions
	 */
	protected void registerBeans(Element element, ParserContext parserContext,
			Map beanDefinitions) {
		CompositeComponentDefinition compositeDef = new CompositeComponentDefinition(element.getTagName(),
				parserContext.extractSource(element));
		parserContext.pushContainingComponent(compositeDef);

		for (Map.Entry entry : beanDefinitions.entrySet()) {
			parserContext.getRegistry().registerBeanDefinition(entry.getKey(), entry.getValue());
			parserContext.registerComponent(new BeanComponentDefinition(entry.getValue(), entry.getKey()));
		}

		parserContext.popAndRegisterContainingComponent();
	}
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy