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      * @param request the current HttpServletRequest
682      * @param response the current HttpServletResponse
683      * @param uri the decoded request URI
684      * @return <code>true</code> if the request was for a page flow, in which case it was forwarded.
685      * @throws IOException
686      * @throws ServletException
687      */

688     protected boolean processPageFlowRequest( HttpServletRequest JavaDoc request, HttpServletResponse JavaDoc response, String JavaDoc uri )
689         throws IOException JavaDoc, ServletException JavaDoc
690     {
691         //
692
// Forward requests for *.jpf to the "begin" action within the appropriate Struts module.
693
//
694
if ( FileUtils.osSensitiveEndsWith( uri, PageFlowConstants.PAGEFLOW_EXTENSION ) )
695         {
696             //
697
// Make sure the current module config matches the request URI. If not, this could be an
698
// EAR where the jpf-struts-config.xml wasn't included because of a compilation error.
699
//
700
String JavaDoc modulePath = PageFlowUtils.getModulePath( request );
701             if ( ! moduleConfig.getPrefix().equals( modulePath ) )
702             {
703                 if ( _log.isErrorEnabled() )
704                 {
705                     InternalStringBuilder msg = new InternalStringBuilder( "No module configuration registered for " );
706                     msg.append( uri ).append( " (module path " ).append( modulePath ).append( ")." );
707                     _log.error( msg.toString() );
708                 }
709
710                 if ( modulePath.length() == 0 ) modulePath = "/";
711                 InternalUtils.sendDevTimeError( "PageFlow_NoModuleConf", null,
712                                                 HttpServletResponse.SC_INTERNAL_SERVER_ERROR, request, response,
713                                                 getServletContext(), new Object JavaDoc[]{ uri, modulePath } );
714                 return true;
715             }
716
717             //
718
// Make sure that the requested pageflow matches the pageflow for the directory.
719
//
720
ActionMapping beginMapping = getBeginMapping();
721             if ( beginMapping != null )
722             {
723                 String JavaDoc desiredType = beginMapping.getParameter();
724                 desiredType = desiredType.substring( desiredType.lastIndexOf( '.' ) + 1 ) + JPF_EXTENSION;
725                 String JavaDoc requestedType = InternalUtils.getDecodedServletPath( request );
726                 requestedType = requestedType.substring( requestedType.lastIndexOf( '/' ) + 1 );
727
728                 if ( ! requestedType.equals( desiredType ) )
729                 {
730                     if ( _log.isDebugEnabled() )
731                     {
732                         _log.debug( "Wrong .jpf requested for this directory: got " + requestedType
733                                    + ", expected " + desiredType );
734                     }
735
736                     if ( _log.isErrorEnabled() )
737                     {
738                         InternalStringBuilder msg = new InternalStringBuilder( "Wrong .jpf requested for this directory: got " );
739                         msg.append( requestedType ).append( ", expected " ).append( desiredType ).append( '.' );
740                         _log.error( msg.toString() );
741                     }
742
743                     InternalUtils.sendDevTimeError( "PageFlow_WrongPath", null,
744                                                     HttpServletResponse.SC_INTERNAL_SERVER_ERROR, request, response,
745                                                     getServletContext(), new Object JavaDoc[]{ requestedType, desiredType } );
746
747                     return true;
748                 }
749             }
750
751             uri = PageFlowUtils.getBeginActionURI( uri );
752
753             if ( _log.isDebugEnabled() )
754             {
755                 _log.debug( "Got request for " + request.getRequestURI() + ", forwarding to " + uri );
756             }
757
758             doForward( uri, request, response );
759             return true;
760         }
761         
762         return false;
763     }
764     
765     /**
766      * A MultipartRequestWrapper that we cache in the outer request once we've handled the multipart request once.
767      * It extends the base Struts MultipartRequestWrapper by being aware of ScopedRequests; for ScopedRequests, it
768      * filters the parameter names accordingly.
769      */

770     private static class RehydratedMultipartRequestWrapper extends MultipartRequestWrapper
771     {
772         public RehydratedMultipartRequestWrapper( HttpServletRequest JavaDoc req )
773         {
774             super( req );
775              
776             MultipartRequestHandler handler = MultipartRequestUtils.getCachedMultipartHandler( req );
777              
778             if ( handler != null )
779             {
780                 ScopedRequest scopedRequest = ScopedServletUtils.unwrapRequest( req );
781                 Map JavaDoc textElements = handler.getTextElements();
782                 parameters = scopedRequest != null ? scopedRequest.filterParameterMap( textElements ) : textElements;
783             }
784         }
785     }
786
787     public void process( HttpServletRequest JavaDoc request, HttpServletResponse JavaDoc response )
788         throws IOException JavaDoc, ServletException JavaDoc
789     {
790         int localRequestCount = -1;
791
792         if ( _log.isTraceEnabled() )
793         {
794             localRequestCount = ++requestCount;
795             _log.trace( "------------------------------- Start Request #" + localRequestCount
796                        + " -----------------------------------" );
797         }
798
799         //
800
// First reinitialize the reloadable class handler. This will bounce a classloader if necessary.
801
//
802
ServletContext JavaDoc servletContext = getServletContext();
803         _handlers.getReloadableClassHandler().reloadClasses( new RequestContext( request, response ) );
804         
805         //
806
// Go through the chain of pre-request interceptors.
807
//
808
RequestInterceptorContext context = new RequestInterceptorContext( request, response, getServletContext() );
809         List JavaDoc/*< Interceptor >*/ interceptors = context.getRequestInterceptors();
810         
811         try
812         {
813             Interceptors.doPreIntercept( context, interceptors );
814             
815             if ( context.requestWasCancelled() )
816             {
817                 if ( _log.isDebugEnabled() )
818                 {
819                     _log.debug ( "Interceptor " + context.getOverridingInterceptor() + " cancelled the request." );
820                 }
821                 
822                 return;
823             }
824         }
825         catch ( InterceptorException e )
826         {
827             throw new ServletException JavaDoc( e );
828         }
829         
830         //
831
// Initialize the ServletContext in the request. Often, we need access to the ServletContext when we only
832
// have a ServletRequest.
833
//
834
InternalUtils.setServletContext( request, servletContext );
835         
836         //
837
// Callback to the server adapter.
838
//
839
PageFlowEventReporter er = _servletContainerAdapter.getEventReporter();
840         _servletContainerAdapter.beginRequest( request, response );
841         er.beginActionRequest( request, response );
842         long startTime = System.currentTimeMillis();
843         
844         //
845
// Initialize the ControlBeanContext in the session.
846
//
847
JavaControlUtils.initializeControlContext( request, response, servletContext );
848
849         //
850
// Register the default URLRewriter
851
//
852
URLRewriterService.registerURLRewriter( 0, request, new DefaultURLRewriter() );
853
854         try
855         {
856             processInternal( request, response );
857         }
858         finally
859         {
860             //
861
// Clean up the ControlBeanContext in the session.
862
//
863
JavaControlUtils.uninitializeControlContext( request, response, getServletContext() );
864             
865             //
866
// Callback to the server adapter.
867
//
868
_servletContainerAdapter.endRequest( request, response );
869             long timeTaken = System.currentTimeMillis() - startTime;
870             er.endActionRequest( request, response, timeTaken );
871         }
872
873         //
874
// Go through the chain of pre-request interceptors.
875
//
876
try
877         {
878             Interceptors.doPostIntercept( context, interceptors );
879         }
880         catch ( InterceptorException e )
881         {
882             throw new ServletException JavaDoc( e );
883         }
884         
885         if ( _log.isTraceEnabled() )
886         {
887             _log.trace( "-------------------------------- End Request #" + localRequestCount
888                        + " ------------------------------------" );
889         }
890     }
891     
892     /**
893      * If this is a multipart request, wrap it with a special wrapper. Otherwise, return the request unchanged.
894      *
895      * @param request The HttpServletRequest we are processing
896      */

