View Javadoc

1   package com.atlassian.plugin.spring.pluginns;
2   
3   import org.springframework.beans.factory.config.BeanDefinition;
4   import org.springframework.beans.factory.config.BeanDefinitionHolder;
5   import org.springframework.beans.factory.support.BeanDefinitionBuilder;
6   import org.springframework.beans.factory.support.BeanDefinitionRegistry;
7   import org.springframework.beans.factory.xml.BeanDefinitionDecorator;
8   import org.springframework.beans.factory.xml.ParserContext;
9   import org.springframework.beans.factory.BeanFactory;
10  import org.springframework.beans.factory.HierarchicalBeanFactory;
11  import org.springframework.jms.*;
12  import org.w3c.dom.Attr;
13  import org.w3c.dom.Node;
14  
15  import java.util.ArrayList;
16  import java.util.List;
17  import java.lang.IllegalStateException;
18  
19  /**
20   * Processes an "available" attribute in the plugin namespace.  Also handles registering the {@link SpringXmlHostComponentProvider}.
21   *
22   * In the case of hierarchical contexts we will put the host
23   * component provider in the lowest possible context.
24   */
25  public class PluginAvailableBeanDefinitionDecorator implements BeanDefinitionDecorator
26  {
27  
28      private static final String HOST_COMPONENT_PROVIDER = "hostComponentProvider";
29  
30      /**
31       * Called when the Spring parser encounters an "available" attribute.
32       * @param source The attribute
33       * @param holder The containing bean definition
34       * @param ctx The parser context
35       * @return The containing bean definition
36       */
37      public BeanDefinitionHolder decorate(
38              Node source, BeanDefinitionHolder holder, ParserContext ctx)
39      {
40  
41          String isAvailable = ((Attr) source).getValue();
42          if (Boolean.parseBoolean(isAvailable))
43          {
44              BeanDefinition providerDef = registerHostComponent(ctx);
45              List<String> registrations = (List<String>) providerDef.getPropertyValues().getPropertyValue("registrations").getValue();
46              registrations.add(holder.getBeanName());
47          }
48          return holder;
49  
50      }
51  
52      /**
53       * Registered a host component provider, if none already exist
54       * @param ctx The parser context
55       * @return The discovered host component provider definition
56       */
57      private BeanDefinition registerHostComponent(ParserContext ctx)
58      {
59          BeanDefinition providerDef;
60  
61          BeanDefinitionRegistry registry = findRegistryContainingComponentProvider(HOST_COMPONENT_PROVIDER, ctx.getRegistry());
62  
63          if (registry == null)
64          {
65              BeanDefinitionBuilder providerDefBuilder = BeanDefinitionBuilder.rootBeanDefinition(SpringXmlHostComponentProvider.class);
66              providerDefBuilder.addPropertyValue("registrations", new ArrayList());
67              providerDef = providerDefBuilder.getBeanDefinition();
68              ctx.getRegistry().registerBeanDefinition(HOST_COMPONENT_PROVIDER, providerDef);
69          }
70          else
71          {
72              providerDef = registry.getBeanDefinition(HOST_COMPONENT_PROVIDER);
73  
74              // try to pull component provider down to child ("current") bean factory
75              if (registry != ctx.getRegistry())
76              {
77                  registry.removeBeanDefinition(HOST_COMPONENT_PROVIDER);
78                  ctx.getRegistry().registerBeanDefinition(HOST_COMPONENT_PROVIDER, providerDef);
79              }
80          }
81  
82          if (providerDef == null)
83          {
84              throw new IllegalStateException("Host component provider not found or created. This should never happen.");
85          }
86          
87          return providerDef;
88      }
89  
90      /**
91       * Dodgey hack to recursively find the bean registry containing the bean definition (recurses up).
92       *
93       * Courtesy of The Don. Kill him. Not me.
94       *
95       * @param beanName
96       * @param registry
97       * @return
98       */
99      private BeanDefinitionRegistry findRegistryContainingComponentProvider(String beanName, BeanDefinitionRegistry registry)
100     {
101         if (registry.containsBeanDefinition(beanName))
102         {
103             return registry;
104         }
105         else if (registry instanceof HierarchicalBeanFactory)
106         {
107             HierarchicalBeanFactory hbf = (HierarchicalBeanFactory) registry;
108             if (hbf.getParentBeanFactory() != null && hbf.getParentBeanFactory() instanceof BeanDefinitionRegistry)
109             {
110                 return findRegistryContainingComponentProvider(beanName, (BeanDefinitionRegistry) hbf.getParentBeanFactory());
111             }
112         }
113 
114         return null;
115     }
116 }