/* * Copyright (c) MuleSoft, Inc. All rights reserved. http://www.mulesoft.com * The software in this package is published under the terms of the CPAL v1.0 * license, a copy of which has been included with this distribution in the * LICENSE.txt file. */ package org.mule.runtime.config.spring.parsers.generic; import org.mule.runtime.config.spring.parsers.assembly.BeanAssembler; import org.mule.runtime.config.spring.parsers.assembly.BeanAssemblerFactory; import org.mule.runtime.config.spring.parsers.assembly.DefaultBeanAssembler; import org.mule.runtime.config.spring.parsers.assembly.configuration.PropertyConfiguration; import org.mule.runtime.config.spring.parsers.assembly.configuration.SingleProperty; import org.springframework.beans.MutablePropertyValues; import org.springframework.beans.factory.config.BeanDefinition; import org.springframework.beans.factory.support.AbstractBeanDefinition; import org.springframework.beans.factory.support.BeanDefinitionBuilder; import org.springframework.beans.factory.xml.ParserContext; import org.w3c.dom.Element; /** * This extends {@link ParentDefinitionParser} so that the "name" attribute is set locally, not on the parent. * * <p> * It's easier to understand with an example. Consider a custom security provider, set with the following XML: * </p> * * <pre> <mule:security-manager> <mule:custom-security-provider name="dummySecurityProvider" provider-ref="dummySecurityProvider"/> </mule:security-manager> * </pre> * <p> * What is happening here? First, the custom-security-provider is being handled by this class. Since this class extends * ParentDefinitionParser, the provider value is set on the parent (the security manager). But we want the name attribute to be * set on the provider (the referenced bean). So the "name" is set on the provider, not on the manager. Then the provider is set * on the manager. * </p> */ public class NameTransferDefinitionParser extends ParentDefinitionParser { private String name; private String componentAttributeValue; private String componentAttributeName; /** * @param componentAttributeName The attribute name (after processing, which will strip "-ref", add plurals, etc) that * identifies the service which will receive the "name". */ public NameTransferDefinitionParser(String componentAttributeName) { this.componentAttributeName = componentAttributeName; setBeanAssemblerFactory(new LocalBeanAssemblerFactory()); } // this is a bit of a hack - we transfer the name to the provider // reset for each use protected AbstractBeanDefinition parseInternal(Element element, ParserContext parserContext) { name = null; componentAttributeValue = null; AbstractBeanDefinition bd = super.parseInternal(element, parserContext); element.removeAttribute(ATTRIBUTE_NAME); return bd; } // only set name if not already given private void setName() { BeanDefinition beanDef = getParserContext().getRegistry().getBeanDefinition(componentAttributeValue); MutablePropertyValues propertyValues = beanDef.getPropertyValues(); if (!propertyValues.contains(ATTRIBUTE_NAME)) { logger.debug("Setting " + ATTRIBUTE_NAME + " on " + componentAttributeValue + " to " + name); propertyValues.addPropertyValue(ATTRIBUTE_NAME, name); } else { logger.debug("Not setting " + ATTRIBUTE_NAME + " on " + componentAttributeValue + " as already " + propertyValues.getPropertyValue(ATTRIBUTE_NAME)); } } private class LocalBeanAssembler extends DefaultBeanAssembler { public LocalBeanAssembler(PropertyConfiguration beanConfig, BeanDefinitionBuilder bean, PropertyConfiguration targetConfig, BeanDefinition target) { super(beanConfig, bean, targetConfig, target); } protected void addPropertyWithReference(MutablePropertyValues properties, SingleProperty config, String name, Object value) { // intercept setting of name if (ATTRIBUTE_NAME.equals(name) && value instanceof String) { NameTransferDefinitionParser.this.name = (String) value; // name is set after service if (null != componentAttributeValue) { setName(); } } else { super.addPropertyWithReference(properties, config, name, value); // intercept setting of service if (componentAttributeName.equals(name) && value instanceof String) { componentAttributeValue = (String) value; // name was set before service if (null != NameTransferDefinitionParser.this.name) { setName(); } } } } } private class LocalBeanAssemblerFactory implements BeanAssemblerFactory { public BeanAssembler newBeanAssembler(PropertyConfiguration beanConfig, BeanDefinitionBuilder bean, PropertyConfiguration targetConfig, BeanDefinition target) { return new LocalBeanAssembler(beanConfig, bean, targetConfig, target); } } }