KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > apache > beehive > netui > pageflow > PageFlowRequestProcessor


1 /*
2  * Copyright 2004 The Apache Software Foundation.
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  * http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  *
16  * $Header:$
17  */

18 package org.apache.beehive.netui.pageflow;
19
20 import org.apache.beehive.netui.util.internal.InternalStringBuilder;
21
22 import org.apache.beehive.netui.core.urls.URLRewriterService;
23 import org.apache.beehive.netui.pageflow.config.PageFlowActionForward;
24 import org.apache.beehive.netui.pageflow.config.PageFlowActionMapping;
25 import org.apache.beehive.netui.pageflow.handler.ActionForwardHandler;
26 import org.apache.beehive.netui.pageflow.handler.FlowControllerHandlerContext;
27 import org.apache.beehive.netui.pageflow.handler.ForwardRedirectHandler;
28 import org.apache.beehive.netui.pageflow.handler.Handlers;
29 import org.apache.beehive.netui.pageflow.handler.LoginHandler;
30 import org.apache.beehive.netui.pageflow.handler.ReloadableClassHandler;
31 import org.apache.beehive.netui.pageflow.interceptor.InterceptorException;
32 import org.apache.beehive.netui.pageflow.interceptor.Interceptors;
33 import org.apache.beehive.netui.pageflow.interceptor.Interceptor;
34 import org.apache.beehive.netui.pageflow.interceptor.action.ActionInterceptorContext;
35 import org.apache.beehive.netui.pageflow.interceptor.action.InterceptorForward;
36 import org.apache.beehive.netui.pageflow.interceptor.action.internal.ActionInterceptors;
37 import org.apache.beehive.netui.pageflow.interceptor.request.RequestInterceptorContext;
38 import org.apache.beehive.netui.pageflow.internal.AdapterManager;
39 import org.apache.beehive.netui.pageflow.internal.DefaultURLRewriter;
40 import org.apache.beehive.netui.pageflow.internal.FlowControllerAction;
41 import org.apache.beehive.netui.pageflow.internal.InternalUtils;
42 import org.apache.beehive.netui.pageflow.internal.JavaControlUtils;
43 import org.apache.beehive.netui.pageflow.internal.LegacySettings;
44 import org.apache.beehive.netui.pageflow.internal.PageFlowRequestWrapper;
45 import org.apache.beehive.netui.pageflow.internal.InternalConstants;
46 import org.apache.beehive.netui.pageflow.scoping.ScopedRequest;
47 import org.apache.beehive.netui.pageflow.scoping.ScopedServletUtils;
48 import org.apache.beehive.netui.script.common.ImplicitObjectUtil;
49 import org.apache.beehive.netui.util.internal.DiscoveryUtils;
50 import org.apache.beehive.netui.util.internal.FileUtils;
51 import org.apache.beehive.netui.util.internal.ServletUtils;
52 import org.apache.beehive.netui.util.config.ConfigUtil;
53 import org.apache.beehive.netui.util.config.bean.PageflowConfig;
54 import org.apache.beehive.netui.util.logging.Logger;
55 import org.apache.struts.Globals;
56 import org.apache.struts.action.Action;
57 import org.apache.struts.action.ActionForm;
58 import org.apache.struts.action.ActionForward;
59 import org.apache.struts.action.ActionMapping;
60 import org.apache.struts.action.ActionServlet;
61 import org.apache.struts.action.DynaActionForm;
62 import org.apache.struts.action.DynaActionFormClass;
63 import org.apache.struts.config.ActionConfig;
64 import org.apache.struts.config.FormBeanConfig;
65 import org.apache.struts.config.ForwardConfig;
66 import org.apache.struts.config.ModuleConfig;
67 import org.apache.struts.tiles.TilesRequestProcessor;
68 import org.apache.struts.tiles.TilesUtil;
69 import org.apache.struts.tiles.TilesUtilImpl;
70 import org.apache.struts.tiles.TilesUtilStrutsImpl;
71 import org.apache.struts.upload.MultipartRequestHandler;
72 import org.apache.struts.upload.MultipartRequestWrapper;
73 import org.apache.struts.util.RequestUtils;
74 import org.apache.struts.util.TokenProcessor;
75
76 import javax.servlet.FilterChain JavaDoc;
77 import javax.servlet.Servlet JavaDoc;
78 import javax.servlet.ServletConfig JavaDoc;
79 import javax.servlet.ServletContext JavaDoc;
80 import javax.servlet.ServletException JavaDoc;
81 import javax.servlet.ServletRequest JavaDoc;
82 import javax.servlet.ServletResponse JavaDoc;
83 import javax.servlet.http.HttpServletRequest JavaDoc;
84 import javax.servlet.http.HttpServletResponse JavaDoc;
85 import javax.servlet.http.HttpSession JavaDoc;
86 import java.io.IOException JavaDoc;
87 import java.io.InputStream JavaDoc;
88 import java.io.Serializable JavaDoc;
89 import java.lang.reflect.Field JavaDoc;
90 import java.net.URI JavaDoc;
91 import java.net.URISyntaxException JavaDoc;
92 import java.util.ArrayList JavaDoc;
93 import java.util.Collections JavaDoc;
94 import java.util.Enumeration JavaDoc;
95 import java.util.HashMap JavaDoc;
96 import java.util.Iterator JavaDoc;
97 import java.util.List JavaDoc;
98 import java.util.Map JavaDoc;
99 import java.util.Properties JavaDoc;
100 import java.util.Set JavaDoc;
101 import org.apache.beehive.netui.util.internal.concurrent.InternalConcurrentHashMap;
102
103
104 /**
105  * The Page Flow extension of the Struts RequestProcessor, which contains callbacks that are invoked
106  * during processing of a request to the Struts action servlet. This class is registered as the
107  * <strong>controller</strong> for all Struts modules derived from page flows.
108  */

