View Javadoc

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