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     public <T> Collection<T> getBeansOfType(Class<T> interfaceClass) {
124         try
125         {
126             Map<String, T> beans = (Map<String, T>) nativeGetBeansOfTypeMethod.invoke(nativeBeanFactory, interfaceClass);
127             return beans.values();
128         }
129         catch (final IllegalAccessException e)
130         {
131             // Should never happen
132             throw new PluginException("Unable to access getBeansOfType method", e);
133         }
134         catch (final InvocationTargetException e)
135         {
136             handleSpringMethodInvocationError(e);
137             return null;
138         }
139     }
140 
141     public void autowireBean(final Object instance, AutowireCapablePlugin.AutowireStrategy autowireStrategy)
142     {
143         try
144         {
145             nativeAutowireBeanMethod.invoke(nativeBeanFactory, instance, autowireStrategy.ordinal(), false);
146         }
147         catch (final IllegalAccessException e)
148         {
149             // Should never happen
150             throw new PluginException("Unable to access createBean method", e);
151         }
152         catch (final InvocationTargetException e)
153         {
154             handleSpringMethodInvocationError(e);
155         }
156     }
157 
158     public Object getBean(String id)
159     {
160         try
161         {
162             return nativeGetBeanMethod.invoke(nativeBeanFactory, id);
163         }
164         catch (final IllegalAccessException e)
165         {
166             // Should never happen
167             throw new PluginException("Unable to access getBean method", e);
168         }
169         catch (final InvocationTargetException e)
170         {
171             handleSpringMethodInvocationError(e);
172             return null;
173         }
174     }
175 }