897     protected HttpServletRequest JavaDoc processMultipart( HttpServletRequest JavaDoc request )
898     {
899         if ( ! "POST".equalsIgnoreCase( request.getMethod() ) ) return request;
900
901         String JavaDoc contentType = request.getContentType();
902         if ( contentType != null && contentType.startsWith( "multipart/form-data" ) )
903         {
904             PageFlowRequestWrapper pageFlowRequestWrapper = PageFlowRequestWrapper.get( request );
905             
906             //
907
// We may have already gotten a multipart wrapper during process(). If so, use that.
908
//
909
MultipartRequestWrapper cachedWrapper = pageFlowRequestWrapper.getMultipartRequestWrapper();
910             
911             if ( cachedWrapper != null && cachedWrapper.getRequest() == request ) return cachedWrapper;
912             
913             try
914             {
915                 //
916
// First, pre-handle the multipart request. This parses the stream and caches a single
917
// MultipartRequestHandler in the outer request, so we can create new wrappers around it at will.
918
//
919
MultipartRequestUtils.preHandleMultipartRequest( request );
920             }
921             catch ( ServletException JavaDoc e )
922             {
923                 _log.error( "Could not parse multipart request.", e.getRootCause() );
924                 return request;
925             }
926             
927             MultipartRequestWrapper ret = new RehydratedMultipartRequestWrapper( request );
928             pageFlowRequestWrapper.setMultipartRequestWrapper( ret );
929             return ret;
930         }
931         else
932         {
933             return request;
934         }
935
936     }
937     
938     protected ActionMapping getBeginMapping()
939     {
940         return ( ActionMapping ) moduleConfig.findActionConfig( BEGIN_ACTION_PATH );
941     }
942     
943     private static String JavaDoc makeRedirectedRequestAttrsKey( String JavaDoc webappRelativeURI, String JavaDoc hash )
944     {
945         return REDIRECT_REQUEST_ATTRS_PREFIX + hash + webappRelativeURI;
946     }
947     
948     public ActionForward processException( HttpServletRequest JavaDoc request, HttpServletResponse JavaDoc response,
949                                            Exception JavaDoc ex, ActionForm form, ActionMapping mapping )
950         throws IOException JavaDoc, ServletException JavaDoc
951     {
952         //
953
// Note: we should only get here if FlowController.handleException itself throws an exception,
954
// or if the user has merged in Struts code that delegates to an action/exception-handler outside
955
// of the pageflow.
956
//
957

958         return super.processException( request, response, ex, form, mapping );
959     }
960     
961     /**
962      * Used by {@link PageFlowRequestProcessor#processMapping}. Its main job is to return
963      * {@link ExceptionHandledAction} as the type.
964      */

965     protected static class ExceptionHandledActionMapping extends ActionMapping
966     {
967         private ActionForward _fwd;
968         
969         public ExceptionHandledActionMapping( String JavaDoc actionPath, ActionForward fwd )
970         {
971             setPath( actionPath );
972             _fwd = fwd;
973         }
974         
975         public String JavaDoc getType()
976         {
977             return ExceptionHandledAction.class.getName();
978         }
979         
980         public ActionForward getActionForward()
981         {
982             return _fwd;
983         }
984         
985         public boolean getValidate()
986         {
987             return false;
988         }
989     }
990     
991     /**
992      * Used by {@link PageFlowRequestProcessor#processMapping}. This action simply returns the ActionForward stored in the
993      * ExceptionHandledActionMapping that's passed in.
994      */

