1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18 package org.apache.struts2.plexus;
19
20 import java.util.HashMap;
21 import java.util.Map;
22
23 import javax.servlet.ServletContext;
24
25 import org.apache.commons.logging.Log;
26 import org.apache.commons.logging.LogFactory;
27 import org.apache.struts2.util.ObjectFactoryInitializable;
28 import org.codehaus.plexus.PlexusContainer;
29
30 import com.opensymphony.xwork2.Action;
31 import com.opensymphony.xwork2.ObjectFactory;
32 import com.opensymphony.xwork2.Result;
33 import com.opensymphony.xwork2.config.ConfigurationException;
34 import com.opensymphony.xwork2.config.entities.ActionConfig;
35 import com.opensymphony.xwork2.config.entities.InterceptorConfig;
36 import com.opensymphony.xwork2.config.entities.ResultConfig;
37 import com.opensymphony.xwork2.interceptor.Interceptor;
38 import com.opensymphony.xwork2.util.OgnlUtil;
39 import com.opensymphony.xwork2.validator.Validator;
40
41 /***
42 * Plexus integartion. You need three optional files: plexus-request.xml, plexus-session.xml, and
43 * plexus-application.xml.
44 * <p/>
45 * The syntax of these files is:
46 * <p/>
47 * <pre>
48 * <plexus>
49 * <components>
50 * <component>
51 * <role>com.acme.MyBean</role>
52 * <implementation>com.acme.MyBean|com.acme.MyBeanImpl</implementation>
53 * <componentComposer>field|setter|?</componentComposer>
54 * <requirements>
55 * <requirement>
56 * <role>com.acme.MyOtherBean</role>
57 * </requirement>
58 * </requirements>
59 * <configuration>
60 * <foo>123</foo>
61 * <bar>hello, world</bar>
62 * </configuration>
63 * </component>
64 * </components>
65 * </plexus>
66 * </pre>
67 *
68 * @author <a href="mailto:evenisse@apache.org">Emmanuel Venisse</a>
69 */
70 public class PlexusObjectFactory extends ObjectFactory implements ObjectFactoryInitializable {
71 private static final Log log = LogFactory.getLog(PlexusObjectFactory.class);
72
73 private static final String PLEXUS_COMPONENT_TYPE = "plexus.component.type";
74
75 private PlexusContainer base;
76
77
78
79
80 public void init(ServletContext servletContext) {
81 if (!PlexusLifecycleListener.isLoaded() || !PlexusFilter.isLoaded()) {
82
83 String message = "********** FATAL ERROR STARTING UP PLEXUS-STRUTS INTEGRATION **********\n" +
84 "Looks like the Plexus listener was not configured for your web app! \n" +
85 "You need to add the following to web.xml: \n" +
86 "\n" +
87 " <!-- this should be before the Struts filter -->\n" +
88 " <filter>\n" +
89 " <filter-name>plexus</filter-name>\n" +
90 " <filter-class>org.apache.struts2.plexus.PlexusFilter</filter-class>\n" +
91 " </filter>\n" +
92 "\n" +
93 "...\n" +
94 "\n" +
95 " <!-- this should be before the Struts filter -->\n" +
96 " <filter-mapping>\n" +
97 " <filter-name>plexus</filter-name>\n" +
98 " <url-pattern>/*</url-pattern>\n" +
99 " </filter-mapping>\n" +
100 "\n" +
101 "...\n" +
102 "\n" +
103 " <listener>\n" +
104 " <listener-class>org.apache.struts2.plexus.PlexusLifecycleListener</listener-class>\n" +
105 " </listener>";
106 log.fatal(message);
107 return;
108 }
109
110 base = (PlexusContainer) servletContext.getAttribute(PlexusLifecycleListener.KEY);
111 }
112
113
114
115
116 public Object buildAction(String actionName, String namespace, ActionConfig config, Map extraContext)
117 throws Exception {
118 if (extraContext == null) {
119 extraContext = new HashMap();
120 }
121
122 extraContext.put(PLEXUS_COMPONENT_TYPE, Action.class.getName());
123
124 return super.buildAction(actionName, namespace, config, extraContext);
125 }
126
127
128
129
130 public Interceptor buildInterceptor(InterceptorConfig interceptorConfig, Map interceptorRefParams)
131 throws ConfigurationException {
132 String interceptorClassName = interceptorConfig.getClassName();
133 Map thisInterceptorClassParams = interceptorConfig.getParams();
134 Map params = (thisInterceptorClassParams == null) ? new HashMap() : new HashMap(thisInterceptorClassParams);
135 params.putAll(interceptorRefParams);
136
137 String message;
138 Throwable cause;
139
140 try {
141 Map extraContext = new HashMap();
142 extraContext.put(PLEXUS_COMPONENT_TYPE, Interceptor.class.getName());
143 Interceptor interceptor = (Interceptor) buildBean(interceptorClassName, extraContext);
144 OgnlUtil.setProperties(params, interceptor);
145 interceptor.init();
146
147 return interceptor;
148 }
149 catch (InstantiationException e) {
150 cause = e;
151 message = "Unable to instantiate an instance of Interceptor class [" + interceptorClassName + "].";
152 }
153 catch (IllegalAccessException e) {
154 cause = e;
155 message = "IllegalAccessException while attempting to instantiate an instance of Interceptor class [" + interceptorClassName + "].";
156 }
157 catch (ClassCastException e) {
158 cause = e;
159 message = "Class [" + interceptorClassName + "] does not implement com.opensymphony.xwork2.interceptor.Interceptor";
160 }
161 catch (Exception e) {
162 cause = e;
163 message = "Caught Exception while registering Interceptor class " + interceptorClassName;
164 }
165 catch (NoClassDefFoundError e) {
166 cause = e;
167 message = "Could not load class " + interceptorClassName + ". Perhaps it exists but certain dependencies are not available?";
168 }
169
170 throw new ConfigurationException(message, cause);
171 }
172
173
174
175
176 public Result buildResult(ResultConfig resultConfig, Map extraContext)
177 throws Exception {
178 if (extraContext == null) {
179 extraContext = new HashMap();
180 }
181
182 extraContext.put(PLEXUS_COMPONENT_TYPE, Result.class.getName());
183
184 return super.buildResult(resultConfig, extraContext);
185 }
186
187
188
189
190 public Validator buildValidator(String className, Map params, Map extraContext)
191 throws Exception {
192 Map context = new HashMap();
193 context.put(PLEXUS_COMPONENT_TYPE, Validator.class.getName());
194 Validator validator = (Validator) buildBean(className, context);
195 OgnlUtil.setProperties(params, validator);
196
197 return validator;
198 }
199
200
201
202
203 public Object buildBean(Class clazz, Map extraContext)
204 throws Exception {
205 try {
206 return lookup(clazz.getName(), extraContext);
207 }
208 catch (Exception e) {
209 if (extraContext != null) {
210 String type = (String) extraContext.get(PLEXUS_COMPONENT_TYPE);
211
212 if (type != null) {
213 return lookup(type, clazz.getName(), extraContext);
214 }
215 }
216
217 throw e;
218 }
219 }
220
221
222
223
224 public Class getClassInstance(String className)
225 throws ClassNotFoundException {
226 PlexusContainer pc = PlexusThreadLocal.getPlexusContainer();
227
228 if (pc == null) {
229 pc = base;
230 }
231
232 try {
233 return pc.lookup(className).getClass();
234 }
235 catch (Exception e1) {
236 try {
237 return pc.lookup(Action.class.getName(), className).getClass();
238 }
239 catch (Exception e2) {
240 try {
241 return pc.lookup(Interceptor.class.getName(), className).getClass();
242 }
243 catch (Exception e3) {
244 try {
245 return pc.lookup(Validator.class.getName(), className).getClass();
246 }
247 catch (Exception e4) {
248 try {
249 return pc.lookup(Result.class.getName(), className).getClass();
250 }
251 catch (Exception e5) {
252 return super.getClassInstance(className);
253 }
254 }
255 }
256 }
257 }
258 }
259
260 /***
261 * Looks up an object
262 *
263 * @param role The role name
264 * @param extraContext The extra context
265 * @return The object
266 * @throws Exception If the lookup fails
267 */
268 private Object lookup(String role, Map extraContext)
269 throws Exception {
270 return lookup(role, null, extraContext);
271 }
272
273 /***
274 * Looks up an object
275 *
276 * @param role The role name
277 * @param roleHint The role hint
278 * @param extraContext The extra context
279 * @return The object
280 * @throws Exception If the lookup fails
281 */
282 private Object lookup(String role, String roleHint, Map extraContext)
283 throws Exception {
284 PlexusContainer pc = PlexusThreadLocal.getPlexusContainer();
285
286 if (pc == null) {
287 pc = base;
288 }
289
290 try {
291 return pc.lookup(role, roleHint);
292 }
293 catch (Exception e) {
294 log.debug("Can't load component (" + role + "/" + roleHint + ") with plexus, try now with struts.", e);
295 Object o = super.buildBean(super.getClassInstance(role), extraContext);
296 pc.autowire(o);
297 return o;
298 }
299 }
300 }