1 package com.atlassian.plugin.spring;
2
3 import com.atlassian.plugin.osgi.hostcomponents.ContextClassLoaderStrategy;
4 import org.springframework.beans.factory.config.BeanDefinition;
5 import org.springframework.beans.factory.support.BeanDefinitionBuilder;
6 import org.springframework.beans.factory.support.BeanDefinitionRegistry;
7
8 import java.util.ArrayList;
9 import java.util.Collection;
10 import java.util.Collections;
11 import java.util.HashMap;
12 import java.util.HashSet;
13 import java.util.List;
14 import java.util.Map;
15 import java.util.Set;
16
17 import static com.atlassian.plugin.util.Assertions.notNull;
18
19 public class PluginBeanDefinitionRegistry
20 {
21 public static final String HOST_COMPONENT_PROVIDER = "hostComponentProvider";
22
23 private static final String BEAN_NAMES = "beanNames";
24 private static final String BEAN_INTERFACES = "beanInterfaces";
25 private static final String BEAN_CONTEXT_CLASS_LOADER_STRATEGIES = "beanContextClassLoaderStrategies";
26 private static final String BUNDLE_TRACKING_BEANS = "bundleTrackingBeans";
27
28 private final BeanDefinitionRegistry registry;
29
30 public PluginBeanDefinitionRegistry(BeanDefinitionRegistry registry)
31 {
32 this.registry = notNull("registry", registry);
33 }
34
35 public BeanDefinition getBeanDefinition()
36 {
37 if (!registry.containsBeanDefinition(HOST_COMPONENT_PROVIDER))
38 {
39 BeanDefinitionBuilder builder = BeanDefinitionBuilder.rootBeanDefinition(SpringHostComponentProviderFactoryBean.class);
40 BeanDefinition beanDef = builder.getBeanDefinition();
41 primeHostComponentBeanDefinition(beanDef);
42
43 registry.registerBeanDefinition(HOST_COMPONENT_PROVIDER, beanDef);
44 }
45
46 final BeanDefinition beanDef = registry.getBeanDefinition(HOST_COMPONENT_PROVIDER);
47 primeHostComponentBeanDefinition(beanDef);
48
49 if (beanDef == null)
50 {
51 throw new IllegalStateException("Host component provider not found nor created. This should never happen.");
52 }
53 return beanDef;
54 }
55
56 private void primeHostComponentBeanDefinition(BeanDefinition beanDef)
57 {
58 ensurePropertyNotNull(beanDef, BEAN_NAMES, new ArrayList<String>());
59 ensurePropertyNotNull(beanDef, BEAN_INTERFACES, new HashMap<String, List<String>>());
60 ensurePropertyNotNull(beanDef, BEAN_CONTEXT_CLASS_LOADER_STRATEGIES, new HashMap<String, ContextClassLoaderStrategy>());
61 ensurePropertyNotNull(beanDef, BUNDLE_TRACKING_BEANS, new HashSet<String>());
62 }
63
64 private void ensurePropertyNotNull(BeanDefinition beanDef, String propertyName, Object defaultValue)
65 {
66 if (!beanDef.getPropertyValues().contains(propertyName))
67 {
68 beanDef.getPropertyValues().addPropertyValue(propertyName, defaultValue);
69 }
70 }
71
72 public void addBeanName(String beanName)
73 {
74 getBeanNames().add(beanName);
75 }
76
77 public void addBeanInterface(String beanName, String ifce)
78 {
79 addBeanInterfaces(beanName, Collections.singleton(ifce));
80 }
81
82 public void addBeanInterfaces(String beanName, Collection<String> ifces)
83 {
84 final Map<String, List<String>> beanInterfaces = getBeanInterfaces();
85
86 List<String> interfaces = beanInterfaces.get(beanName);
87 if (interfaces == null)
88 {
89 interfaces = new ArrayList<String>();
90 beanInterfaces.put(beanName, interfaces);
91 }
92 interfaces.addAll(ifces);
93 }
94
95 public void addContextClassLoaderStrategy(String beanName, ContextClassLoaderStrategy strategy)
96 {
97 getBeanContextClassLoaderStrategies().put(beanName, strategy);
98 }
99
100 public void addBundleTrackingBean(String beanName)
101 {
102 getBundleTrackingBeans().add(beanName);
103 }
104
105 @SuppressWarnings("unchecked")
106 private Map<String, ContextClassLoaderStrategy> getBeanContextClassLoaderStrategies()
107 {
108 return (Map<String, ContextClassLoaderStrategy>) getPropertyValue(BEAN_CONTEXT_CLASS_LOADER_STRATEGIES);
109 }
110
111 @SuppressWarnings("unchecked")
112 private Map<String, List<String>> getBeanInterfaces()
113 {
114 return (Map<String, List<String>>) getPropertyValue(BEAN_INTERFACES);
115 }
116
117 @SuppressWarnings("unchecked")
118 private List<String> getBeanNames()
119 {
120 return (List<String>) getPropertyValue(BEAN_NAMES);
121 }
122
123 @SuppressWarnings("unchecked")
124 private Set<String> getBundleTrackingBeans()
125 {
126 return (Set<String>) getPropertyValue(BUNDLE_TRACKING_BEANS);
127 }
128
129 private Object getPropertyValue(String propertyName)
130 {
131 return getBeanDefinition().getPropertyValues().getPropertyValue(propertyName).getValue();
132 }
133 }