1 package siouxsie.mvc.spring;
2
3 import java.util.HashMap;
4 import java.util.Map;
5
6 import org.springframework.beans.BeansException;
7 import org.springframework.beans.factory.NoSuchBeanDefinitionException;
8 import org.springframework.beans.factory.UnsatisfiedDependencyException;
9 import org.springframework.beans.factory.config.AutowireCapableBeanFactory;
10 import org.springframework.context.ApplicationContext;
11 import org.springframework.context.ApplicationContextAware;
12 import org.springframework.context.ConfigurableApplicationContext;
13
14 import com.opensymphony.xwork2.ObjectFactory;
15 import com.opensymphony.xwork2.util.logging.Logger;
16 import com.opensymphony.xwork2.util.logging.LoggerFactory;
17
18
19 /**
20 * static Spring object factory.
21 * The application context must be assigned statically
22 * before the factory is used.
23 * Static init is nasty but allows easy sharing of
24 * application contexts.
25 * If the MVC app is standalone, prefer the XW spring object factory
26 * and set the XML files path via the XW container.
27 * Code mainly taken from XW 2.1.
28 * @author Arnaud Cogoluegnes
29 * @version $Id: SpringObjectFactory.java 119 2008-02-24 18:16:32Z acogo $
30 */
31 @SuppressWarnings("unchecked")
32 public class SpringObjectFactory extends ObjectFactory {
33
34 /**
35 *
36 */
37 private static final long serialVersionUID = 8061000508318029222L;
38
39 private static final Logger LOG = LoggerFactory.getLogger(SpringObjectFactory.class);
40
41 protected static ApplicationContext APP_CONTEXT;
42 protected static AutowireCapableBeanFactory autoWiringFactory;
43 protected int autowireStrategy = AutowireCapableBeanFactory.AUTOWIRE_BY_NAME;
44 private Map classes = new HashMap();
45 private boolean useClassCache = true;
46
47 /**
48 * Set the Spring ApplicationContext that should be used to look beans up with.
49 *
50 * @param appContext The Spring ApplicationContext that should be used to look beans up with.
51 */
52 public static void setApplicationContext(ApplicationContext appContext)
53 throws BeansException {
54 APP_CONTEXT = appContext;
55 autoWiringFactory = findAutoWiringBeanFactory(appContext);
56 }
57
58 /**
59 * Sets the autowiring strategy
60 *
61 * @param autowireStrategy
62 */
63 public void setAutowireStrategy(int autowireStrategy) {
64 switch (autowireStrategy) {
65 case AutowireCapableBeanFactory.AUTOWIRE_AUTODETECT:
66 LOG.info("Setting autowire strategy to autodetect");
67 this.autowireStrategy = autowireStrategy;
68 break;
69 case AutowireCapableBeanFactory.AUTOWIRE_BY_NAME:
70 LOG.info("Setting autowire strategy to name");
71 this.autowireStrategy = autowireStrategy;
72 break;
73 case AutowireCapableBeanFactory.AUTOWIRE_BY_TYPE:
74 LOG.info("Setting autowire strategy to type");
75 this.autowireStrategy = autowireStrategy;
76 break;
77 case AutowireCapableBeanFactory.AUTOWIRE_CONSTRUCTOR:
78 LOG.info("Setting autowire strategy to constructor");
79 this.autowireStrategy = autowireStrategy;
80 break;
81 default:
82 throw new IllegalStateException("Invalid autowire type set");
83 }
84 }
85
86 public int getAutowireStrategy() {
87 return autowireStrategy;
88 }
89
90
91 /**
92 * If the given context is assignable to AutowireCapbleBeanFactory or contains a parent or a factory that is, then
93 * set the autoWiringFactory appropriately.
94 *
95 * @param context
96 */
97 protected static AutowireCapableBeanFactory findAutoWiringBeanFactory(ApplicationContext context) {
98 if (context instanceof AutowireCapableBeanFactory) {
99
100 return (AutowireCapableBeanFactory) context;
101 } else if (context instanceof ConfigurableApplicationContext) {
102
103 return ((ConfigurableApplicationContext) context).getBeanFactory();
104 } else if (context.getParent() != null) {
105
106 return findAutoWiringBeanFactory(context.getParent());
107 }
108 return null;
109 }
110
111 /**
112 * Looks up beans using Spring's application context before falling back to the method defined in the {@link
113 * ObjectFactory}.
114 *
115 * @param beanName The name of the bean to look up in the application context
116 * @param extraContext
117 * @return A bean from Spring or the result of calling the overridden
118 * method.
119 * @throws Exception
120 */
121 public Object buildBean(String beanName, Map extraContext, boolean injectInternal) throws Exception {
122 Object o = null;
123 try {
124 o = APP_CONTEXT.getBean(beanName);
125 } catch (NoSuchBeanDefinitionException e) {
126 Class beanClazz = getClassInstance(beanName);
127 o = buildBean(beanClazz, extraContext);
128 }
129 if (injectInternal) {
130 injectInternalBeans(o);
131 }
132 return o;
133 }
134
135 /**
136 * @param clazz
137 * @param extraContext
138 * @throws Exception
139 */
140 public Object buildBean(Class clazz, Map extraContext) throws Exception {
141 Object bean;
142
143 try {
144 bean = autoWiringFactory.autowire(clazz, AutowireCapableBeanFactory.AUTOWIRE_CONSTRUCTOR, false);
145 } catch (UnsatisfiedDependencyException e) {
146
147 bean = super.buildBean(clazz, extraContext);
148 }
149
150 bean = autoWiringFactory.applyBeanPostProcessorsBeforeInitialization(bean, bean.getClass().getName());
151
152 bean = autoWiringFactory.applyBeanPostProcessorsAfterInitialization(bean, bean.getClass().getName());
153 return autoWireBean(bean, autoWiringFactory);
154 }
155
156 public Object autoWireBean(Object bean) {
157 return autoWireBean(bean, autoWiringFactory);
158 }
159
160 /**
161 * @param bean
162 * @param autoWiringFactory
163 */
164 public Object autoWireBean(Object bean, AutowireCapableBeanFactory autoWiringFactory) {
165 if (autoWiringFactory != null) {
166 autoWiringFactory.autowireBeanProperties(bean,
167 autowireStrategy, false);
168 }
169 if (bean instanceof ApplicationContextAware) {
170 ((ApplicationContextAware) bean).setApplicationContext(APP_CONTEXT);
171 }
172
173 injectInternalBeans(bean);
174
175 return bean;
176 }
177
178 public Class getClassInstance(String className) throws ClassNotFoundException {
179 Class clazz = null;
180 if (useClassCache) {
181 synchronized(classes) {
182
183
184 clazz = (Class) classes.get(className);
185 }
186 }
187
188 if (clazz == null) {
189 if (APP_CONTEXT.containsBean(className)) {
190 clazz = APP_CONTEXT.getBean(className).getClass();
191 } else {
192 clazz = super.getClassInstance(className);
193 }
194
195 if (useClassCache) {
196 synchronized(classes) {
197 classes.put(className, clazz);
198 }
199 }
200 }
201
202 return clazz;
203 }
204
205 /**
206 * Allows for ObjectFactory implementations that support
207 * Actions without no-arg constructors.
208 *
209 * @return false
210 */
211 public boolean isNoArgConstructorRequired() {
212 return false;
213 }
214
215 /**
216 * Enable / disable caching of classes loaded by Spring.
217 *
218 * @param useClassCache
219 */
220 public void setUseClassCache(boolean useClassCache) {
221 this.useClassCache = useClassCache;
222 }
223
224
225 }