995     public static class ExceptionHandledAction extends Action
996     {
997         public ActionForward execute( ActionMapping mapping, ActionForm form, HttpServletRequest JavaDoc request,
998                                       HttpServletResponse JavaDoc response )
999         {
1000            assert mapping instanceof ExceptionHandledActionMapping : mapping.getClass().getName();
1001            
1002            return ( ( ExceptionHandledActionMapping ) mapping ).getActionForward();
1003        }
1004    }
1005    
1006    private boolean isCorrectFormType( Class JavaDoc formBeanClass, ActionMapping mapping )
1007    {
1008        assert mapping.getName() != null : "cannot pass an ActionMapping that has no form bean";
1009        Class JavaDoc cachedFormBeanClass = ( Class JavaDoc ) _formBeanClasses.get( mapping.getName() );
1010        return isCorrectFormType( formBeanClass, cachedFormBeanClass, mapping );
1011    }
1012    
1013    private boolean isCorrectFormType( Class JavaDoc formBeanClass, Class JavaDoc actionMappingFormBeanClass, ActionMapping mapping )
1014    {
1015        if ( actionMappingFormBeanClass != null )
1016        {
1017            return actionMappingFormBeanClass .isAssignableFrom( formBeanClass );
1018        }
1019        else
1020        {
1021            //
1022
// The form bean class couldn't be loaded at init time -- just check against the class name.
1023
//
1024
FormBeanConfig mappingFormBean = moduleConfig.findFormBeanConfig( mapping.getName() );
1025            String JavaDoc formClassName = formBeanClass.getName();
1026            
1027            if ( mappingFormBean != null && mappingFormBean.getType().equals( formClassName ) ) return true;
1028            
1029            if ( mapping instanceof PageFlowActionMapping )
1030            {
1031                String JavaDoc desiredType = ( ( PageFlowActionMapping ) mapping ).getFormClass();
1032                if ( formClassName.equals( desiredType ) ) return true;
1033            }
1034        }
1035        
1036        return false;
1037    }
1038    
1039    private ActionMapping checkTransaction( HttpServletRequest JavaDoc request, HttpServletResponse JavaDoc response,
1040                                            ActionMapping mapping, String JavaDoc actionPath )
1041        throws IOException JavaDoc
1042    {
1043        if ( mapping instanceof PageFlowActionMapping && ( ( PageFlowActionMapping ) mapping ).isPreventDoubleSubmit() )
1044        {
1045            if ( ! TokenProcessor.getInstance().isTokenValid( request, true ) )
1046            {
1047                FlowController currentFC = PageFlowRequestWrapper.get( request ).getCurrentFlowController();
1048                String JavaDoc actionName = InternalUtils.getActionName( mapping );
1049                DoubleSubmitException ex = new DoubleSubmitException( actionName, currentFC );
1050                
1051                if ( currentFC != null )
1052                {
1053                    try
1054                    {
1055                        ActionForward fwd = currentFC.handleException( ex, mapping, null, request, response );
1056                        return new ExceptionHandledActionMapping( actionPath, fwd );
1057                    }
1058                    catch ( ServletException JavaDoc servletException)
1059                    {
1060                        _log.error( "Exception occurred while handling " + ex.getClass().getName(), servletException );
1061                    }
1062                }
1063                
1064                ex.sendResponseErrorCode( response );
1065                return null;
1066            }
1067        }
1068        
1069        return mapping;
1070    }
1071   
1072    public void init( ActionServlet actionServlet, ModuleConfig mc )
1073        throws ServletException JavaDoc
1074    {
1075        super.init( actionServlet, mc );
1076        
1077        ServletContext JavaDoc servletContext = getServletContext();
1078        
1079        //
1080
// Cache a reference to the ServletContainerAdapter, the Handlers, and the LegacySettings.
1081
//
1082
_servletContainerAdapter = AdapterManager.getServletContainerAdapter( servletContext );
1083        _legacySettings = LegacySettings.get( servletContext );
1084        _handlers = Handlers.get( servletContext );
1085        _flowControllerFactory = FlowControllerFactory.get( servletContext );
1086        
1087        //
1088
// Cache a list of overloaded actions for each overloaded action path (actions are overloaded by form bean type).
1089
//
1090
cacheOverloadedActionMappings();
1091        
1092        //
1093
// Cache the form bean Classes by form bean name.
1094
//
1095
cacheFormClasses();
1096        
1097        //
1098
// Initialize the request interceptors and action interceptors.
1099
//
1100
ActionInterceptorContext.init( servletContext );
1101        RequestInterceptorContext.init( servletContext );
1102        
1103        _pageServletFilter = new PageServletFilter();
1104    }
1105    
1106    private class PageServletFilter extends PageFlowPageFilter
1107    {
1108        public PageServletFilter()
1109        {
1110            super( getServletContext() );
1111        }
1112
1113        protected Set JavaDoc getValidFileExtensions()
1114        {
1115            return null; // accept all
1116
}
1117    }
1118    
1119    private void cacheOverloadedActionMappings()
1120    {
1121        ActionConfig[] actionConfigs = moduleConfig.findActionConfigs();
1122        
1123        for ( int i = 0; i < actionConfigs.length; i++ )
1124        {
1125            ActionConfig actionConfig = actionConfigs[i];
1126            
1127            if ( actionConfig instanceof PageFlowActionMapping )
1128            {
1129                PageFlowActionMapping mapping = ( PageFlowActionMapping ) actionConfig;
1130                String JavaDoc unqualifiedActionPath = ( ( PageFlowActionMapping ) actionConfig ).getUnqualifiedActionPath();
1131                
1132                if ( unqualifiedActionPath != null )
1133                {
1134                    List JavaDoc/*< ActionMapping >*/ overloaded = ( List JavaDoc ) _overloadedActions.get( unqualifiedActionPath );
1135                    
1136                    if ( overloaded == null )
1137                    {
1138                        overloaded = new ArrayList JavaDoc/*< ActionMapping >*/();
1139                        _overloadedActions.put( unqualifiedActionPath, overloaded );
1140                    }
1141                    
1142                    overloaded.add( mapping );
1143                }
1144            }
1145        }
1146    }
1147    
1148    private void cacheFormClasses()
1149    {
1150        FormBeanConfig[] formBeans = moduleConfig.findFormBeanConfigs();
1151        ReloadableClassHandler rch = _handlers.getReloadableClassHandler();
1152        
1153        for ( int i = 0; i < formBeans.length; i++ )
1154        {
1155            FormBeanConfig formBeanConfig = formBeans[i];
1156            String JavaDoc formType = InternalUtils.getFormBeanType( formBeanConfig );
1157            
1158            try
1159            {
1160                Class JavaDoc formBeanClass = rch.loadClass( formType );
1161                _formBeanClasses.put( formBeanConfig.getName(), formBeanClass );
1162            }
1163            catch ( ClassNotFoundException JavaDoc e )
1164            {
1165                _log.error( "Could not load class " + formType + " referenced from form bean config "
1166                            + formBeanConfig.getName() + " in Struts module " + moduleConfig );
1167            }
1168        }
1169    }
1170
1171    /**
1172     * Read component instance mapping configuration file.
1173     * This is where we read files properties.
1174     */

