1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21 package org.apache.struts.chain;
22
23 import java.io.IOException;
24 import java.lang.reflect.Constructor;
25
26 import jakarta.servlet.ServletContext;
27 import jakarta.servlet.ServletException;
28 import jakarta.servlet.UnavailableException;
29 import jakarta.servlet.http.HttpServletRequest;
30 import jakarta.servlet.http.HttpServletResponse;
31
32 import org.apache.commons.beanutils.ConstructorUtils;
33 import org.apache.commons.chain.Catalog;
34 import org.apache.commons.chain.CatalogFactory;
35 import org.apache.commons.chain.Command;
36 import org.apache.struts.action.ActionServlet;
37 import org.apache.struts.action.RequestProcessor;
38 import org.apache.struts.chain.contexts.ActionContext;
39 import org.apache.struts.chain.contexts.ServletActionContext;
40 import org.apache.struts.config.ControllerConfig;
41 import org.apache.struts.config.ModuleConfig;
42 import org.apache.struts.upload.MultipartRequestWrapper;
43 import org.apache.struts.util.RequestUtils;
44 import org.slf4j.Logger;
45 import org.slf4j.LoggerFactory;
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67 public class ComposableRequestProcessor extends RequestProcessor {
68 private static final long serialVersionUID = -1205090974097129899L;
69
70
71
72
73
74
75 private static final Class<?>[] SERVLET_ACTION_CONTEXT_CTOR_SIGNATURE =
76 {
77 ServletContext.class, HttpServletRequest.class,
78 HttpServletResponse.class
79 };
80
81
82
83
84
85 public static final String ACTION_CONTEXT_CLASS = "ACTION_CONTEXT_CLASS";
86
87
88
89
90 private transient final Logger log =
91 LoggerFactory.getLogger(ComposableRequestProcessor.class);
92
93
94
95
96
97 protected CatalogFactory<ActionContext> catalogFactory = null;
98
99
100
101
102
103 protected Catalog<ActionContext> catalog = null;
104
105
106
107
108 protected Command<ActionContext> command = null;
109
110
111
112
113 private Class<? extends ActionContext> actionContextClass;
114
115
116
117
118
119 private Constructor<? extends ActionContext> servletActionContextConstructor = null;
120
121
122
123
124
125
126 public void destroy() {
127 super.destroy();
128 catalogFactory = null;
129 catalog = null;
130 command = null;
131 actionContextClass = null;
132 servletActionContextConstructor = null;
133 }
134
135
136
137
138
139
140
141
142
143 public void init(ActionServlet servlet, ModuleConfig moduleConfig)
144 throws ServletException {
145 log.info(
146 "Initializing composable request processor for module prefix '"
147 + moduleConfig.getPrefix() + "'");
148 super.init(servlet, moduleConfig);
149
150 initCatalogFactory(servlet, moduleConfig);
151
152 ControllerConfig controllerConfig = moduleConfig.getControllerConfig();
153
154 String catalogName = controllerConfig.getCatalog();
155
156 catalog = this.catalogFactory.getCatalog(catalogName);
157
158 if (catalog == null) {
159 throw new ServletException("Cannot find catalog '" + catalogName
160 + "'");
161 }
162
163 String commandName = controllerConfig.getCommand();
164
165 command = catalog.getCommand(commandName);
166
167 if (command == null) {
168 throw new ServletException("Cannot find command '" + commandName
169 + "'");
170 }
171
172 this.setActionContextClassName(controllerConfig.getProperty(
173 ACTION_CONTEXT_CLASS));
174 }
175
176
177
178
179
180
181
182
183
184
185 private void setActionContextClass(Class<? extends ActionContext> actionContextClass) {
186 this.actionContextClass = actionContextClass;
187
188 if (actionContextClass != null) {
189 this.servletActionContextConstructor =
190 ConstructorUtils.getAccessibleConstructor(actionContextClass,
191 SERVLET_ACTION_CONTEXT_CTOR_SIGNATURE);
192 } else {
193 this.servletActionContextConstructor = null;
194 }
195 }
196
197
198
199
200
201
202
203
204
205
206
207 private void setActionContextClassName(String className)
208 throws ServletException {
209 if ((className != null) && (className.trim().length() > 0)) {
210 if (log.isDebugEnabled()) {
211 log.debug(
212 "setActionContextClassName: requested context class: "
213 + className);
214 }
215
216 try {
217 Class<?> actionContextClass =
218 RequestUtils.applicationClass(className);
219
220 if (!ActionContext.class.isAssignableFrom(actionContextClass)) {
221 throw new UnavailableException("ActionContextClass " + "["
222 + className + "]"
223 + " must implement ActionContext interface.");
224 }
225
226 this.setActionContextClass(actionContextClass.asSubclass(ActionContext.class));
227 } catch (ClassNotFoundException e) {
228 throw new UnavailableException("ActionContextClass "
229 + className + " not found.");
230 }
231 } else {
232 if (log.isDebugEnabled()) {
233 log.debug("setActionContextClassName: no className specified");
234 }
235
236 this.setActionContextClass(null);
237 }
238 }
239
240
241
242
243
244
245
246
247
248
249
250
251 protected void initCatalogFactory(ActionServlet servlet,
252 ModuleConfig moduleConfig) {
253 if (this.catalogFactory != null) {
254 return;
255 }
256
257 this.catalogFactory = CatalogFactory.getInstance();
258 }
259
260
261
262
263
264
265
266
267
268
269
270 public void process(HttpServletRequest request, HttpServletResponse response)
271 throws IOException, ServletException {
272
273 request = processMultipart(request);
274
275
276 ActionContext context = contextInstance(request, response);
277
278
279 try {
280 if (log.isDebugEnabled()) {
281 log.debug("Using processing chain for this request");
282 }
283
284 command.execute(context);
285 } catch (Exception e) {
286
287 throw new ServletException(e);
288 } finally {
289
290 if (context != null) {
291 context.release();
292 }
293 }
294 }
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309 protected ActionContext contextInstance(HttpServletRequest request,
310 HttpServletResponse response)
311 throws ServletException {
312 ActionContext context =
313 createActionContextInstance(getServletContext(), request, response);
314
315 initializeActionContext(context);
316
317 return context;
318 }
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340 protected ActionContext createActionContextInstance(
341 ServletContext servletContext, HttpServletRequest request,
342 HttpServletResponse response)
343 throws ServletException {
344 if (this.actionContextClass == null) {
345 return new ServletActionContext(servletContext, request, response);
346 }
347
348 try {
349 if (this.servletActionContextConstructor == null) {
350 return this.actionContextClass.getDeclaredConstructor().newInstance();
351 }
352
353 return this.servletActionContextConstructor
354 .newInstance(servletContext, request, response);
355 } catch (Exception e) {
356 throw new ServletException(
357 "Error creating ActionContext instance of type "
358 + this.actionContextClass, e);
359 }
360 }
361
362
363
364
365
366
367
368
369
370
371
372 protected void initializeActionContext(ActionContext context) {
373 if (context instanceof ServletActionContext) {
374 ((ServletActionContext) context).setActionServlet(this.servlet);
375 }
376
377 context.setModuleConfig(this.moduleConfig);
378 }
379
380
381
382
383
384
385
386
387
388 protected HttpServletRequest processMultipart(HttpServletRequest request) {
389 if (!"POST".equalsIgnoreCase(request.getMethod())) {
390 return (request);
391 }
392
393 String contentType = request.getContentType();
394
395 if ((contentType != null)
396 && contentType.startsWith("multipart/form-data")) {
397 return (new MultipartRequestWrapper(request));
398 } else {
399 return (request);
400 }
401 }
402
403
404
405
406
407
408
409
410
411 public void setCatalogFactory(CatalogFactory<ActionContext> catalogFactory) {
412 this.catalogFactory = catalogFactory;
413 }
414 }