1 package com.atlassian.plugin.osgi.spring;
2
3 import com.atlassian.plugin.PluginException;
4 import com.atlassian.plugin.module.ContainerAccessor;
5
6 import java.lang.reflect.InvocationTargetException;
7 import java.lang.reflect.Method;
8 import java.util.Collection;
9 import java.util.Map;
10 import java.util.Objects;
11 import java.util.stream.Stream;
12
13 import static com.google.common.base.Preconditions.checkState;
14
15
16
17
18
19
20 public class DefaultSpringContainerAccessor implements ContainerAccessor {
21 private final Object nativeBeanFactory;
22 private final Method nativeCreateBeanMethod;
23 private final Method nativeAutowireBeanMethod;
24 private final Method nativeGetBeanMethod;
25 private final Method nativeGetBeansOfTypeMethod;
26
27
28
29
30 public enum AutowireStrategy {
31 AUTOWIRE_NO,
32
33
34
35 AUTOWIRE_BY_NAME,
36
37
38
39
40 AUTOWIRE_BY_TYPE,
41
42
43
44
45 AUTOWIRE_BY_CONSTRUCTOR,
46
47
48
49
50
51
52
53 @Deprecated
54 AUTOWIRE_AUTODETECT
55 }
56
57 public DefaultSpringContainerAccessor(final Object applicationContext) {
58 Object beanFactory = null;
59 try {
60 final Method m = applicationContext.getClass().getMethod("getAutowireCapableBeanFactory");
61 beanFactory = m.invoke(applicationContext);
62 } catch (final NoSuchMethodException e) {
63
64 throw new PluginException("Cannot find getAutowireCapableBeanFactory method on " + applicationContext.getClass(), e);
65 } catch (final IllegalAccessException e) {
66
67 throw new PluginException("Cannot access getAutowireCapableBeanFactory method", e);
68 } catch (final InvocationTargetException e) {
69 handleSpringMethodInvocationError(e);
70 }
71
72 nativeBeanFactory = beanFactory;
73 try {
74 nativeCreateBeanMethod = beanFactory.getClass().getMethod("createBean", Class.class, int.class, boolean.class);
75 nativeAutowireBeanMethod = beanFactory.getClass().getMethod("autowireBean", Object.class);
76 nativeGetBeanMethod = beanFactory.getClass().getMethod("getBean", String.class);
77 nativeGetBeansOfTypeMethod = beanFactory.getClass().getMethod("getBeansOfType", Class.class);
78
79 checkState(Stream.of(nativeGetBeansOfTypeMethod, nativeAutowireBeanMethod, nativeCreateBeanMethod, nativeGetBeanMethod).allMatch(Objects::nonNull));
80 } catch (final NoSuchMethodException e) {
81
82 throw new PluginException("Cannot find one or more methods on registered bean factory: " + nativeBeanFactory, e);
83 }
84 }
85
86 private void handleSpringMethodInvocationError(final InvocationTargetException e) {
87 if (e.getCause() instanceof Error) {
88 throw (Error) e.getCause();
89 } else if (e.getCause() instanceof RuntimeException) {
90 throw (RuntimeException) e.getCause();
91 } else {
92
93 throw new PluginException("Unable to invoke createBean", e.getCause());
94 }
95 }
96
97 public <T> T createBean(final Class<T> clazz) {
98 try {
99 return clazz.cast(nativeCreateBeanMethod.invoke(nativeBeanFactory, clazz, AutowireStrategy.AUTOWIRE_BY_CONSTRUCTOR.ordinal(), false));
100 } catch (final IllegalAccessException e) {
101
102 throw new PluginException("Unable to access createBean method", e);
103 } catch (final InvocationTargetException e) {
104 handleSpringMethodInvocationError(e);
105 return null;
106 }
107 }
108
109 @Override
110 public <T> T injectBean(T bean) {
111 try {
112 nativeAutowireBeanMethod.invoke(nativeBeanFactory, bean);
113 } catch (final IllegalAccessException e) {
114
115 throw new PluginException("Unable to access autowireBean method", e);
116 } catch (final InvocationTargetException e) {
117 handleSpringMethodInvocationError(e);
118 }
119 return bean;
120 }
121
122 public <T> Collection<T> getBeansOfType(Class<T> interfaceClass) {
123 try {
124
125 Map<String, T> beans = (Map<String, T>) nativeGetBeansOfTypeMethod.invoke(nativeBeanFactory, interfaceClass);
126 return beans.values();
127 } catch (final IllegalAccessException e) {
128
129 throw new PluginException("Unable to access getBeansOfType method", e);
130 } catch (final InvocationTargetException e) {
131 handleSpringMethodInvocationError(e);
132 return null;
133 }
134 }
135
136 @Override
137 public <T> T getBean(final String id) {
138 try {
139
140 return (T) nativeGetBeanMethod.invoke(nativeBeanFactory, id);
141 } catch (final IllegalAccessException e) {
142
143 throw new PluginException("Unable to access getBean method", e);
144 } catch (final InvocationTargetException e) {
145 handleSpringMethodInvocationError(e);
146 return null;
147 }
148 }
149 }