1175    
1176    protected void initDefinitionsMapping() throws ServletException JavaDoc
1177    {
1178        definitionsFactory = null;
1179        TilesUtilImpl tilesUtil = TilesUtil.getTilesUtil();
1180
1181        if ( tilesUtil instanceof TilesUtilStrutsImpl )
1182        {
1183            // Retrieve and set factory for this modules
1184
definitionsFactory =
1185                    ( ( TilesUtilStrutsImpl ) tilesUtil ).getDefinitionsFactory( getServletContext(), moduleConfig );
1186
1187            if ( definitionsFactory == null && log.isDebugEnabled() )
1188            {
1189                log.debug( "Definition Factory not found for module: '"
1190                           + moduleConfig.getPrefix() );
1191            }
1192        }
1193    }
1194
1195    public ActionMapping processMapping( HttpServletRequest JavaDoc request, HttpServletResponse JavaDoc response, String JavaDoc path )
1196        throws IOException JavaDoc
1197    {
1198        FlowController fc = PageFlowRequestWrapper.get( request ).getCurrentFlowController();
1199        Object JavaDoc forwardedForm = InternalUtils.unwrapFormBean( InternalUtils.getForwardedFormBean( request, false ) );
1200        
1201        //
1202
// First, see if this is a request for a shared flow action. The shared flow's name (as declared by the
1203
// current page flow) will precede the dot.
1204
//
1205
if ( fc != null && ! processSharedFlowMapping( request, response, path, fc ) ) return null;
1206        
1207        //
1208
// Look for a form-specific action path. This is used when there are two actions with the same
1209
// name, but different forms (in nesting).
1210
//
1211
Class JavaDoc forwardedFormClass = null;
1212        
1213        if ( forwardedForm != null )
1214        {
1215            forwardedFormClass = forwardedForm.getClass();
1216            List JavaDoc/*< ActionMapping >*/ possibleMatches = ( List JavaDoc ) _overloadedActions.get( path );
1217            ActionMapping bestMatch = null;
1218            
1219            //
1220
// Troll through the overloaded actions for the given path. Look for the one whose form bean class is
1221
// exactly the class of the forwarded form; failing that, look for one that's assignable from the class
1222
// of the forwarded form.
1223
//
1224
for ( int i = 0; possibleMatches != null && i < possibleMatches.size(); ++i )
1225            {
1226                ActionMapping possibleMatch = ( ActionMapping ) possibleMatches.get( i );
1227                assert possibleMatch instanceof PageFlowActionMapping : possibleMatch.getClass();
1228                Class JavaDoc cachedFormBeanClass = ( Class JavaDoc ) _formBeanClasses.get( possibleMatch.getName() );
1229                
1230                if ( forwardedFormClass.equals( cachedFormBeanClass ) )
1231                {
1232                    bestMatch = possibleMatch;
1233                    break;
1234                }
1235                if ( bestMatch == null && isCorrectFormType( forwardedFormClass, possibleMatch ) )
1236                {
1237                    bestMatch = possibleMatch;
1238                }
1239            }
1240            
1241            if ( bestMatch != null )
1242            {
1243                request.setAttribute( Globals.MAPPING_KEY, bestMatch );
1244                
1245                if ( _log.isDebugEnabled() )
1246                {
1247                    _log.debug( "Found form-specific action mapping " + bestMatch.getPath() + " for " + path
1248                                + ", form " + forwardedFormClass.getName() );
1249                }
1250                
1251                return checkTransaction( request, response, bestMatch, path );
1252            }
1253        }
1254        
1255        //
1256
// Look for a directly-defined mapping for this path.
1257
//
1258
ActionMapping mapping = ( ActionMapping ) moduleConfig.findActionConfig( path );
1259        
1260        if ( mapping != null )
1261        {
1262            boolean wrongForm = false;
1263            
1264            //
1265
// We're going to bail out if there is a forwarded form and this mapping requires a different form type.
1266
//
1267
if ( forwardedForm != null )
1268            {
1269                boolean mappingHasNoFormBean = mapping.getName() == null;
1270                wrongForm = mappingHasNoFormBean || ! isCorrectFormType( forwardedFormClass, mapping );
1271            }
1272            
1273            if ( ! wrongForm )
1274            {
1275                request.setAttribute( Globals.MAPPING_KEY, mapping );
1276                return checkTransaction( request, response, mapping, path );
1277            }
1278        }
1279
1280        //
1281
// Look for a mapping for "unknown" paths
1282
//
1283
ActionConfig configs[] = moduleConfig.findActionConfigs();
1284        for ( int i = 0; i < configs.length; i++ )
1285        {
1286            if ( configs[i].getUnknown() )
1287            {
1288                mapping = ( ActionMapping ) configs[i];
1289                request.setAttribute( Globals.MAPPING_KEY, mapping );
1290                return checkTransaction( request, response, mapping, path );
1291            }
1292        }
1293
1294        //
1295
// PageFlowRequestWrapper.get( request ).getOriginalServletPath returns the request URI we had before trying to forward to an action
1296
// in a shared flow.
1297
//
1298
String JavaDoc errorServletPath = PageFlowRequestWrapper.get( request ).getOriginalServletPath();
1299        
1300        if ( errorServletPath == null
1301             && InternalUtils.getModuleConfig( GLOBALAPP_MODULE_CONTEXT_PATH, getServletContext() ) != null )
1302        {
1303            if ( _log.isDebugEnabled() )
1304            {
1305                _log.debug( "Trying Global.app for unhandled action " + path );
1306            }
1307            
1308            //
1309
// We haven't tried the deprecated Global.app fallback yet. Try it now.
1310
//
1311
errorServletPath = InternalUtils.getDecodedServletPath( request );
1312            PageFlowRequestWrapper.get( request ).setOriginalServletPath( errorServletPath );
1313            String JavaDoc globalAppURI = GLOBALAPP_MODULE_CONTEXT_PATH + path + ACTION_EXTENSION;
1314            try
1315            {
1316                doForward( globalAppURI, request, response );
1317            }
1318            catch ( ServletException JavaDoc e )
1319            {
1320                _log.error( "Could not forward to Global.app URI " + globalAppURI );
1321            }
1322            return null;
1323        }
1324        else
1325        {
1326            //
1327
// If the error action path has a slash in it, then it's not local to the current page flow. Replace
1328
// it with the original servlet path.
1329
//
1330
if ( errorServletPath != null && path.indexOf( '/' ) > 0 ) path = errorServletPath;
1331            return processUnresolvedAction( path, request, response, forwardedForm );
1332        }
1333    }
1334    
1335    protected boolean processSharedFlowMapping( HttpServletRequest JavaDoc request, HttpServletResponse JavaDoc response,
1336                                                String JavaDoc actionPath, FlowController currentFlowController )
1337            throws IOException JavaDoc
1338    {
1339        if ( currentFlowController.isPageFlow() )
1340        {
1341            int dot = actionPath.indexOf( '.' );
1342            
1343            if ( dot != -1 )
1344            {
1345                Map JavaDoc/*< String, SharedFlowController >*/ sharedFlows = PageFlowUtils.getSharedFlows( request );
1346                if ( sharedFlows == null ) return true;
1347                if ( dot == actionPath.length() - 1 ) return true; // empty action name
1348
assert actionPath.length() > 0 && actionPath.charAt( 0 ) == '/' : actionPath;
1349                String JavaDoc sharedFlowName = actionPath.substring( 1, dot );
1350                SharedFlowController sf = ( SharedFlowController ) sharedFlows.get( sharedFlowName );
1351                
1352                if ( sf != null )
1353                {
1354                    if ( _log.isDebugEnabled() )
1355                    {
1356                        _log.debug( "Forwarding to shared flow " + sf.getDisplayName() + " to handle action \""
1357                                    + actionPath + "\"." );
1358                    }
1359                    
1360                    //
1361
// Save the original request URI, so if the action fails on the shared flow, too, then we can
1362
// give an error message that includes *this* URI, not the shared flow URI.
1363
//
1364
PageFlowRequestWrapper.get( request ).setOriginalServletPath( InternalUtils.getDecodedServletPath( request ) );
1365                    
1366                    //
1367
// Construct a URI that is [shared flow module path] + [base action path] + [action-extension (.do)]
1368
//
1369
int lastSlash = actionPath.lastIndexOf( '/' );
1370                    assert lastSlash != -1 : actionPath;
1371                    InternalStringBuilder uri = new InternalStringBuilder( sf.getModulePath() );
1372                    uri.append( '/' );
1373                    uri.append( actionPath.substring( dot + 1 ) );
1374                    uri.append( ACTION_EXTENSION );
1375                    
1376                    try
1377                    {
1378                        doForward( uri.toString(), request, response );
1379                        return false;
1380                    }
1381                    catch ( ServletException JavaDoc e )
1382                    {
1383                        _log.error( "Could not forward to shared flow URI " + uri, e );
1384                    }
1385                }
1386            }
1387        }
1388        
1389        return true;
1390    }
1391    
1392    protected ActionMapping processUnresolvedAction( String JavaDoc actionPath, HttpServletRequest JavaDoc request,
1393                                                     HttpServletResponse JavaDoc response, Object JavaDoc returningForm )
1394        throws IOException JavaDoc
1395    {
1396                if ( _log.isInfoEnabled() )
1397        {
1398            InternalStringBuilder msg = new InternalStringBuilder( "Action \"" ).append( actionPath );
1399            _log.info( msg.append( "\" was also unhandled by Global.app." ).toString() );
1400        }
1401        
1402        //
1403
// If there's a PageFlowController for this request, try and let it handle an
1404
// action-not-found exception. Otherwise, let Struts print out its "invalid path"
1405
// message.
1406
//
1407
FlowController fc = PageFlowUtils.getCurrentPageFlow( request );
1408        
1409        try
1410        {
1411            if ( fc != null )
1412            {
1413                Exception JavaDoc ex = new ActionNotFoundException( actionPath, fc, returningForm );
1414                InternalUtils.setCurrentModule( fc.getModuleConfig(), request );
1415                ActionForward result = fc.handleException( ex, null, null, request, response );
1416                return new ExceptionHandledActionMapping( actionPath, result );
1417            }
1418        }
1419        catch ( ServletException JavaDoc e )
1420        {
1421            // ignore this -- just let Struts do its thing.
1422

1423            if ( _log.isDebugEnabled() )
1424            {
1425                _log.debug( e );
1426            }
1427        }
1428                    
1429        if ( _log.isDebugEnabled() )
1430        {
1431            _log.debug( "Couldn't handle an ActionNotFoundException -- delegating to Struts" );
1432        }
1433        
1434        return super.processMapping( request, response, actionPath );
1435    }
1436    
1437    protected boolean processRoles( HttpServletRequest JavaDoc request, HttpServletResponse JavaDoc response, ActionMapping mapping )
1438        throws IOException JavaDoc, ServletException JavaDoc
1439    {
1440        //
1441
// If there are no required roles for this action, just return.
1442
//
1443
String JavaDoc roles[] = mapping.getRoleNames();
1444        if ( roles == null || roles.length < 1 )
1445        {
1446            return true;
1447        }
1448
1449        // Check the current user against the list of required roles
1450
FlowController fc = PageFlowRequestWrapper.get( request ).getCurrentFlowController();
1451        FlowControllerHandlerContext context = new FlowControllerHandlerContext( request, response, fc );
1452        
1453        for ( int i = 0; i < roles.length; i++ )
1454        {
1455            if ( _handlers.getLoginHandler().isUserInRole( context, roles[i] ) )
1456            {
1457                if ( _log.isDebugEnabled() )
1458                {
1459                    _log.debug( " User " + request.getRemoteUser() + " has role '" + roles[i] + "', granting access" );
1460                }
1461                
1462                return true;
1463            }
1464        }
1465
1466        // The current user is not authorized for this action
1467
if ( _log.isDebugEnabled() )
1468        {
1469            _log.debug( " User '" + request.getRemoteUser() + "' does not have any required role, denying access" );
1470        }
1471                
1472        //
1473
// Here, Struts sends an HTTP error. We try to let the current page flow handle a relevant exception.
1474
//
1475
LoginHandler loginHandler = _handlers.getLoginHandler();
1476        String JavaDoc actionName = InternalUtils.getActionName( mapping );
1477        FlowController currentFC = PageFlowRequestWrapper.get( request ).getCurrentFlowController();
1478        PageFlowException ex;
1479        
1480        if ( loginHandler.getUserPrincipal( context ) == null )
1481        {
1482            ex = currentFC.createNotLoggedInException( actionName, request );
1483        }
1484        else
1485        {
1486            ex = new UnfulfilledRolesException( mapping.getRoleNames(), mapping.getRoles(), actionName, currentFC );
1487        }
1488        
1489        if ( currentFC != null )
1490        {
1491            ActionForward fwd = currentFC.handleException( ex, mapping, null, request, response );
1492            processForwardConfig( request, response, fwd );
1493        }
1494        else
1495        {
1496            ( ( ResponseErrorCodeSender ) ex ).sendResponseErrorCode( response );
1497        }
1498        
1499        return false;
1500    }
1501    
1502    private static String JavaDoc addScopeParams( String JavaDoc url, HttpServletRequest JavaDoc request )
1503    {
1504        //
1505
// If the current request is scoped, add the right request parameter to the URL.
1506
//
1507
String JavaDoc scopeID = request.getParameter( ScopedServletUtils.SCOPE_ID_PARAM );
1508        if ( scopeID != null )
1509        {
1510            return InternalUtils.addParam( url, ScopedServletUtils.SCOPE_ID_PARAM, scopeID );
1511        }
1512        else
1513        {
1514            return url;
1515        }
1516    }
1517    
1518    /**
1519     * This override of the base method ensures that absolute URIs don't get the context
1520     * path prepended, and handles forwards to special things like return-to="currentPage".
1521     */

