1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17 package org.apache.struts.faces.application;
18
19
20 import java.io.IOException;
21 import javax.faces.FactoryFinder;
22 import javax.faces.application.ViewHandler;
23 import javax.faces.component.UICommand;
24 import javax.faces.component.UIComponent;
25 import javax.faces.context.FacesContext;
26 import javax.faces.context.FacesContextFactory;
27 import javax.faces.event.ActionEvent;
28 import javax.faces.lifecycle.Lifecycle;
29 import javax.faces.lifecycle.LifecycleFactory;
30 import javax.servlet.ServletException;
31 import javax.servlet.http.HttpServletRequest;
32 import javax.servlet.http.HttpServletResponse;
33 import org.apache.commons.logging.Log;
34 import org.apache.commons.logging.LogFactory;
35 import org.apache.struts.Globals;
36 import org.apache.struts.action.Action;
37 import org.apache.struts.action.ActionForm;
38 import org.apache.struts.action.ActionForward;
39 import org.apache.struts.action.ActionMapping;
40 import org.apache.struts.action.RequestProcessor;
41 import org.apache.struts.action.InvalidCancelException;
42 import org.apache.struts.config.FormBeanConfig;
43 import org.apache.struts.config.ForwardConfig;
44 import org.apache.struts.faces.Constants;
45 import org.apache.struts.faces.component.FormComponent;
46
47
48
49 /***
50 * <p>Concrete implementation of <code>RequestProcessor</code> that
51 * implements the standard Struts request processing lifecycle on a
52 * request that was received as an <code>ActionEvent</code> by our
53 * associated <code>ActionListener</code>. It replaces the request processor
54 * instance normally configured by Struts, so it must support non-Faces
55 * requests as well.</p>
56 *
57 * @version $Rev: 421138 $ $Date: 2006-07-11 22:41:40 -0700 (Tue, 11 Jul 2006) $
58 */
59
60 public class FacesRequestProcessor extends RequestProcessor {
61
62
63
64
65
66 /***
67 * <p>The log instance for this class.</p>
68 */
69 protected static Log log = LogFactory.getLog(FacesRequestProcessor.class);
70
71
72
73
74
75
76 /***
77 * <p>Set up a Faces Request if we are not already processing one. Next,
78 * create a new view if the specified <code>uri</code> is different from
79 * the current view identifier. Finally, cause the new view to be
80 * rendered, and call <code>FacesContext.responseComplete()</code> to
81 * indicate that this has already been done.</p>
82 *
83 * @param uri Context-relative path to forward to
84 * @param request Current page request
85 * @param response Current page response
86 *
87 * @exception IOException if an input/output error occurs
88 * @exception ServletException if a servlet error occurs
89 */
90 protected void doForward(String uri,
91 HttpServletRequest request,
92 HttpServletResponse response)
93 throws IOException, ServletException {
94
95 if (log.isDebugEnabled()) {
96 log.debug("doForward(" + uri + ")");
97 }
98
99
100 request.removeAttribute(Constants.ACTION_EVENT_KEY);
101
102
103 if (isStrutsRequest(uri)) {
104 if (response.isCommitted()) {
105 if (log.isTraceEnabled()) {
106 log.trace(" super.doInclude(" + uri + ")");
107 }
108 super.doInclude(uri, request, response);
109 } else {
110 if (log.isTraceEnabled()) {
111 log.trace(" super.doForward(" + uri + ")");
112 }
113 super.doForward(uri, request, response);
114 }
115 return;
116 }
117
118
119 LifecycleFactory lf = (LifecycleFactory)
120 FactoryFinder.getFactory(FactoryFinder.LIFECYCLE_FACTORY);
121 Lifecycle lifecycle =
122 lf.getLifecycle(LifecycleFactory.DEFAULT_LIFECYCLE);
123 boolean created = false;
124 FacesContext context = FacesContext.getCurrentInstance();
125 if (context == null) {
126 if (log.isTraceEnabled()) {
127 log.trace(" Creating new FacesContext for '" + uri + "'");
128 }
129 created = true;
130 FacesContextFactory fcf = (FacesContextFactory)
131 FactoryFinder.getFactory(FactoryFinder.FACES_CONTEXT_FACTORY);
132 context = fcf.getFacesContext(servlet.getServletContext(),
133 request, response, lifecycle);
134 }
135
136
137 ViewHandler vh = context.getApplication().getViewHandler();
138 if (log.isTraceEnabled()) {
139 log.trace(" Creating new view for '" + uri + "'");
140 }
141 context.setViewRoot(vh.createView(context, uri));
142
143
144 if (log.isTraceEnabled()) {
145 log.trace(" Rendering view for '" + uri + "'");
146 }
147 try {
148 lifecycle.render(context);
149 } finally {
150 if (created) {
151 if (log.isTraceEnabled()) {
152 log.trace(" Releasing context for '" + uri + "'");
153 }
154 context.release();
155 } else {
156 if (log.isTraceEnabled()) {
157 log.trace(" Rendering completed");
158 }
159 }
160 }
161
162 }
163
164
165
166 protected Action processActionCreate(HttpServletRequest request,
167 HttpServletResponse response,
168 ActionMapping mapping)
169 throws IOException {
170
171 if (log.isTraceEnabled()) {
172 log.trace("Performing standard action create");
173 }
174 Action result = super.processActionCreate(request, response, mapping);
175 if (log.isDebugEnabled()) {
176 log.debug("Standard action create returned " +
177 result.getClass().getName() + " instance");
178 }
179 return (result);
180
181 }
182
183
184
185 protected ActionForm processActionForm(HttpServletRequest request,
186 HttpServletResponse response,
187 ActionMapping mapping) {
188 if (log.isTraceEnabled()) {
189 log.trace("Performing standard action form processing");
190 String attribute = mapping.getAttribute();
191 if (attribute != null) {
192 String name = mapping.getName();
193 FormBeanConfig fbc = moduleConfig.findFormBeanConfig(name);
194 if (fbc != null) {
195 if ("request".equals(mapping.getScope())) {
196 log.trace(" Bean in request scope = " +
197 request.getAttribute(attribute));
198 } else {
199 log.trace(" Bean in session scope = " +
200 request.getSession().getAttribute(attribute));
201 }
202 } else {
203 log.trace(" No FormBeanConfig for '" + name + "'");
204 }
205 } else {
206 log.trace(" No form bean for this action");
207 }
208 }
209 ActionForm result =
210 super.processActionForm(request, response, mapping);
211 if (log.isDebugEnabled()) {
212 log.debug("Standard action form returned " +
213 result);
214 }
215 return (result);
216
217
218 }
219
220
221
222 protected ActionForward processActionPerform(HttpServletRequest request,
223 HttpServletResponse response,
224 Action action,
225 ActionForm form,
226 ActionMapping mapping)
227 throws IOException, ServletException {
228
229 if (log.isTraceEnabled()) {
230 log.trace("Performing standard action perform");
231 }
232 ActionForward result =
233 super.processActionPerform(request, response, action,
234 form, mapping);
235 if (log.isDebugEnabled()) {
236 log.debug("Standard action perform returned " +
237 (result == null ? "NULL" :
238 result.getPath()) + " forward path");
239 }
240 return (result);
241
242 }
243
244
245
246 protected boolean processForward(HttpServletRequest request,
247 HttpServletResponse response,
248 ActionMapping mapping)
249 throws IOException, ServletException {
250
251 if (log.isTraceEnabled()) {
252 log.trace("Performing standard forward handling");
253 }
254 boolean result = super.processForward
255 (request, response, mapping);
256 if (log.isDebugEnabled()) {
257 log.debug("Standard forward handling returned " + result);
258 }
259 return (result);
260
261 }
262
263
264
265 protected void processForwardConfig(HttpServletRequest request,
266 HttpServletResponse response,
267 ForwardConfig forward)
268 throws IOException, ServletException {
269
270 if (log.isTraceEnabled()) {
271 log.trace("Performing standard forward config handling");
272 }
273 super.processForwardConfig(request, response, forward);
274 if (log.isDebugEnabled()) {
275 log.debug("Standard forward config handling completed");
276 }
277
278 }
279
280
281
282 protected boolean processInclude(HttpServletRequest request,
283 HttpServletResponse response,
284 ActionMapping mapping)
285 throws IOException, ServletException {
286
287 if (log.isTraceEnabled()) {
288 log.trace("Performing standard include handling");
289 }
290 boolean result = super.processInclude
291 (request, response, mapping);
292 if (log.isDebugEnabled()) {
293 log.debug("Standard include handling returned " + result);
294 }
295 return (result);
296
297 }
298
299
300 /***
301 * <p>Identify and return the path component (from the request URI for a
302 * non-Faces request, or from the form event for a Faces request)
303 * that we will use to select an ActionMapping to dispatch with.
304 * If no such path can be identified, create an error response and return
305 * <code>null</code>.</p>
306 *
307 * @param request The servlet request we are processing
308 * @param response The servlet response we are creating
309 *
310 * @exception IOException if an input/output error occurs
311 */
312 protected String processPath(HttpServletRequest request,
313 HttpServletResponse response)
314 throws IOException {
315
316
317 ActionEvent event = (ActionEvent)
318 request.getAttribute(Constants.ACTION_EVENT_KEY);
319
320
321 if (event == null) {
322 if (log.isTraceEnabled()) {
323 log.trace("Performing standard processPath() processing");
324 }
325 return (super.processPath(request, response));
326 }
327
328
329 UIComponent component = event.getComponent();
330 if (log.isTraceEnabled()) {
331 log.trace("Locating form parent for command component " +
332 event.getComponent());
333 }
334 while (!(component instanceof FormComponent)) {
335 component = component.getParent();
336 if (component == null) {
337 log.warn("Command component was not nested in a Struts form!");
338 return (null);
339 }
340 }
341 if (log.isDebugEnabled()) {
342 log.debug("Returning selected path of '" +
343 ((FormComponent) component).getAction() + "'");
344 }
345 return (((FormComponent) component).getAction());
346
347 }
348
349
350 /***
351 * <p>Populate the properties of the specified <code>ActionForm</code>
352 * instance from the request parameters included with this request,
353 * <strong>IF</strong> this is a non-Faces request. For a Faces request,
354 * this will have already been done by the <em>Update Model Values</em>
355 * phase of the request processing lifecycle, so all we have to do is
356 * recognize whether the request was cancelled or not.</p>
357 *
358 * @param request The servlet request we are processing
359 * @param response The servlet response we are creating
360 * @param form The ActionForm instance we are populating
361 * @param mapping The ActionMapping we are using
362 *
363 * @exception ServletException if thrown by RequestUtils.populate()
364 */
365 protected void processPopulate(HttpServletRequest request,
366 HttpServletResponse response,
367 ActionForm form,
368 ActionMapping mapping)
369 throws ServletException {
370
371
372 ActionEvent event = (ActionEvent)
373 request.getAttribute(Constants.ACTION_EVENT_KEY);
374
375
376 if (event == null) {
377 if (log.isTraceEnabled()) {
378 log.trace("Performing standard processPopulate() processing");
379 }
380 super.processPopulate(request, response, form, mapping);
381 return;
382 }
383
384
385
386 if (log.isTraceEnabled()) {
387 log.trace("Faces request, so no processPopulate() processing");
388 }
389 UIComponent source = event.getComponent();
390 if (source instanceof UICommand) {
391 if ("cancel".equals(((UICommand) source).getId())) {
392 if (log.isTraceEnabled()) {
393 log.trace("Faces request with cancel button pressed");
394 }
395 request.setAttribute(Globals.CANCEL_KEY, Boolean.TRUE);
396 }
397 }
398
399 }
400
401
402
403 protected boolean processValidate(HttpServletRequest request,
404 HttpServletResponse response,
405 ActionForm form,
406 ActionMapping mapping)
407 throws IOException, ServletException, InvalidCancelException {
408
409 if (log.isTraceEnabled()) {
410 log.trace("Performing standard validation");
411 }
412 boolean result = super.processValidate
413 (request, response, form, mapping);
414 if (log.isDebugEnabled()) {
415 log.debug("Standard validation processing returned " + result);
416 }
417 return (result);
418
419 }
420
421
422
423
424
425 /***
426 * <p>Return <code>true</code> if the specified context-relative URI
427 * specifies a request to be processed by the Struts controller servlet.</p>
428 *
429 * @param uri URI to be checked
430 */
431 private boolean isStrutsRequest(String uri) {
432
433 int question = uri.indexOf("?");
434 if (question >= 0) {
435 uri = uri.substring(0, question);
436 }
437 String mapping = (String)
438 servlet.getServletContext().getAttribute(Globals.SERVLET_KEY);
439 if (mapping == null) {
440 return (false);
441 } else if (mapping.startsWith("*.")) {
442 return (uri.endsWith(mapping.substring(1)));
443 } else if (mapping.endsWith("/*")) {
444 return (uri.startsWith(mapping.substring(0, mapping.length() - 2)));
445 } else {
446 return (false);
447 }
448
449 }
450
451
452 }