View Javadoc

1   package com.atlassian.plugin.osgi.spring;
2   
3   import com.atlassian.plugin.PluginException;
4   import com.atlassian.plugin.AutowireCapablePlugin;
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 org.apache.commons.lang.Validate;
12  
13  /**
14   * Manages spring context access, including autowiring.
15   *
16   * @since 2.2.0
17   */
18  public class DefaultSpringContainerAccessor implements SpringContainerAccessor
19  {
20      private final Object nativeBeanFactory;
21      private final Method nativeCreateBeanMethod;
22      private final Method nativeAutowireBeanMethod;
23      private final Method nativeGetBeanMethod;
24      private final Method nativeGetBeansOfTypeMethod;
25  
26      /**
27       * The autowire strategy to use when creating and wiring a bean
28       */
29      private enum AutowireStrategy
30      {
31          AUTOWIRE_NO,
32          /** Performs setter-based injection by name */
33          AUTOWIRE_BY_NAME,
34  
35          /** Performs setter-based injection by type */
36          AUTOWIRE_BY_TYPE,
37  
38          /** Performs construction-based injection by type */
39          AUTOWIRE_BY_CONSTRUCTOR,
40  
41          /**
42           * Autodetects appropriate injection by first seeing if any no-arg constructors exist.  If not, performs constructor
43           * injection, and if so, autowires by type then name
44           */
45          AUTOWIRE_AUTODETECT
46      }
47  
48      public DefaultSpringContainerAccessor(final Object applicationContext)
49      {
50          Object beanFactory = null;
51          try
52          {
53              final Method m = applicationContext.getClass().getMethod("getAutowireCapableBeanFactory");
54              beanFactory = m.invoke(applicationContext);
55          }
56          catch (final NoSuchMethodException e)
57          {
58              // Should never happen
59              throw new PluginException("Cannot find createBean method on registered bean factory: " + beanFactory, e);
60          }
61          catch (final IllegalAccessException e)
62          {
63              // Should never happen
64              throw new PluginException("Cannot access createBean method", e);
65          }
66          catch (final InvocationTargetException e)
67          {
68              handleSpringMethodInvocationError(e);
69          }
70  
71          nativeBeanFactory = beanFactory;
72          try
73          {
74              nativeCreateBeanMethod = beanFactory.getClass().getMethod("createBean", Class.class, int.class, boolean.class);
75              nativeAutowireBeanMethod = beanFactory.getClass().getMethod("autowireBeanProperties", Object.class, int.class, boolean.class);
76              nativeGetBeanMethod = beanFactory.getClass().getMethod("getBean", String.class);
77              nativeGetBeansOfTypeMethod = beanFactory.getClass().getMethod("getBeansOfType", Class.class);
78  
79              Validate.noNullElements(new Object[] {nativeGetBeansOfTypeMethod, nativeAutowireBeanMethod, nativeCreateBeanMethod, nativeGetBeanMethod});
80          }
81          catch (final NoSuchMethodException e)
82          {
83              // Should never happen
84              throw new PluginException("Cannot find one or more methods on registered bean factory: " + nativeBeanFactory, e);
85          }
86      }
87  
88      private void handleSpringMethodInvocationError(final InvocationTargetException e)
89      {
90          if (e.getCause() instanceof Error)
91          {
92              throw (Error) e.getCause();
93          }
94          else if (e.getCause() instanceof RuntimeException)
95          {
96              throw (RuntimeException) e.getCause();
97          }
98          else
99          {
100             // Should never happen as Spring methods only throw runtime exceptions
101             throw new PluginException("Unable to invoke createBean", e.getCause());
102         }
103     }
104 
105     public <T> T createBean(final Class<T> clazz)
106     {
107         try
108         {
109             return clazz.cast(nativeCreateBeanMethod.invoke(nativeBeanFactory, clazz, AutowireStrategy.AUTOWIRE_AUTODETECT.ordinal(), false));
110         }
111         catch (final IllegalAccessException e)
112         {
113             // Should never happen
114             throw new PluginException("Unable to access createBean method", e);
115         }
116         catch (final InvocationTargetException e)
117         {
118             handleSpringMethodInvocationError(e);
119             return null;
120         }
121     }
122 
123     @Override
124     public <T> T injectBean(T bean)
125     {
126         autowireBean(bean, AutowireCapablePlugin.AutowireStrategy.AUTOWIRE_AUTODETECT);
127         return bean;
128     }
129 
130     public <T> Collection<T> getBeansOfType(Class<T> interfaceClass) {
131         try
132         {
133             Map<String, T> beans = (Map<String, T>) nativeGetBeansOfTypeMethod.invoke(nativeBeanFactory, interfaceClass);
134             return beans.values();
135         }
136         catch (final IllegalAccessException e)
137         {
138             // Should never happen
139             throw new PluginException("Unable to access getBeansOfType method", e);
140         }
141         catch (final InvocationTargetException e)
142         {
143             handleSpringMethodInvocationError(e);
144             return null;
145         }
146     }
147 
148     public void autowireBean(final Object instance, AutowireCapablePlugin.AutowireStrategy autowireStrategy)
149     {
150         try
151         {
152             nativeAutowireBeanMethod.invoke(nativeBeanFactory, instance, autowireStrategy.ordinal(), false);
153         }
154         catch (final IllegalAccessException e)
155         {
156             // Should never happen
157             throw new PluginException("Unable to access createBean method", e);
158         }
159         catch (final InvocationTargetException e)
160         {
161             handleSpringMethodInvocationError(e);
162         }
163     }
164 
165     public Object getBean(String id)
166     {
167         try
168         {
169             return nativeGetBeanMethod.invoke(nativeBeanFactory, id);
170         }
171         catch (final IllegalAccessException e)
172         {
173             // Should never happen
174             throw new PluginException("Unable to access getBean method", e);
175         }
176         catch (final InvocationTargetException e)
177         {
178             handleSpringMethodInvocationError(e);
179             return null;
180         }
181     }
182 }