1522    protected void processForwardConfig( HttpServletRequest JavaDoc request, HttpServletResponse JavaDoc response, ForwardConfig fwd )
1523            throws IOException JavaDoc, ServletException JavaDoc
1524    {
1525        ServletContext JavaDoc servletContext = getServletContext();
1526        ForwardRedirectHandler fwdRedirectHandler = _handlers.getForwardRedirectHandler();
1527        FlowController fc = PageFlowRequestWrapper.get( request ).getCurrentFlowController();
1528        FlowControllerHandlerContext context = new FlowControllerHandlerContext( request, response, fc );
1529
1530        // Register this module as the one that's handling the action.
1531
if ( fc != null )
1532        {
1533            InternalUtils.setForwardingModule( request, fc.getModulePath() );
1534        }
1535        
1536        //
1537
// The following is similar to what's in super.processForwardConfig(), but it avoids putting
1538
// a slash in front of absolute URLs (e.g., ones that start with "http:").
1539
//
1540
if ( fwd != null )
1541        {
1542            if ( _log.isDebugEnabled() ) _log.debug( "processForwardConfig(" + fwd + ')' );
1543    
1544            //
1545
// Try to process a tiles definition. If the forward doesn't contain a
1546
// a tiles definition, continue on.
1547
//
1548
if ( processTilesDefinition( fwd.getPath(), fwd.getContextRelative(), request, response ) )
1549            {
1550                if ( log.isDebugEnabled() )
1551                {
1552                    log.debug( " '" + fwd.getPath() + "' - processed as definition" );
1553                }
1554                return;
1555            }
1556
1557            //
1558
// If this is a "special" page flow forward, create a Forward to handle it and pass
1559
// it to the current page flow. This should only happen when processValidate()
1560
// calls this method (or if a plain Struts action forwards to this forward) --
1561
// otherwise, the page flow should be using a Forward already.
1562
//
1563
if ( fwd instanceof PageFlowActionForward )
1564            {
1565                ActionMapping mapping = ( ActionMapping ) request.getAttribute( Globals.MAPPING_KEY );
1566                assert mapping != null;
1567                ActionForm form = InternalUtils.getFormBean( mapping, request );
1568                Forward pfFwd = new Forward( ( ActionForward ) fwd, servletContext );
1569                ActionForwardHandler handler = _handlers.getActionForwardHandler();
1570                fwd = handler.doForward( context, pfFwd, mapping, InternalUtils.getActionName( mapping ), null, form );
1571            }
1572            
1573            String JavaDoc path = fwd.getPath();
1574            boolean startsWithSlash = path.length() > 0 && path.charAt( 0 ) == '/';
1575            
1576            //
1577
// If the URI is absolute (e.g., starts with "http:"), do a redirect to it no matter what.
1578
//
1579
if ( FileUtils.isAbsoluteURI( path ) )
1580            {
1581                fwdRedirectHandler.redirect( context, addScopeParams( path, request ) );
1582            }
1583            else if ( fwd.getRedirect() )
1584            {
1585                String JavaDoc redirectURI;
1586                
1587                if ( startsWithSlash && fwd instanceof Forward && ( ( Forward ) fwd ).isExplicitPath() )
1588                {
1589                    redirectURI = path;
1590                }
1591                else if ( fwd instanceof Forward && ( ( Forward ) fwd ).isExternalRedirect() )
1592                {
1593                    assert startsWithSlash : path; // compiler should ensure path starts with '/'
1594
redirectURI = path;
1595                }
1596                else
1597                {
1598                    redirectURI = request.getContextPath() + RequestUtils.forwardURL( request, fwd );
1599                }
1600                
1601                fwdRedirectHandler.redirect( context, addScopeParams( redirectURI, request ) );
1602            }
1603            else
1604            {
1605                String JavaDoc fwdURI;
1606                
1607                if ( startsWithSlash && fwd instanceof Forward && ( ( Forward ) fwd ).isExplicitPath() )
1608                {
1609                    fwdURI = path;
1610                }
1611                else
1612                {
1613                    fwdURI = RequestUtils.forwardURL( request, fwd );
1614                    
1615                    //
1616
// First, see if the current module is a Shared Flow module. If so, unless this is a forward to
1617
// another action in the shared flow, we need to translate the local path so it makes sense (strip
1618
// off the shared flow module prefix "/-" and replace it with "/").
1619
//
1620
ModuleConfig mc = ( ModuleConfig ) request.getAttribute( Globals.MODULE_KEY );
1621                    
1622                    if ( InternalUtils.isSharedFlowModule( mc ) && ! fwdURI.endsWith( ACTION_EXTENSION )
1623                         && fwdURI.startsWith( SHARED_FLOW_MODULE_PREFIX ) )
1624                    {
1625                        fwdURI = '/' + fwdURI.substring( SHARED_FLOW_MODULE_PREFIX_LEN );
1626                    }
1627                }
1628                
1629                doForward( fwdURI, request, response );
1630            }
1631        }
1632    }
1633    
1634    protected boolean changeScheme( String JavaDoc webappRelativeURI, String JavaDoc scheme, int port,
1635                                    FlowControllerHandlerContext context )
1636        throws URISyntaxException JavaDoc, IOException JavaDoc, ServletException JavaDoc
1637    {
1638        if ( port == -1 )
1639        {
1640            if ( _log.isWarnEnabled() )
1641            {
1642                _log.warn( "Could not change the scheme to " + scheme + " because the relevant port was not provided "
1643                           + "by the ServletContainerAdapter." );
1644                return false;
1645            }
1646        }
1647        
1648        //
1649
// First put all request attributes into the session, so they can be added to the
1650
// redirected request.
1651
//
1652
Map JavaDoc attrs = new HashMap JavaDoc();
1653        String JavaDoc queryString = null;
1654        ServletContext JavaDoc servletContext = getServletContext();
1655        HttpServletRequest JavaDoc request = ( ( RequestContext ) context ).getHttpRequest();
1656        
1657        for ( Enumeration JavaDoc e = request.getAttributeNames(); e.hasMoreElements(); )
1658        {
1659            String JavaDoc name = ( String JavaDoc ) e.nextElement();
1660            attrs.put( name, request.getAttribute( name ) );
1661        }
1662        
1663        if ( ! attrs.isEmpty() )
1664        {
1665            String JavaDoc hash = Integer.toString( request.hashCode() );
1666            String JavaDoc key = makeRedirectedRequestAttrsKey( webappRelativeURI, hash );
1667            request.getSession().setAttribute( key, attrs );
1668            queryString = URLRewriterService.getNamePrefix( servletContext, request, REDIRECT_REQUEST_ATTRS_PARAM )
1669                          + REDIRECT_REQUEST_ATTRS_PARAM + '=' + hash;
1670        }
1671
1672        
1673        //
1674
// Now do the redirect.
1675
//
1676
URI JavaDoc redirectURI = new URI JavaDoc( scheme, null, request.getServerName(), port,
1677                                   request.getContextPath() + webappRelativeURI,
1678                                   queryString, null );
1679        
1680        ForwardRedirectHandler fwdRedirectHandler = _handlers.getForwardRedirectHandler();
1681        fwdRedirectHandler.redirect( context, redirectURI.toString() );
1682        
1683        if ( _log.isDebugEnabled() )
1684        {
1685            _log.debug( "Redirected to " + redirectURI );
1686        }
1687        
1688        return true;
1689    }
1690    
1691    /**
1692     * @deprecated Use {@link LegacySettings#shouldDoSecureForwards} instead.
1693     */

