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