View Javadoc
1   /*
2    * Copyright (c) MuleSoft, Inc.  All rights reserved.  http://www.mulesoft.com
3    * The software in this package is published under the terms of the CPAL v1.0
4    * license, a copy of which has been included with this distribution in the
5    * LICENSE.txt file.
6    */
7   package org.mule.config.spring.parsers.generic;
8   
9   import org.mule.config.spring.parsers.assembly.BeanAssembler;
10  import org.mule.config.spring.parsers.assembly.BeanAssemblerFactory;
11  import org.mule.config.spring.parsers.assembly.DefaultBeanAssembler;
12  import org.mule.config.spring.parsers.assembly.configuration.PropertyConfiguration;
13  import org.mule.config.spring.parsers.assembly.configuration.SingleProperty;
14  
15  import org.springframework.beans.MutablePropertyValues;
16  import org.springframework.beans.factory.config.BeanDefinition;
17  import org.springframework.beans.factory.support.AbstractBeanDefinition;
18  import org.springframework.beans.factory.support.BeanDefinitionBuilder;
19  import org.springframework.beans.factory.xml.ParserContext;
20  import org.w3c.dom.Element;
21  
22  /**
23   * This extends {@link ParentDefinitionParser} so that the "name" attribute is set locally,
24   * not on the parent.
25   *
26   * <p>It's easier to understand with an example. Consider a custom security provider, set with the
27   * following XML:</p>
28   * <pre>
29   &lt;mule:security-manager&gt;
30       &lt;mule:custom-security-provider name="dummySecurityProvider"
31                                      provider-ref="dummySecurityProvider"/&gt;
32   &lt;/mule:security-manager&gt;</pre>
33   * <p>What is happening here?  First, the custom-security-provider is being handled by this class.
34   * Since this class extends ParentDefinitionParser, the provider value is set on the parent (the
35   * security manager).  But we want the name attribute to be set on the provider (the referenced
36   * bean).  So the "name" is set on the provider, not on the manager.  Then the provider is set on
37   * the manager.</p> 
38   */
39  public class NameTransferDefinitionParser extends ParentDefinitionParser
40  {
41  
42      private String name;
43      private String componentAttributeValue;
44      private String componentAttributeName;
45  
46      /**
47       * @param componentAttributeName The attribute name (after processing, which will strip "-ref",
48       * add plurals, etc) that identifies the service which will receive the "name".
49       */
50      public NameTransferDefinitionParser(String componentAttributeName)
51      {
52          this.componentAttributeName = componentAttributeName;
53          setBeanAssemblerFactory(new LocalBeanAssemblerFactory());
54      }
55  
56      // this is a bit of a hack - we transfer the name to the provider
57  
58      // reset for each use
59      protected AbstractBeanDefinition parseInternal(Element element, ParserContext parserContext)
60      {
61          name = null;
62          componentAttributeValue = null;
63          AbstractBeanDefinition bd = super.parseInternal(element, parserContext);
64          element.removeAttribute(ATTRIBUTE_NAME);
65          return bd; 
66      }
67  
68  
69      //  only set name if not already given
70      private void setName()
71      {
72          BeanDefinition beanDef = getParserContext().getRegistry().getBeanDefinition(componentAttributeValue);
73          MutablePropertyValues propertyValues = beanDef.getPropertyValues();
74          if (!propertyValues.contains(ATTRIBUTE_NAME))
75          {
76              logger.debug("Setting " + ATTRIBUTE_NAME + " on " + componentAttributeValue + " to " + name);
77              propertyValues.addPropertyValue(ATTRIBUTE_NAME, name);
78          }
79          else
80          {
81              logger.debug("Not setting " + ATTRIBUTE_NAME + " on " + componentAttributeValue +
82                      " as already " + propertyValues.getPropertyValue(ATTRIBUTE_NAME));
83          }
84      }
85  
86      private class LocalBeanAssembler extends DefaultBeanAssembler
87      {
88  
89          public LocalBeanAssembler(PropertyConfiguration beanConfig, BeanDefinitionBuilder bean,
90                                        PropertyConfiguration targetConfig, BeanDefinition target)
91          {
92              super(beanConfig, bean, targetConfig, target);
93          }
94  
95          protected void addPropertyWithReference(MutablePropertyValues properties, SingleProperty config, String name, Object value)
96          {
97              // intercept setting of name
98              if (ATTRIBUTE_NAME.equals(name) && value instanceof String)
99              {
100                 NameTransferDefinitionParser.this.name = (String) value;
101                 // name is set after service
102                 if (null != componentAttributeValue)
103                 {
104                     setName();
105                 }
106             }
107             else
108             {
109                 super.addPropertyWithReference(properties, config, name, value);
110 
111                 // intercept setting of service
112                 if (componentAttributeName.equals(name) && value instanceof String)
113                 {
114                     componentAttributeValue = (String) value;
115                     // name was set before service
116                     if (null != NameTransferDefinitionParser.this.name)
117                     {
118                         setName();
119                     }
120                 }
121             }
122         }
123     }
124 
125     private class LocalBeanAssemblerFactory implements BeanAssemblerFactory
126     {
127 
128         public BeanAssembler newBeanAssembler(PropertyConfiguration beanConfig, BeanDefinitionBuilder bean,
129                                                       PropertyConfiguration targetConfig, BeanDefinition target)
130         {
131             return new LocalBeanAssembler(beanConfig, bean, targetConfig, target);
132         }
133 
134     }
135 
136 }