1694    protected boolean shouldDoSecureForwards()
1695    {
1696        return _legacySettings.shouldDoSecureForwards();
1697    }
1698
1699    protected void doForward( String JavaDoc uri, HttpServletRequest JavaDoc request, HttpServletResponse JavaDoc response )
1700        throws IOException JavaDoc, ServletException JavaDoc
1701    {
1702        boolean securityRedirected = false;
1703        ServletContext JavaDoc servletContext = getServletContext();
1704
1705        //
1706
// As in the TilesRequestProcessor.doForward(), if the response has already been commited,
1707
// do an include instead.
1708
//
1709
if ( response.isCommitted() )
1710        {
1711            doInclude( uri, request, response );
1712            return;
1713        }
1714        
1715        FlowController fc = PageFlowRequestWrapper.get( request ).getCurrentFlowController();
1716        FlowControllerHandlerContext context = new FlowControllerHandlerContext( request, response, fc );
1717
1718        if ( _legacySettings.shouldDoSecureForwards() )
1719        {
1720            SecurityProtocol sp = PageFlowUtils.getSecurityProtocol( uri, servletContext, request );
1721            
1722            if ( ! sp.equals( SecurityProtocol.UNSPECIFIED ) )
1723            {
1724                try
1725                {
1726                    if ( request.isSecure() )
1727                    {
1728                        if ( sp.equals( SecurityProtocol.UNSECURE ) )
1729                        {
1730                            int listenPort = _servletContainerAdapter.getListenPort( request );
1731                            securityRedirected = changeScheme( uri, SCHEME_UNSECURE, listenPort, context );
1732                        }
1733                    }
1734                    else
1735                    {
1736                        if ( sp.equals( SecurityProtocol.SECURE ) )
1737                        {
1738                            int secureListenPort = _servletContainerAdapter.getSecureListenPort( request );
1739                            securityRedirected = changeScheme( uri, SCHEME_SECURE, secureListenPort, context );
1740                        }
1741                    }
1742                }
1743                catch ( URISyntaxException JavaDoc e )
1744                {
1745                    _log.error( "Bad forward URI " + uri, e );
1746                }
1747            }
1748        }
1749        
1750        if ( ! securityRedirected )
1751        {
1752            if ( ! processPageForward( uri, request, response ) )
1753            {
1754                ForwardRedirectHandler fwdRedirectHandler = _handlers.getForwardRedirectHandler();
1755                fwdRedirectHandler.forward( context, uri );
1756            }
1757        }
1758    }
1759    
1760    /**
1761     * An opportunity to process a page forward in a different way than performing a server forward. The default
1762     * implementation looks for a file on classpath called
1763     * META-INF/pageflow-page-servlets/<i>path-to-page</i>.properties (e.g.,
1764     * "/META-INF/pageflow-page-servlets/foo/bar/hello.jsp.properties"). This file contains mappings from
1765     * <i>platform-name</i> (the value returned by {@link ServletContainerAdapter#getPlatformName}) to the name of a Servlet
1766     * class that will process the page request. If the current platform name is not found, the value "default" is
1767     * tried. An example file might look like this:
1768     * <pre>
1769     * tomcat=org.apache.jsp.foo.bar.hello_jsp
1770     * default=my.servlets.foo.bar.hello
1771     * </pre>
1772     * @param pagePath the webapp-relative path to the page, e.g., "/foo/bar/hello.jsp"
1773     * @param request the current HttpServletRequest
1774     * @param response the current HttpServletResponse
1775     * @return <code>true</code> if the method handled the request, in which case it should not be forwarded.
1776     * @throws IOException
1777     * @throws ServletException
1778     */