109 public class PageFlowRequestProcessor
110         extends TilesRequestProcessor
111         implements Serializable JavaDoc, InternalConstants, PageFlowConstants
112 {
113     private static int requestCount = 0;
114
115     private static final Logger _log = Logger.getInstance( PageFlowRequestProcessor.class );
116     
117     private static final String JavaDoc ACTION_OVERRIDE_PARAM_PREFIX = "actionOverride:";
118     private static final int ACTION_OVERRIDE_PARAM_PREFIX_LEN = ACTION_OVERRIDE_PARAM_PREFIX.length();
119     private static final String JavaDoc SCHEME_UNSECURE = "http";
120     private static final String JavaDoc SCHEME_SECURE = "https";
121     private static final String JavaDoc REDIRECT_REQUEST_ATTRS_PREFIX = InternalConstants.ATTR_PREFIX + "requestAttrs:";
122     private static final String JavaDoc REDIRECT_REQUEST_ATTRS_PARAM = "forceRedirect";
123     private static final String JavaDoc FLOW_CONTROLLER_ACTION_CLASSNAME = FlowControllerAction.class.getName();
124     
125     private Map JavaDoc/*< String, Class >*/ _formBeanClasses = new HashMap JavaDoc/*< String, Class >*/();
126     private Map JavaDoc/*< String, List< ActionMapping > >*/ _overloadedActions = new HashMap JavaDoc/*< String, List< ActionMapping > >*/();
127     private ServletContainerAdapter _servletContainerAdapter;
128     private Handlers _handlers;
129     private FlowControllerFactory _flowControllerFactory;
130     private LegacySettings _legacySettings;
131     private InternalConcurrentHashMap/*< String, Class >*/ _pageServletClasses = new InternalConcurrentHashMap/*< String, Class >*/();
132     private PageFlowPageFilter _pageServletFilter;
133     
134
135     protected Action processActionCreate( HttpServletRequest JavaDoc request, HttpServletResponse JavaDoc response,
136                                           ActionMapping actionMapping )
137         throws IOException JavaDoc
138     {
139         String JavaDoc className = actionMapping.getType();
140
141         if ( className != null && className.equals( FLOW_CONTROLLER_ACTION_CLASSNAME ) )
142         {
143             FlowController fc = PageFlowRequestWrapper.get( request ).getCurrentFlowController();
144             assert fc != null : "no FlowController for request " + request.getRequestURI();
145             assert fc.getClass().getName().equals( actionMapping.getParameter() )
146                     : "current page flow type " + fc.getClass().getName() + " does not match type specified in "
147                       + FLOW_CONTROLLER_ACTION_CLASSNAME + ": " + actionMapping.getParameter();
148             
149             Action action = new FlowControllerAction( fc );
150             action.setServlet( servlet );
151             return action;
152         }
153
154         return super.processActionCreate( request, response, actionMapping );
155     }
156
157     /**
158      * Same as code in RequestUtils.createActionForm(), but doesn't try to get the form bean out of
159      * the request/session (i.e., always creates a new one).
160      */

161     private ActionForm createActionForm( ActionMapping mapping, HttpServletRequest JavaDoc request )
162     {
163         String JavaDoc name = mapping.getName();
164
165         assert name != null : mapping.getPath();
166         if ( name == null ) return null;
167
168         FormBeanConfig config = moduleConfig.findFormBeanConfig( name );
169         ActionForm instance;
170         
171         //
172
// Create the form bean. There's special handling for dyna-form-beans.
173
//
174
if ( config.getDynamic() )
175         {
176             try
177             {
178                 DynaActionFormClass dynaClass = DynaActionFormClass.createDynaActionFormClass( config );
179                 instance = ( ActionForm ) dynaClass.newInstance();
180                 ( ( DynaActionForm ) instance ).initialize( mapping );
181                 
182                 if ( _log.isDebugEnabled() )
183                 {
184                     _log.debug( " Creating new DynaActionForm instance " + "of type '" + config.getType() + '\'' );
185                 }
186             }
187             catch ( Exception JavaDoc e )
188             {
189                 _log.error( servlet.getInternal().getMessage( "formBean", config.getType() ), e );
190                 return null;
191             }
192         }
193         else
194         {
195             try
196             {
197                 instance = ( ActionForm ) InternalUtils.newReloadableInstance( config.getType(), getServletContext() );
198                 
199                 if ( _log.isDebugEnabled() )
200                 {
201                     _log.debug( " Creating new ActionForm instance " + "of type '" + config.getType() + '\'' );
202                 }
203             }
204             catch ( Exception JavaDoc e )
205             {
206                 _log.error( servlet.getInternal().getMessage( "formBean", config.getType() ), e );
207                 return null;
208             }
209         }
210         
211         instance.setServlet( servlet );
212         return instance;
213     }
214     
215     private Field JavaDoc getPageFlowScopedFormMember( ActionMapping mapping, HttpServletRequest JavaDoc request )
216     {
217         if ( mapping instanceof PageFlowActionMapping )
218         {
219             PageFlowActionMapping pfam = ( PageFlowActionMapping ) mapping;
220             String JavaDoc formMember = pfam.getFormMember();
221             
222             try
223             {
224                 if ( formMember != null )
225                 {
226                     FlowController fc = PageFlowRequestWrapper.get( request ).getCurrentFlowController();
227                     Field JavaDoc field = fc.getClass().getDeclaredField( formMember );
228                     field.setAccessible( true );
229                     return field;
230                 }
231             }
232             catch ( Exception JavaDoc e )
233             {
234                 _log.error( "Could not use page flow member " + formMember + " as the form bean.", e );
235             }
236         }
237         
238         return null;
239     }
240     
241     protected ActionForm processActionForm( HttpServletRequest JavaDoc request, HttpServletResponse JavaDoc response,
242                                             ActionMapping mapping )
243     {
244         //
245
// See if we're using a pageflow-scoped form (a member variable in the current pageflow).
246
//
247
Field JavaDoc formMemberField = getPageFlowScopedFormMember( mapping, request );
248         
249         //
250
// First look to see whether the input form was overridden in the request.
251
// This happens when a pageflow action forwards to another pageflow,
252
// whose begin action expects a form. In this case, the form is already
253
// constructed, and shouldn't be instantiated anew or populated from request
254
// parameters.
255
//
256
ActionForm previousForm = InternalUtils.getForwardedFormBean( request, false );
257         
258         if ( previousForm != null )
259         {
260             //
261
// If there was a forwarded form, and if this action specifies a pageflow-scoped form member,
262
// set the member with this form.
263
//
264
if ( formMemberField != null )
265             {
266                 try
267                 {
268                     FlowController fc = PageFlowRequestWrapper.get( request ).getCurrentFlowController();
269                     assert fc != null : "no FlowController in request " + request.getRequestURI();
270                     formMemberField.set( fc, InternalUtils.unwrapFormBean( previousForm ) );
271                 }
272                 catch ( IllegalAccessException JavaDoc e )
273                 {
274                     _log.error( "Could not access page flow member " + formMemberField.getName()
275                                   + " as the form bean.", e );
276                 }
277             }
278             
279             //
280
// Return the forwarded form.
281
//
282
previousForm.setServlet( servlet );
283             return previousForm;
284         }
285         
286         //
287
// First see if the previous action put a pageflow-scoped form in the request. If so, remove it;
288
// we don't want a normal request-scoped action to use this pageflow-scoped form.
289
//
290
String JavaDoc pageFlowScopedFormName = PageFlowRequestWrapper.get( request ).getPageFlowScopedFormName();
291         if ( pageFlowScopedFormName != null )
292         {
293             request.removeAttribute( pageFlowScopedFormName );
294             PageFlowRequestWrapper.get( request ).setPageFlowScopedFormName( null );
295         }
296         
297         //
298
// If this action specifies a pageflow-scoped form member variable, use it.
299
//
300
if ( formMemberField != null )
301         {
302             try
303             {
304                 FlowController fc = PageFlowRequestWrapper.get( request ).getCurrentFlowController();
305                 ActionForm form = InternalUtils.wrapFormBean( formMemberField.get( fc ) );
306                 
307                 if ( form == null ) // the pageflow hasn't filled the value yet
308
{
309                     form = createActionForm( mapping, request );
310                     form.reset( mapping, request );
311                     formMemberField.set( fc, InternalUtils.unwrapFormBean( form ) );
312                 }
313                 
314                 //
315
// Store the form in the right place in the request, so Struts can see it.
316
// But, mark a flag so we know to remove this on the next action request -- we don't
317
// want this form used by another action unless that action uses the pageflow-scoped
318
// form.
319
//
320
String JavaDoc formAttrName = mapping.getAttribute();
321                 request.setAttribute( formAttrName, form );
322                 PageFlowRequestWrapper.get( request ).setPageFlowScopedFormName( formAttrName );
323                 return form;
324             }
325             catch ( IllegalAccessException JavaDoc e )
326             {
327                 _log.error( "Could not access page flow member " + formMemberField.getName() + " as the form bean.", e );
328             }
329         }
330         
331         ActionForm bean = super.processActionForm( request, response, mapping );
332         if ( bean == null )
333         {
334             bean = InternalUtils.createActionForm( mapping, moduleConfig, servlet, getServletContext() );
335         }
336         
337         return bean;
338     }
339     
340     protected void processPopulate( HttpServletRequest JavaDoc request, HttpServletResponse JavaDoc response, ActionForm form,
341                                     ActionMapping mapping )
342         throws ServletException JavaDoc
343     {
344         //
345
// If a previous action forwarded us a form, use that -- don't populate it from request parameters.
346
//
347
ActionForm previousForm = InternalUtils.getForwardedFormBean( request, true );
348
349         if ( previousForm != null )
350         {
351             return;
352         }
353
354         if ( _log.isDebugEnabled() )
355         {
356             _log.debug( "Populating bean properties from this request" );
357         }
358
359         // struts does this
360
if ( form != null )
361         {
362             form.setServlet( servlet );
363             form.reset( mapping, request );
364         }
365
366         if ( mapping.getMultipartClass() != null )
367         {
368             request.setAttribute( Globals.MULTIPART_KEY, mapping.getMultipartClass() );
369         }
370
371         PageFlowRequestWrapper requestWrapper = PageFlowRequestWrapper.get( request );
372         boolean alreadyCalledInRequest = requestWrapper.isProcessPopulateAlreadyCalled();
373         if ( ! alreadyCalledInRequest ) requestWrapper.setProcessPopulateAlreadyCalled( true );
374         
375         //
376
// If this is a forwarded request and the form-bean is null, don't call to ProcessPopulate.
377
// We don't want to expose errors due to parameters from the original request, which won't
378
// apply to a forwarded action that doesn't take a form.
379
//
380
if ( !alreadyCalledInRequest || form != null )
381         {
382             ProcessPopulate.populate( request, response, form, alreadyCalledInRequest );
383         }
384     }
385
386     /**
387      * The requested action can be overridden by a request parameter. In this case, we parse the action from
388      * the request parameter and forward to a URI constructed from it.
389      *
390      * @param request the current HttpServletRequest
391      * @param response the current HttpServletResponse
392      * @return <code>true</code> if the action was overridden by a request parameter, in which case the request
393      * was forwarded.
394      * @throws IOException
395      * @throws ServletException
396      */

397     protected boolean processActionOverride( HttpServletRequest JavaDoc request, HttpServletResponse JavaDoc response )
398         throws IOException JavaDoc, ServletException JavaDoc
399     {
400         // Only make this check if this is an initial (non-forwarded) request.
401
//
402
// TODO: performance?
403
//
404
PageFlowRequestWrapper wrapper = PageFlowRequestWrapper.get( request );
405         if ( ! wrapper.isForwardedByButton() )
406         {
407             wrapper.setForwardedByButton( true );
408             
409             //
410
// First, since we need access to request parameters here, process a multipart request
411
// if that's what we have. This puts the parameters (each in a MIME part) behind an
412
// interface that makes them look like normal request parameters.
413
//
414
HttpServletRequest JavaDoc multipartAwareRequest = processMultipart( request );
415             
416             for ( Enumeration JavaDoc e = multipartAwareRequest.getParameterNames(); e.hasMoreElements(); )
417             {
418                 String JavaDoc paramName = ( String JavaDoc ) e.nextElement();
419
420                 if ( paramName.startsWith( ACTION_OVERRIDE_PARAM_PREFIX ) )
421                 {
422                     String JavaDoc actionPath = paramName.substring( ACTION_OVERRIDE_PARAM_PREFIX_LEN );
423                     ServletContext JavaDoc servletContext = getServletContext();
424
425                     String JavaDoc qualifiedAction = InternalUtils.qualifyAction( servletContext,actionPath );
426                     actionPath = InternalUtils.createActionPath(request, qualifiedAction );
427
428                     if ( _log.isDebugEnabled() )
429                     {
430                         _log.debug( "A request parameter overrode the action. Forwarding to: " + actionPath );
431                     }
432
433                     doForward( actionPath, request, response );
434                     return true;
435                 }
436             }
437         }
438         
439         return false;
440     }
441     
442     private void processInternal( HttpServletRequest JavaDoc request, HttpServletResponse JavaDoc response )
443             throws IOException JavaDoc, ServletException JavaDoc
444     {
445         //
446
// First wrap the request with an object that contains request-scoped values that our runtime uses. This
447
// is faster than sticking everything into attributes on the request (then basically reading from a HashMap).
448
//
449
request = PageFlowRequestWrapper.wrapRequest( request );
450         
451         String JavaDoc uri = InternalUtils.getDecodedServletPath( request );
452         ServletContext JavaDoc servletContext = getServletContext();
453
454         //
455
// Allow the container to do a security check on forwarded requests, if that feature is enabled.
456
//
457
if ( LegacySettings.get( servletContext ).shouldDoSecureForwards()
458              && PageFlowRequestWrapper.get( request ).isForwardedRequest() )
459         {
460             //
461
// In some situations (namely, in scoped requests under portal), the initial
462
// security check may not have been done for the request URI. In this case, a redirect
463
// to https may happen during checkSecurity().
464
//
465
if ( _servletContainerAdapter.doSecurityRedirect( uri, request, response ) )
466             {
467                 if ( _log.isDebugEnabled() )
468                 {
469                     _log.debug( "checkSecurity() caused a redirect. Ending processing for this request "
470                                + '(' + uri + ')' );
471                 }
472                 
473                 return;
474             }
475         }
476
477         //
478
// If we've come in on a forced redirect due to security constraints, look for request attrs
479
// that we put into the session.
480
//
481
String JavaDoc hash = request.getParameter( REDIRECT_REQUEST_ATTRS_PARAM );
482         if ( hash != null )
483         {
484             HttpSession JavaDoc session = request.getSession( false );
485
486             if ( session != null )
487             {
488                 String JavaDoc carryoverAttrName = makeRedirectedRequestAttrsKey( uri, hash );
489                 Map JavaDoc attrs = ( Map JavaDoc ) session.getAttribute( carryoverAttrName );
490                 session.removeAttribute( carryoverAttrName );
491
492                 if ( attrs != null )
493                 {
494                     for ( Iterator JavaDoc i = attrs.entrySet().iterator(); i.hasNext(); )
495                     {
496                         Map.Entry JavaDoc entry = ( Map.Entry JavaDoc ) i.next();
497
498                         String JavaDoc attrName = ( String JavaDoc ) entry.getKey();
499                         if ( request.getAttribute( attrName ) == null )
500                         {
501                             request.setAttribute( attrName, entry.getValue() );
502                         }
503                     }
504                 }
505             }
506         }
507
508         //
509
// The requested action can be overridden by a request parameter. In this case, we parse the action from
510
// the request parameter and forward to a URI constructed from it. If this happens, just return.
511
//
512
if ( processActionOverride( request, response ) ) return;
513         
514         //
515
// Process any direct request for a page flow by forwarding to its "begin" action.
516
//
517
if ( processPageFlowRequest( request, response, uri ) ) return;
518
519         //
520
// Get the FlowController for this request (page flow or shared flow), and cache it in the request.
521
//
522
String JavaDoc flowControllerClassName = InternalUtils.getFlowControllerClassName( moduleConfig );
523         
524         if ( flowControllerClassName == null &&
525              ! ( moduleConfig instanceof AutoRegisterActionServlet.MissingRootModuleControllerConfig ) )
526         {
527             //
528
// If this isn't a blank module initialized in place of a missing root PageFlowController, emit a warning
529
// about the missing controllerClass property.
530
//
531
_log.warn( "Struts module " + moduleConfig.getPrefix() + " is configured to use " + getClass().getName()
532                         + " as the request processor, but the <controller> element does not contain a <set-property>"
533                         + " for \"controllerClass\". Page Flow actions in this module may not be handled correctly." );
534         }
535         
536         //
537
// Create the appropriate SharedFlowController if it doesn't exist.
538
//
539
if ( _log.isInfoEnabled() )
540         {
541             _log.info( "Attempting to instantiate SharedFlowControllers for request " + request.getRequestURI() );
542         }
543         
544         FlowController currentFlowController = null;
545         
546         try
547         {
548             RequestContext requestContext = new RequestContext( request, response );
549             Map JavaDoc/*< String, SharedFlowController >*/ sharedFlows =
550                     _flowControllerFactory.getSharedFlowsForRequest( requestContext );
551             ImplicitObjectUtil.loadSharedFlow( request, sharedFlows );
552             ImplicitObjectUtil.loadGlobalApp( request, PageFlowUtils.getGlobalApp( request ) );
553             
554             if ( flowControllerClassName != null )
555             {
556                 currentFlowController = getFlowController( requestContext, flowControllerClassName );
557                 PageFlowRequestWrapper.get( request ).setCurrentFlowController( currentFlowController );
558             }
559             else
560             {
561                 PageFlowRequestWrapper.get( request ).setCurrentFlowController( null );
562             }
563         }
564         catch ( ClassNotFoundException JavaDoc e )
565         {
566             _log.error( "Could not find FlowController class " + flowControllerClassName, e );
567             throw new ServletException JavaDoc( e );
568         }
569         catch ( InstantiationException JavaDoc e )
570         {
571             _log.error( "Could not instantiate FlowController of type " + flowControllerClassName, e );
572             throw new ServletException JavaDoc( e );
573         }
574         catch ( IllegalAccessException JavaDoc e )
575         {
576             _log.error( "Could not instantiate FlowController of type " + flowControllerClassName, e );
577             throw new ServletException JavaDoc( e );
578         }
579         
580         //
581
// Get the page flow for this request.
582
//
583
PageFlowController jpf = PageFlowUtils.getCurrentPageFlow( request );
584         
585         //
586
// Set up implicit objects used by the expression language in simple actions and in declarative validation.
587
//
588
ImplicitObjectUtil.loadImplicitObjects( request, response, servletContext, jpf );
589         
590         try
591         {
592             super.process( request, response );
593         }
594         catch ( ServletException JavaDoc servletEx )
595         {
596             // If a ServletException escapes out of any of the processing methods, let the current FlowController handle it.
597
if ( ! handleException( servletEx, currentFlowController, request, response ) ) throw servletEx;
598         }
599         catch ( IOException JavaDoc ioe )
600         {
601             // If an IOException escapes out of any of the processing methods, let the current FlowController handle it.
602
if ( ! handleException( ioe, currentFlowController, request, response ) ) throw ioe;
603         }
604         catch ( Throwable JavaDoc th )
605         {
606             // If a Throwable escapes out of any of the processing methods, let the current FlowController handle it.
607
if ( ! handleException( th, currentFlowController, request, response ) ) throw new ServletException JavaDoc( th );
608         }
609     }
610     
611     private FlowController getFlowController( RequestContext requestContext, String JavaDoc fcClassName )
612         throws ClassNotFoundException JavaDoc, InstantiationException JavaDoc, IllegalAccessException JavaDoc
613     {
614         Class JavaDoc fcClass = _flowControllerFactory.getFlowControllerClass( fcClassName );
615         HttpServletRequest JavaDoc request = requestContext.getHttpRequest();
616         HttpServletResponse JavaDoc response = requestContext.getHttpResponse();
617         
618         if ( PageFlowController.class.isAssignableFrom( fcClass ) )
619         {
620             PageFlowController current = PageFlowUtils.getCurrentPageFlow( request );
621             
622             if ( current != null && current.getClass().equals( fcClass ) )
623             {
624                 if ( _log.isDebugEnabled() )
625                 {
626                     _log.debug( "Using current page flow: " + current );
627                 }
628                 
629                 //
630
// Reinitialize transient data that may have been lost on session failover.
631
//
632
current.reinitialize( request, response, getServletContext() );
633                 return current;
634             }
635             
636             return _flowControllerFactory.createPageFlow( new RequestContext( request, response ), fcClass );
637         }
638         else
639         {
640             assert SharedFlowController.class.isAssignableFrom( fcClass ) : fcClass.getName();
641             
642             SharedFlowController current = PageFlowUtils.getSharedFlow( fcClass.getName(), request );
643             
644             if ( current != null )
645             {
646                 current.reinitialize( request, response, getServletContext() );
647                 return current;
648             }
649             
650             return _flowControllerFactory.createSharedFlow( new RequestContext( request, response ), fcClass );
651         }
652     }
653     
654     private boolean handleException( Throwable JavaDoc th, FlowController fc, HttpServletRequest JavaDoc request,
655                                      HttpServletResponse JavaDoc response )
656     {
657         if ( fc != null )
658         {
659             try
660             {
661                 ActionMapping mapping = InternalUtils.getCurrentActionMapping( request );
662                 ActionForm form = InternalUtils.getCurrentActionForm( request );
663                 ActionForward fwd = fc.handleException( th, mapping, form, request, response );
664                 processForwardConfig( request, response, fwd );
665                 return true;
666             }
667             catch ( Throwable JavaDoc t )
668             {
669                 _log.error( "Exception while handling exception " + th.getClass().getName()
670                             + ". The original exception will be thrown.", th );
671                 return false;
672             }
673         }
674         
675         return false;
676     }
677     
678     /**
679      * Process any direct request for a page flow by forwarding to its "begin" action.
680      *
681   &nb