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 public static final String HOST_COMPONENT_PROVIDER = "hostComponentProvider";
21
22 private static final String BEAN_NAMES = "beanNames";
23 private static final String BEAN_INTERFACES = "beanInterfaces";
24 private static final String BEAN_CONTEXT_CLASS_LOADER_STRATEGIES = "beanContextClassLoaderStrategies";
25 private static final String BUNDLE_TRACKING_BEANS = "bundleTrackingBeans";
26
27 private final BeanDefinitionRegistry registry;
28
29 public PluginBeanDefinitionRegistry(BeanDefinitionRegistry registry) {
30 this.registry = notNull("registry", registry);
31 }
32
33 public BeanDefinition getBeanDefinition() {
34 if (!registry.containsBeanDefinition(HOST_COMPONENT_PROVIDER)) {
35 BeanDefinitionBuilder builder = BeanDefinitionBuilder.rootBeanDefinition(SpringHostComponentProviderFactoryBean.class);
36 BeanDefinition beanDef = builder.getBeanDefinition();
37 primeHostComponentBeanDefinition(beanDef);
38
39 registry.registerBeanDefinition(HOST_COMPONENT_PROVIDER, beanDef);
40 }
41
42 final BeanDefinition beanDef = registry.getBeanDefinition(HOST_COMPONENT_PROVIDER);
43 primeHostComponentBeanDefinition(beanDef);
44
45 if (beanDef == null) {
46 throw new IllegalStateException("Host component provider not found nor created. This should never happen.");
47 }
48 return beanDef;
49 }
50
51 private void primeHostComponentBeanDefinition(BeanDefinition beanDef) {
52 ensurePropertyNotNull(beanDef, BEAN_NAMES, new ArrayList<String>());
53 ensurePropertyNotNull(beanDef, BEAN_INTERFACES, new HashMap<String, List<String>>());
54 ensurePropertyNotNull(beanDef, BEAN_CONTEXT_CLASS_LOADER_STRATEGIES, new HashMap<String, ContextClassLoaderStrategy>());
55 ensurePropertyNotNull(beanDef, BUNDLE_TRACKING_BEANS, new HashSet<String>());
56 }
57
58 private void ensurePropertyNotNull(BeanDefinition beanDef, String propertyName, Object defaultValue) {
59 if (!beanDef.getPropertyValues().contains(propertyName)) {
60 beanDef.getPropertyValues().addPropertyValue(propertyName, defaultValue);
61 }
62 }
63
64 public void addBeanName(String beanName) {
65 getBeanNames().add(beanName);
66 }
67
68 public void addBeanInterface(String beanName, String ifce) {
69 addBeanInterfaces(beanName, Collections.singleton(ifce));
70 }
71
72 public void addBeanInterfaces(String beanName, Collection<String> ifces) {
73 final Map<String, List<String>> beanInterfaces = getBeanInterfaces();
74
75 List<String> interfaces = beanInterfaces.get(beanName);
76 if (interfaces == null) {
77 interfaces = new ArrayList<>();
78 beanInterfaces.put(beanName, interfaces);
79 }
80 interfaces.addAll(ifces);
81 }
82
83 public void addContextClassLoaderStrategy(String beanName, ContextClassLoaderStrategy strategy) {
84 getBeanContextClassLoaderStrategies().put(beanName, strategy);
85 }
86
87 public void addBundleTrackingBean(String beanName) {
88 getBundleTrackingBeans().add(beanName);
89 }
90
91 @SuppressWarnings("unchecked")
92 private Map<String, ContextClassLoaderStrategy> getBeanContextClassLoaderStrategies() {
93 return (Map<String, ContextClassLoaderStrategy>) getPropertyValue(BEAN_CONTEXT_CLASS_LOADER_STRATEGIES);
94 }
95
96 @SuppressWarnings("unchecked")
97 private Map<String, List<String>> getBeanInterfaces() {
98 return (Map<String, List<String>>) getPropertyValue(BEAN_INTERFACES);
99 }
100
101 @SuppressWarnings("unchecked")
102 private List<String> getBeanNames() {
103 return (List<String>) getPropertyValue(BEAN_NAMES);
104 }
105
106 @SuppressWarnings("unchecked")
107 private Set<String> getBundleTrackingBeans() {
108 return (Set<String>) getPropertyValue(BUNDLE_TRACKING_BEANS);
109 }
110
111 private Object getPropertyValue(String propertyName) {
112 return getBeanDefinition().getPropertyValues().getPropertyValue(propertyName).getValue();
113 }
114 }