1779    private boolean processPageForward( String JavaDoc pagePath, HttpServletRequest JavaDoc request, HttpServletResponse JavaDoc response )
1780        throws IOException JavaDoc, ServletException JavaDoc
1781    {
1782        Class JavaDoc pageServletClass = ( Class JavaDoc ) _pageServletClasses.get( pagePath );
1783        
1784        if ( pageServletClass == null )
1785        {
1786            pageServletClass = Void JavaDoc.class;
1787            ClassLoader JavaDoc cl = DiscoveryUtils.getClassLoader();
1788            String JavaDoc path = "META-INF/pageflow-page-servlets" + pagePath + ".properties";
1789            InputStream JavaDoc in = cl.getResourceAsStream( path );
1790            
1791            if ( in != null )
1792            {
1793                String JavaDoc className = null;
1794                
1795                try
1796                {
1797                    Properties JavaDoc props = new Properties JavaDoc();
1798                    props.load( in );
1799                    className = props.getProperty( _servletContainerAdapter.getPlatformName() );
1800                    if ( className == null ) className = props.getProperty( "default" );
1801                    
1802                    if ( className != null )
1803                    {
1804                        pageServletClass = cl.loadClass( className );
1805                        
1806                        if ( Servlet.class.isAssignableFrom( pageServletClass ) )
1807                        {
1808                            if ( _log.isInfoEnabled() )
1809                            {
1810                                _log.info( "Loaded page Servlet class " + className + " for path " + pagePath );
1811                            }
1812                        }
1813                        else
1814                        {
1815                            pageServletClass = Void JavaDoc.class;
1816                            _log.error( "Page Servlet class " + className + " for path " + pagePath
1817                                        + " does not extend " + Servlet.class.getName() );
1818                        }
1819                    }
1820                }
1821                catch ( IOException JavaDoc e )
1822                {
1823                    _log.error( "Error while reading " + path, e );
1824                }
1825                catch ( ClassNotFoundException JavaDoc e )
1826                {
1827                    _log.error( "Error while loading page Servlet class " + className, e );
1828                }
1829            }
1830            
1831            _pageServletClasses.put( pagePath, pageServletClass );
1832        }
1833        
1834        if ( pageServletClass.equals( Void JavaDoc.class ) )
1835        {
1836            return false;
1837        }
1838        
1839        try
1840        {
1841            Servlet pageServlet = ( Servlet ) pageServletClass.newInstance();
1842            pageServlet.init( new PageServletConfig( pagePath ) );
1843            _pageServletFilter.doFilter( request, response, new PageServletFilterChain( pageServlet ) );
1844            return true;
1845        }
1846        catch ( InstantiationException JavaDoc e )
1847        {
1848            _log.error( "Error while instantiating page Servlet of type " + pageServletClass.getName(), e );
1849        }
1850        catch ( IllegalAccessException JavaDoc e )
1851        {
1852            _log.error( "Error while instantiating page Servlet of type " + pageServletClass.getName(), e );
1853        }
1854        
1855        return false;
1856    }
1857    
1858    /**
1859     * Used by {@link PageFlowRequestProcessor#processPageForward} to run a page Servlet.
1860     */

1861    private static class PageServletFilterChain implements FilterChain JavaDoc
1862    {
1863        private Servlet _pageServlet;
1864        
1865        public PageServletFilterChain( Servlet pageServlet )
1866        {
1867            _pageServlet= pageServlet;
1868        }
1869        
1870        public void doFilter( ServletRequest JavaDoc request, ServletResponse JavaDoc response )
1871                throws IOException JavaDoc, ServletException JavaDoc
1872        {
1873            _pageServlet.service( request, response );
1874        }
1875    }
1876    
1877    /**
1878     * Used by {@link PageFlowRequestProcessor#processPageForward} to initialize a page Servlet.
1879     */

1880    private class PageServletConfig implements ServletConfig JavaDoc
1881    {
1882        private String JavaDoc _pagePath;
1883        
1884        public PageServletConfig( String JavaDoc pagePath )
1885        {
1886            _pagePath = pagePath;
1887        }
1888        
1889        public String JavaDoc getServletName()
1890        {
1891            return _pagePath;
1892        }
1893
1894        public ServletContext JavaDoc getServletContext()
1895        {
1896            return PageFlowRequestProcessor.this.getServletContext();
1897        }
1898
1899        public String JavaDoc getInitParameter( String JavaDoc s )
1900        {
1901            return null;
1902        }
1903
1904        public Enumeration JavaDoc getInitParameterNames()
1905        {
1906            return Collections.enumeration( Collections.EMPTY_LIST );
1907        }
1908    }
1909    
1910    /**
1911     * Set the no-cache headers. This overrides the base Struts behavior to prevent caching even for the pages.
1912     */

1913    protected void processNoCache( HttpServletRequest JavaDoc request, HttpServletResponse JavaDoc response )
1914    {
1915        //
1916
// Set the no-cache headers if:
1917
// 1) the module is configured for it, or
1918
// 2) netui-config.xml has an "always" value for <pageflow-config><prevent-cache>, or
1919
// 3) netui-config.xml has an "inDevMode" value for <pageflow-config><prevent-cache>, and we're not in
1920
// production mode.
1921
//
1922
boolean noCache = moduleConfig.getControllerConfig().getNocache();
1923        
1924        if ( ! noCache )
1925        {
1926            PageflowConfig pfConfig = ConfigUtil.getConfig().getPageflowConfig();
1927            
1928            if ( pfConfig != null )
1929            {
1930                PageflowConfig.PreventCache.Enum preventCache = pfConfig.getPreventCache();
1931                
1932                if ( preventCache != null )
1933                {
1934                    switch ( preventCache.intValue() )
1935                    {
1936                        case PageflowConfig.PreventCache.INT_ALWAYS:
1937                            noCache = true;
1938                            break;
1939                        case PageflowConfig.PreventCache.INT_IN_DEV_MODE:
1940                            noCache = ! _servletContainerAdapter.isInProductionMode();
1941                            break;
1942                    }
1943                }
1944            }
1945        }
1946        
1947        if ( noCache )
1948        {
1949            //
1950
// The call to PageFlowPageFilter.preventCache() will cause caching to be prevented
1951
// even when we end up forwarding to a pagee. Normally, no-cache headers are lost
1952
// when a server forward occurs.
1953
//
1954
ServletUtils.preventCache( response );
1955            PageFlowPageFilter.preventCache( request );
1956        }
1957    }
1958    
1959    private class ActionRunner
1960        implements ActionInterceptors.ActionExecutor
1961    {
1962        RequestInterceptorContext _ctxt;
1963        private Action _action;
1964        private ActionForm _formBean;
1965        private ActionMapping _actionMapping;
1966
1967        public ActionRunner( RequestInterceptorContext context, Action action, ActionForm formBean,
1968                             ActionMapping actionMapping )
1969        {
1970            _ctxt = context;
1971            _action = action;
1972            _formBean = formBean;
1973            _actionMapping = actionMapping;
1974        }
1975
1976        public ActionForward execute()
1977            throws InterceptorException, ServletException JavaDoc, IOException JavaDoc
1978        {
1979            return PageFlowRequestProcessor.super.processActionPerform( _ctxt.getRequest(), _ctxt.getResponse(),
1980                                                                        _action, _formBean, _actionMapping );
1981        }
1982    }
1983
1984    protected ActionForward processActionPerform( HttpServletRequest JavaDoc request, HttpServletResponse JavaDoc response,
1985                                                  Action action, ActionForm form, ActionMapping mapping )
1986            throws IOException JavaDoc, ServletException JavaDoc
1987    {
1988        ServletContext JavaDoc servletContext = getServletContext();
1989        String JavaDoc actionName = InternalUtils.getActionName( mapping );
1990        ActionInterceptorContext context = null;
1991        List JavaDoc/*< Interceptor >*/ interceptors = null;
1992        
1993        if ( action instanceof FlowControllerAction )
1994        {
1995            FlowController fc = ( ( FlowControllerAction ) action ).getFlowController();
1996            
1997            if ( fc instanceof PageFlowController )
1998            {
1999                PageFlowController pfc = ( PageFlowController ) fc;
2000                context = new ActionInterceptorContext( request, response, servletContext, pfc, null, actionName );
2001                interceptors = context.getActionInterceptors();
2002            }
2003        }
2004        
2005        try
2006        {
2007            //
2008
// Run any before-action interceptors.
2009
//
2010
if ( interceptors != null && ! PageFlowRequestWrapper.get( request ).isReturningFromActionIntercept() )
2011            {
2012                Interceptors.doPreIntercept( context, interceptors );
2013                
2014                if ( context.hasInterceptorForward() )
2015                {
2016                    InterceptorForward fwd = context.getInterceptorForward();
2017                    
2018                    if ( _log.isDebugEnabled() )
2019                    {
2020                        
2021                        Interceptor overridingInterceptor = context.getOverridingInterceptor();
2022                        StringBuffer JavaDoc msg = new StringBuffer JavaDoc();
2023                        msg.append( "Action interceptor " );
2024                        msg.append( overridingInterceptor.getClass().getName() );
2025                        msg.append( " before action " );
2026                        msg.append( actionName );
2027                        msg.append( ": forwarding to " );
2028                        msg.append( fwd != null ? fwd.getPath() : "null [no forward]" );
2029                        _log.debug( msg.toString() );
2030                    }
2031                    
2032                    return fwd;
2033                }
2034            }
2035            else
2036            {
2037                PageFlowRequestWrapper.get( request ).setReturningFromActionIntercept( false );
2038            }
2039            
2040            //
2041
// Execute the action.
2042
//
2043
RequestInterceptorContext requestContext =
2044                    context != null ?
2045                    context :
2046                    new RequestInterceptorContext( request, response, getServletContext() );
2047            ActionRunner actionExecutor = new ActionRunner( requestContext, action, form, mapping );
2048            ActionForward ret = ActionInterceptors.wrapAction( context, interceptors, actionExecutor );
2049            
2050            //
2051
// Run any after-action interceptors.
2052
//
2053
if ( interceptors != null )
2054            {
2055                context.setOriginalForward( ret );
2056                Interceptors.doPostIntercept( context, interceptors );
2057                
2058                if ( context.hasInterceptorForward() )
2059                {
2060                    InterceptorForward fwd = context.getInterceptorForward();
2061                    
2062                    if ( _log.isDebugEnabled() )
2063                    {
2064                        _log.debug( "Action interceptor " + context.getOverridingInterceptor().getClass().getName()
2065                                    + " after action " + actionName + ": forwarding to "
2066                                    + fwd != null ? fwd.getPath() : "null [no forward]" );
2067                    }
2068                    
2069                    return fwd;
2070                }
2071            }
2072            
2073            return ret;
2074        }
2075        catch ( InterceptorException e )
2076        {
2077            throw new ServletException JavaDoc( e );
2078        }
2079    }
2080    
2081    void doActionForward( HttpServletRequest JavaDoc request, HttpServletResponse JavaDoc response, ActionForward forward )
2082        throws IOException JavaDoc, ServletException JavaDoc
2083    {
2084        request = PageFlowRequestWrapper.wrapRequest( request );
2085        processForwardConfig( request, response, forward );
2086    }
2087}
2088
Popular Tags