KickJava   Java API By Example, From Geeks To Geeks.

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


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.core.urls.MutableURI;
21 import org.apache.beehive.netui.pageflow.config.PageFlowActionMapping;
22 import org.apache.beehive.netui.pageflow.handler.ActionForwardHandler;
23 import org.apache.beehive.netui.pageflow.handler.ExceptionsHandler;
24 import org.apache.beehive.netui.pageflow.handler.FlowControllerHandlerContext;
25 import org.apache.beehive.netui.pageflow.handler.Handlers;
26 import org.apache.beehive.netui.pageflow.handler.LoginHandler;
27 import org.apache.beehive.netui.pageflow.internal.AdapterManager;
28 import org.apache.beehive.netui.pageflow.internal.InternalConstants;
29 import org.apache.beehive.netui.pageflow.internal.InternalExpressionUtils;
30 import org.apache.beehive.netui.pageflow.internal.InternalUtils;
31 import org.apache.beehive.netui.pageflow.scoping.ScopedRequest;
32 import org.apache.beehive.netui.util.internal.FileUtils;
33 import org.apache.beehive.netui.util.internal.InternalStringBuilder;
34 import org.apache.beehive.netui.util.internal.cache.ClassLevelCache;
35 import org.apache.beehive.netui.util.logging.Logger;
36 import org.apache.struts.Globals;
37 import org.apache.struts.action.ActionForm;
38 import org.apache.struts.action.ActionForward;
39 import org.apache.struts.action.ActionMapping;
40 import org.apache.struts.action.ActionMessage;
41 import org.apache.struts.action.ActionMessages;
42 import org.apache.struts.action.ActionServlet;
43 import org.apache.struts.action.RequestProcessor;
44 import org.apache.struts.config.ActionConfig;
45 import org.apache.struts.config.ControllerConfig;
46 import org.apache.struts.config.ModuleConfig;
47 import org.apache.struts.util.MessageResources;
48 import org.apache.struts.util.RequestUtils;
49 import org.apache.struts.util.TokenProcessor;
50
51 import javax.security.auth.login.LoginException JavaDoc;
52 import javax.servlet.ServletContext JavaDoc;
53 import javax.servlet.ServletException JavaDoc;
54 import javax.servlet.http.HttpServletRequest JavaDoc;
55 import javax.servlet.http.HttpServletResponse JavaDoc;
56 import javax.servlet.http.HttpSession JavaDoc;
57 import javax.sql.DataSource JavaDoc;
58 import java.io.IOException JavaDoc;
59 import java.lang.reflect.Field JavaDoc;
60 import java.lang.reflect.InvocationTargetException JavaDoc;
61 import java.lang.reflect.Method JavaDoc;
62 import java.net.URISyntaxException JavaDoc;
63 import java.util.ArrayList JavaDoc;
64 import java.util.Iterator JavaDoc;
65 import java.util.Locale JavaDoc;
66 import java.util.Map JavaDoc;
67
68
69
70 /**
71  * Base class for user-written flow controllers - {@link PageFlowController}s and {@link SharedFlowController}s.
72  */

73 public abstract class FlowController extends PageFlowManagedObject
74         implements PageFlowConstants, ActionResolver
75 {
76     private static final Logger _log = Logger.getInstance( FlowController.class );
77     
78     private static final String JavaDoc ONCREATE_EXCEPTION_FORWARD = InternalConstants.ATTR_PREFIX + "onCreateException";
79     private static final String JavaDoc CACHEID_ACTION_METHODS = InternalConstants.ATTR_PREFIX + "actionMethods";
80     private static final int DEFAULT_MAX_CONCURRENT_REQUEST_COUNT = 4;
81     private static final String JavaDoc MAX_CONCURRENT_REQUESTS_PARAM = "pageflow-max-concurrent-requests";
82     private static final int EXCEEDED_MAX_CONCURRENT_REQUESTS_ERRORCODE = 503;
83     private static final Locale JavaDoc DEFAULT_LOCALE = Locale.getDefault();
84     private static final ActionForward NULL_ACTION_FORWARD = new ActionForward();
85     private static final TokenProcessor TOKEN_PROCESSOR = TokenProcessor.getInstance();
86     
87     /**
88      * The system default Locale.
89      *
90      * @deprecated Use {@link #getDefaultLocale}.
91      */

92     protected static Locale JavaDoc defaultLocale = DEFAULT_LOCALE;
93
94
95     /**
96      * Get the current Struts ActionServlet.
97      *
98      * @deprecated This variable will be removed with no replacement. In most cases,
99      * {@link FlowController#getServletContext()} is sufficient; for other cases, the ActionServlet itself
100      * is in the ServletContext attribute {@link Globals#ACTION_SERVLET_KEY}.
101      */

102     protected transient ActionServlet servlet = null;
103     
104     
105     static class PerRequestState
106     {
107         private HttpServletRequest JavaDoc _request;
108         private HttpServletResponse JavaDoc _response;
109         private ActionMapping _actionMapping;
110
111         public PerRequestState( HttpServletRequest JavaDoc request, HttpServletResponse JavaDoc response, ActionMapping actionMapping )
112         {
113             _request = request;
114             _response = response;
115             _actionMapping = actionMapping;
116         }
117
118         public HttpServletRequest JavaDoc getRequest()
119         {
120             return _request;
121         }
122
123         public HttpServletResponse JavaDoc getResponse()
124         {
125             return _response;
126         }
127
128         public ActionMapping getActionMapping()
129         {
130             return _actionMapping;
131         }
132     }
133
134     /**
135      * Stores per-request state, which is <i>only valid during calls to {@link FlowController#execute} or {@link FlowController#handleException}</i>.
136      */

137     private transient PerRequestState _perRequestState;
138
139     /**
140      * Cached reference to the associated Struts ModuleConfig.
141      */

142     private transient ModuleConfig _moduleConfig = null;
143
144     /**
145      * @see #incrementRequestCount
146      */

147     private transient int _requestCount = 0;
148     
149     /**
150      * @see #incrementRequestCount
151      */

152     private static int _maxConcurrentRequestCount = -1;
153     
154
155     /**
156      * Default constructor.
157      */

158     protected FlowController()
159     {
160     }
161
162     /**
163      * Reinitialize the object for a new request. Used by the framework; normally should not be called directly.
164      */

165     public void reinitialize( HttpServletRequest JavaDoc request, HttpServletResponse JavaDoc response, ServletContext JavaDoc servletContext )
166     {
167         //
168
// Cache the associated ModuleConfig. This is used throughout the code, in places where the request
169
// isn't available to do a lazy initialization.
170
//
171
super.reinitialize( request, response, servletContext );
172         initModuleConfig( servletContext, request );
173         servlet = getServlet();
174     }
175
176     /**
177      * Log in the user, using "weak" username/password authentication.
178      *
179      * @param username the user's login name
180      * @param password the user's password
181      *
182      * @exception LoginException if the authentication failed
183      */

184     public void login( String JavaDoc username, String JavaDoc password )
185         throws LoginException JavaDoc
186     {
187         LoginHandler lh = Handlers.get( getServletContext() ).getLoginHandler();
188         lh.login( getHandlerContext(), username, password );
189     }
190     
191     /**
192      * Log out the current user.
193      *
194      * @param invalidateSessions if true, the session is invalidated (on all single-signon webapps);
195      * otherwise the session and its data are left intact (except for authentication
196      * information used internally by the server). To invalidate the session in only the
197      * current webapp, set this parameter to <code>false</code> and call
198      * {@link FlowController#getSession}.invalidate().
199      */

200     public void logout( boolean invalidateSessions )
201     {
202         LoginHandler lh = Handlers.get( getServletContext() ).getLoginHandler();
203         lh.logout( getHandlerContext(), invalidateSessions );
204     }
205
206     /**
207      * Send a Page Flow error to the browser.
208      *
209      * @deprecated Use {@link FlowController#sendError(String, HttpServletRequest, HttpServletResponse)} instead.
210      * @param errText the error message to display.
211      * @param response the current HttpServletResponse.
212      */

213     protected void sendError( String JavaDoc errText, HttpServletResponse JavaDoc response )
214         throws IOException JavaDoc
215     {
216         sendError( errText, null, response );
217     }
218     
219     /**
220      * Send a Page Flow error to the browser.
221      *
222      * @param errText the error message to display.
223      * @param response the current HttpServletResponse.
224      */

225     protected void sendError( String JavaDoc errText, HttpServletRequest JavaDoc request, HttpServletResponse JavaDoc response )
226         throws IOException JavaDoc
227     {
228         InternalUtils.sendError( "PageFlow_Custom_Error", null, request, response,
229                                  new Object JavaDoc[]{ getDisplayName(), errText } );
230     }
231     
232     /**
233      * Handle the given exception - invoke user code if appropriate and return a destination URI.
234      *
235      * @param ex the Exception to handle.
236      * @param mapping the Struts action mapping for current Struts action being processed.
237      * @param form the form-bean (if any) associated with the Struts action being processed. May be null.
238      * @param request the current HttpServletRequest.
239      * @param response the current HttpServletResponse.
240      * @return a Struts ActionForward object that specifies the URI that should be displayed.
241      * @throws ServletException if another Exception is thrown during handling of <code>ex</code>.
242      */

243     public synchronized ActionForward handleException( Throwable JavaDoc ex, ActionMapping mapping,
244                                                        ActionForm form, HttpServletRequest JavaDoc request,
245                                                        HttpServletResponse JavaDoc response )
246         throws IOException JavaDoc, ServletException JavaDoc
247     {
248         PerRequestState prevState = setPerRequestState( new PerRequestState( request, response, mapping ) );
249         
250         try
251         {
252             ExceptionsHandler eh = Handlers.get( getServletContext() ).getExceptionsHandler();
253             FlowControllerHandlerContext context = getHandlerContext();
254             
255             // First, put the exception into the request (or other applicable context).
256
Throwable JavaDoc unwrapped = eh.unwrapException( context, ex );
257             eh.exposeException( context, unwrapped, mapping );
258             return eh.handleException( context, unwrapped, mapping, form );
259         }
260         finally
261         {
262             setPerRequestState( prevState );
263         }
264     }
265     
266     /**
267      * Get the name of the current action being executed. This call is only valid
268      * during {@link FlowController#execute} (where any user action method is invoked), and during the lifecycle
269      * methods {@link FlowController#beforeAction} and {@link FlowController#afterAction}.
270      *
271      * @return the name of the current action being executed.
272      * @throws IllegalStateException if this method is invoked outside of action method
273      * execution (i.e., outside of the call to {@link FlowController#execute}, and outside of
274      * {@link FlowController#onCreate}, {@link FlowController#beforeAction}, {@link FlowController#afterAction}.
275      */

276
277     protected String JavaDoc getCurrentActionName()
278     {
279         return InternalUtils.getActionName( getActionMapping() );
280     }
281     
282     /**
283      * Perform decision logic to determine the next URI to be displayed.
284      *
285      * @param mapping the Struts ActionMapping for the current action being processed.
286      * @param form the form-bean (if any) associated with the Struts action being processed. May be null.
287      * @param request the current HttpServletRequest.
288      * @param response the current HttpServletResponse.
289      * @return a Struts ActionForward object that specifies the next URI to be displayed.
290      * @throws Exception if an Exception was thrown during user action-handling code.
291      */

292     public ActionForward execute( ActionMapping mapping, ActionForm form, HttpServletRequest JavaDoc request,
293                                   HttpServletResponse JavaDoc response )
294             throws Exception JavaDoc
295     {
296         //
297
// Don't actually run the action (and perform the associated synchronization) if there are too many
298
// concurrent requests to this instance.
299
//
300
if ( incrementRequestCount( request, response, getServletContext() ) )
301         {
302             try
303             {
304                 synchronized ( this )
305                 {
306                     return internalExecute( mapping, form, request, response );
307                 }
308             }
309             finally
310             {
311                 decrementRequestCount( request );
312             }
313         }
314         else
315         {
316             return null; // error was written to the response by incrementRequestCount()
317
}
318     }
319
320     /**
321      * An internal method for executing an action; should not be invoked directly.
322      */

323     protected ActionForward internalExecute( ActionMapping mapping, ActionForm form, HttpServletRequest JavaDoc request,
324                                              HttpServletResponse JavaDoc response )
325         throws Exception JavaDoc
326     {
327         ServletContainerAdapter sca = AdapterManager.getServletContainerAdapter( getServletContext() );
328         PageFlowEventReporter eventReporter = sca.getEventReporter();
329         eventReporter.actionRaised( this, mapping, form, request, response );
330         long startTime = System.currentTimeMillis();
331         
332         //
333
// If we handled an exception in onCreate, just forward to the result of that.
334
//
335
ActionForward onCreateFwd = ( ActionForward ) request.getAttribute( ONCREATE_EXCEPTION_FORWARD );
336         
337         if ( onCreateFwd != null )
338         {
339             return onCreateFwd == NULL_ACTION_FORWARD ? null : onCreateFwd;
340         }
341         
342         
343         PageFlowUtils.setActionURI( request );
344         
345         //
346
// First change the actionPath (path) so that it lines up with our naming convention
347
// for action methods.
348
//
349
boolean gotPastBeforeAction = false;
350         ServletContext JavaDoc servletContext = getServletContext();
351         PerRequestState prevState = setPerRequestState( new PerRequestState( request, response, mapping ) );
352
353         try
354         {
355             //
356
// beforeAction callback
357
//
358
beforeAction();
359             gotPastBeforeAction = true;
360             
361             PageFlowActionMapping pfActionMapping =
362                     mapping instanceof PageFlowActionMapping ? ( PageFlowActionMapping ) mapping : null;
363             Object JavaDoc unwrappedForm = InternalUtils.unwrapFormBean( form );
364             
365             //
366
// mapping.isOverloaded() means it's the base mapping for a set of overloaded mappings.
367
// Find the one appropriate to the passed-in form.
368
//
369
if ( unwrappedForm != null && pfActionMapping != null )
370             {
371                 if ( pfActionMapping.isOverloaded() )
372                 {
373                     String JavaDoc mappingPath = pfActionMapping.getPath();
374
375                     //
376
// Try the form class and all superclasses to get an overloaded action path.
377
//
378
for ( Class JavaDoc i = unwrappedForm.getClass(); i != null; i = i.getSuperclass() )
379                     {
380                         String JavaDoc formQualifiedActionPath = getFormQualifiedActionPath( i, mappingPath );
381                         ActionConfig cf = pfActionMapping.getModuleConfig().findActionConfig( formQualifiedActionPath );
382                             
383                         if ( cf != null )
384                         {
385                             assert cf instanceof PageFlowActionMapping : cf.getClass().getName();
386                                 
387                             if ( _log.isDebugEnabled() )
388                             {
389                                 _log.debug( "Found form-specific mapping " + cf.getPath() +
390                                            " -- choosing this one over current mapping " + mappingPath );
391                             }
392                                 
393                             pfActionMapping = ( PageFlowActionMapping ) cf;
394                             mapping = pfActionMapping;
395                             break;
396                         }
397                     }
398                 }
399             }
400             
401             String JavaDoc actionName = InternalUtils.getActionName( mapping );
402             
403             //
404
// Check whether isLoginRequired=true for this action.
405
//
406
LoginHandler loginHandler = Handlers.get( getServletContext() ).getLoginHandler();
407             
408             if ( pfActionMapping != null && pfActionMapping.isLoginRequired()
409                  && loginHandler.getUserPrincipal( getHandlerContext() ) == null )
410             {
411                 NotLoggedInException ex = createNotLoggedInException( actionName, request );
412                 return handleException( ex, mapping, form, request, response );
413             }
414             
415             //
416
// Now delegate to the appropriate action method, or if it's a simple action, handle it that way.
417
//
418
ActionForward retVal;
419             if ( pfActionMapping != null && pfActionMapping.isSimpleAction() )
420             {
421                 retVal = handleSimpleAction( pfActionMapping, form, request, servletContext );
422             }
423             else
424             {
425                 retVal = getActionMethodForward( actionName, unwrappedForm, request, response, mapping );
426             }
427             
428             ActionForward ret = forwardTo( retVal, mapping, request, response, actionName, null, form, servletContext );
429             long timeTaken = System.currentTimeMillis() - startTime;
430             eventReporter.actionSuccess( this, mapping, form, request, response, ret, timeTaken );
431             return ret;
432         }
433         catch ( Exception JavaDoc e )
434         {
435             //
436
// Even though we handle any Throwable thrown by the user's action method, we don't need
437
// to catch Throwable here, because anything thrown by the action method will be wrapped
438
// in an InvocationTargetException. Any Error (or other Throwable) that appears here
439
// should not be handled by handleException() -- it's probably a framework problem and
440
// should bubble out to the container.
441
//
442
return handleException( e, mapping, form, request, response );
443         }
444         finally
445         {
446             try
447             {
448                 ActionForward overrideReturn = null;
449                 
450                 if ( gotPastBeforeAction )
451                 {
452                     //
453
// afterAction callback
454
//
455
try
456                     {
457                         afterAction();
458                     }
459                     catch ( Throwable JavaDoc th )
460                     {
461                         overrideReturn = handleException( th, mapping, form, request, response );
462                     }
463                 }
464                 
465                 //
466
// Store information on this action for use with navigateTo=Jpf.NavigateTo.previousAction.
467
//
468
savePreviousActionInfo( form, request, mapping, getServletContext() );
469                 
470                 if ( overrideReturn != null )
471                 {
472                     return overrideReturn;
473                 }
474             }
475             finally
476             {
477                 setPerRequestState( prevState );
478             }
479         }
480     }
481
482     ActionForward forwardTo( ActionForward fwd, ActionMapping mapping, HttpServletRequest JavaDoc request,
483                              HttpServletResponse JavaDoc response, String JavaDoc actionName, ModuleConfig altModuleConfig,
484                              ActionForm form, ServletContext JavaDoc servletContext )
485     {
486         //
487
// This method is overridden in PageFlowController. Even though we're just delegating here, we can't remove it.
488
//
489
ActionForwardHandler handler = Handlers.get( servletContext ).getActionForwardHandler();
490         FlowControllerHandlerContext context = new FlowControllerHandlerContext( request, response, this );
491         return handler.doForward( context, fwd, mapping, actionName, altModuleConfig, form );
492     }
493     
494     NotLoggedInException createNotLoggedInException( String JavaDoc actionName, HttpServletRequest JavaDoc request )
495     {
496         if ( InternalUtils.sessionExpired( request ) )
497         {
498             return new LoginExpiredException( actionName, this );
499         }
500         else
501         {
502             return new NotLoggedInException( actionName, this );
503         }
504     }
505     
506     /**
507      * Initialize after object creation. This is a framework-invoked method; it should not normally be called directly.
508      */

509     public synchronized void create( HttpServletRequest JavaDoc request, HttpServletResponse JavaDoc response,
510                                      ServletContext JavaDoc servletContext )
511     {
512         PerRequestState prevState = setPerRequestState( new PerRequestState( request, response, null ) );
513         
514         try
515         {
516             try
517             {
518                 super.create( request, response, servletContext );
519             }
520             catch ( Throwable JavaDoc th )
521             {
522                 try
523                 {
524                     _log.info( "Handling exception in onCreate(), FlowController " + this, th );
525                     ActionForward fwd = handleException( th, null, null, request, response );
526                     if ( fwd == null ) fwd = NULL_ACTION_FORWARD;
527                     request.setAttribute( ONCREATE_EXCEPTION_FORWARD, fwd );
528                 }
529                 catch ( Exception JavaDoc e )
530                 {
531                     _log.error( "Exception thrown while handling exception in onCreate(): " + e.getMessage(), th );
532                 }
533             }
534         }
535         finally
536         {
537             setPerRequestState( prevState );
538         }
539         
540         PageFlowEventReporter er = AdapterManager.getServletContainerAdapter( servletContext ).getEventReporter();
541         er.flowControllerCreated( this, request, response );
542     }
543     
544     /**
545      * Internal destroy method that is invoked when this object is being removed from the session. This is a
546      * framework-invoked method; it should not normally be called directly.
547      */

548     void destroy( HttpSession JavaDoc session )
549     {
550         onDestroy(); // for backwards compatiblity
551
super.destroy( session );
552         
553         //
554
// We may have lost our transient ServletContext reference. Try to get the ServletContext reference from the
555
// HttpSession object.
556
//
557
ServletContext JavaDoc servletContext = getServletContext();
558         if ( servletContext == null && session != null ) servletContext = session.getServletContext();
559
560         if ( servletContext != null )
561         {
562             PageFlowEventReporter er = AdapterManager.getServletContainerAdapter( servletContext ).getEventReporter();
563             er.flowControllerDestroyed( this );
564         }
565     }
566     
567     /**
568      * Get the Struts module path for this controller.
569      *
570      * @return a String that is the Struts module path for this controller.
571      */

572     public abstract String JavaDoc getModulePath();
573
574     /**
575      * Callback that occurs before any user action method is invoked. {@link FlowController#getRequest},
576      * {@link FlowController#getResponse}, {@link FlowController#getSession}, and
577      * {@link FlowController#getActionMapping} may all be used during this method. The action to be run can be
578      * discovered by calling {@link ActionMapping#getPath} on the value returned from
579      * {@link FlowController#getActionMapping}.
580      */

581     protected synchronized void beforeAction()
582         throws Exception JavaDoc
583     {
584     }
585     
586     /**
587      * Callback that occurs after any user action method is invoked. {@link FlowController#getRequest},
588      * {@link FlowController#getResponse}, {@link FlowController#getSession}, and
589      * {@link FlowController#getActionMapping} may all be used during this method. The action that was run can be
590      * discovered by calling {@link ActionMapping#getPath} on the value returned from
591      * {@link FlowController#getActionMapping}.
592      */

593     protected synchronized void afterAction()
594         throws Exception JavaDoc
595     {
596     }
597
598     /**
599      * Callback that is invoked when this controller instance is created. {@link FlowController#getRequest},
600      * {@link FlowController#getResponse}, {@link FlowController#getSession} may all be used during this method.
601      */

602     protected void onCreate()
603         throws Exception JavaDoc
604     {
605     }
606
607     /**
608      * Callback that is invoked when this controller instance is "destroyed", i.e., removed from the user session.
609      * {@link FlowController#getRequest}, {@link FlowController#getResponse}, and {@link FlowController#getActionMapping}
610      * may <i>not</i> be used during this method, since it may be called due to session termination outside of a
611      * request. {@link FlowController#getSession} also may not be used, but the session is passed as an argument
612      * to {@link FlowController#onDestroy(HttpSession)}, which should be used in place of this method.
613      * <br>
614      * Note that this method is <strong>not synchronized</strong>. It is dangerous to synchronize your override of
615      * this method because it is invoked during a callback from the Servlet container. Depending on the container,
616      * synchronization here can cause deadlocks.
617      *
618      * @deprecated {@link FlowController#onDestroy(HttpSession)} should be used instead.
619      */

620     protected void onDestroy()
621     {
622     }
623     
624     /**
625      * Callback that is invoked when this controller instance is "destroyed", i.e., removed from the user session.
626      * {@link FlowController#getRequest}, {@link FlowController#getResponse}, and {@link FlowController#getActionMapping}
627      * may <i>not</i> be used during this method, since it may be called due to session termination outside of a
628      * request. {@link FlowController#getSession} also may not be used, but the session is passed as an argument.
629      * <br>
630      * Note that this method is <strong>not synchronized</strong>. It is dangerous to synchronize your override of
631      * this method because it is invoked during a callback from the Servlet container. Depending on the container,
632      * synchronization here can cause deadlocks.
633      */

634     protected void onDestroy( HttpSession JavaDoc session )
635     {
636     }
637     
638     /**
639      * Get a legacy PreviousPageInfo.
640      * @deprecated This method will be removed without replacement in a future release.
641      */

642     public abstract PreviousPageInfo getPreviousPageInfoLegacy( PageFlowController curJpf, HttpServletRequest JavaDoc request );
643     
644     /**
645      * Get an action handler method of the given name/signature.
646      *
647      * @param methodName the name of the action handler method to query.
648      * @param argType the type of the argument to the action handler method; if <code>null</code>,
649      * the method takes no arguments.
650      * @return the desired Method, or <code>null</code> if it doesn't exist.
651      */

652     protected Method JavaDoc getActionMethod( String JavaDoc methodName, Class JavaDoc argType )
653     {
654         String JavaDoc cacheKey = argType != null ? methodName + '/' + argType.getName() : methodName;
655         Class JavaDoc thisClass = getClass();
656         ClassLevelCache cache = ClassLevelCache.getCache( thisClass );
657         Method JavaDoc actionMethod = ( Method JavaDoc ) cache.get( CACHEID_ACTION_METHODS, cacheKey );
658         
659         if ( actionMethod != null )
660         {
661             return actionMethod;
662         }
663         else
664         {
665             //
666
// We didn't find it in the cache. Look for it reflectively.
667
//
668
if ( argType == null )
669             {
670                 //
671
// No form -- look for a method with no arguments.
672
//
673
actionMethod = InternalUtils.lookupMethod( thisClass, methodName, null );
674             }
675             else
676             {
677                 //
678
// Has a form. Look for a method with a single argument -- either the given type
679
// or any superclass.
680
//
681
while ( argType != null )
682                 {
683                     actionMethod = InternalUtils.lookupMethod( thisClass, methodName, new Class JavaDoc[]{ argType } );
684                     
685                     if ( actionMethod != null )
686                     {
687                         break;
688                     }
689                     
690                     argType = argType.getSuperclass();
691                 }
692             }
693                 
694             if ( actionMethod != null && actionMethod.getReturnType().equals( Forward.class ) )
695             {
696                 actionMethod.setAccessible( true );
697                 cache.put( CACHEID_ACTION_METHODS, cacheKey, actionMethod );
698                 return actionMethod;
699             }
700         }
701         
702         return null;
703     }
704
705     private Class JavaDoc getFormClass( Object JavaDoc form, ActionMapping mapping, HttpServletRequest JavaDoc request )
706         throws ClassNotFoundException JavaDoc
707     {
708         if ( mapping instanceof PageFlowActionMapping )
709         {
710             String JavaDoc formClassName = ( ( PageFlowActionMapping ) mapping ).getFormClass();
711             
712             if ( formClassName != null )
713             {
714                 return InternalUtils.getReloadableClass( formClassName, getServletContext() );
715             }
716         }
717         
718         return form != null ? form.getClass() : null;
719     }
720     
721     /**
722      * Get the ActionForward returned by the action handler method that corresponds to the
723      * given action name and form-bean, or send an error to the browser if there is no
724      * matching method.
725      *
726      * @param actionName the name of the Struts action to handle.
727      * @param inputForm the form-bean associated with the action. May be <code>null</code>.
728      * @param response the current HttpServletResponse.
729      * @return the ActionForward returned by the action handler method, or <code>null</code> if
730      * there was no matching method (in which case an error was written to the
731      * browser.
732      * @throws Exception if an Exception was raised in user code.
733      */

734     ActionForward getActionMethodForward( String JavaDoc actionName, Object JavaDoc inputForm,
735                                           HttpServletRequest JavaDoc request, HttpServletResponse JavaDoc response,
736                                           ActionMapping mapping )
737         throws Exception JavaDoc
738     {
739         //
740
// Find the method.
741
//
742
Class JavaDoc formClass = getFormClass( inputForm, mapping, request );
743         Method JavaDoc actionMethod = getActionMethod( actionName, formClass );
744
745         //
746
// Invoke the method.
747
//
748
if ( actionMethod != null )
749         {
750             return invokeActionMethod( actionMethod, inputForm, request, mapping );
751         }
752         
753         if ( _log.isWarnEnabled() )
754         {
755             InternalStringBuilder msg = new InternalStringBuilder( "Could not find matching action method for action=" );
756             msg.append( actionName ).append( ", form=" );
757             msg.append( inputForm != null ? inputForm.getClass().getName() :"[none]" );
758             _log.warn( msg.toString() );
759         }
760
761         PageFlowException ex = new NoMatchingActionMethodException( actionName, inputForm, this );
762         InternalUtils.throwPageFlowException( ex, request );
763         return null;
764     }
765
766     private static String JavaDoc getFormQualifiedActionPath( Class JavaDoc formClass, String JavaDoc actionPath )
767     {
768         InternalStringBuilder ret = new InternalStringBuilder( actionPath );
769         ret.append( '_' );
770         ret.append( formClass.getName().replace( '.', '_' ).replace( '$', '_' ) );
771         return ret.toString();
772     }
773     
774     /**
775      * Invoke the given action handler method, passing it an argument if appropriate.
776      *
777      * @param method the action handler method to invoke.
778      * @param arg the form-bean to pass; may be <code>null</code>.
779      * @return the ActionForward returned by the action handler method.
780      * @throws Exception if an Exception was raised in user code.
781      */

782     protected ActionForward invokeActionMethod( Method JavaDoc method, Object JavaDoc arg )
783         throws Exception JavaDoc
784     {
785         return invokeActionMethod( method, arg, getRequest(), getActionMapping() );
786     }
787     
788     /**
789      * Invoke the given action handler method, passing it an argument if appropriate.
790      *
791      * @param method the action handler method to invoke.
792      * @param arg the form-bean to pass; may be <code>null</code>.
793      * @param request the current HttpServletRequest.
794      * @return the ActionForward returned by the action handler method.
795      * @throws Exception if an Exception was raised in user code.
796      */

797     ActionForward invokeActionMethod( Method JavaDoc method, Object JavaDoc arg, HttpServletRequest JavaDoc request, ActionMapping mapping )
798         throws Exception JavaDoc
799     {
800         Class JavaDoc[] paramTypes = method.getParameterTypes();
801
802         try
803         {
804             if ( paramTypes.length > 0 && paramTypes[0].isInstance( arg ) )
805             {
806                 if ( _log.isDebugEnabled() )
807                 {
808                     _log.debug( "Invoking action method " + method.getName() + '(' + paramTypes[0].getName() + ')' );
809                 }
810     
811                 return ( ActionForward ) method.invoke( this, new Object JavaDoc[]{ arg } );
812             }
813             else if ( paramTypes.length == 0 )
814             {
815                 if ( _log.isDebugEnabled() )
816                 {
817                     _log.debug( "Invoking action method " + method.getName() + "()" );
818                 }
819     
820                 return ( ActionForward ) method.invoke( this, null );
821             }
822         }
823         finally
824         {
825             boolean readonly = false;
826             
827             if ( mapping instanceof PageFlowActionMapping )
828             {
829                 PageFlowActionMapping pfam = ( PageFlowActionMapping ) mapping;
830                 readonly = pfam.isReadonly();
831             }
832
833             if ( ! readonly )
834             {
835                 ensureFailover( getRequest() );
836             }
837         }
838
839         if ( _log.isWarnEnabled() )
840         {
841             _log.warn( "Could not find action method " + method.getName() + " with appropriate signature." );
842         }
843         
844         return null;
845     }
846
847     /**
848      * Get the current HttpServletRequest. This call is only valid during {@link FlowController#execute} (where
849      * any user action method is invoked), and during the lifecycle methods {@link FlowController#onCreate},
850      * {@link FlowController#beforeAction}, {@link FlowController#afterAction}.
851      *
852      * @return the current HttpServletRequest.
853      * @throws IllegalStateException if this method is invoked outside of action method
854      * execution (i.e., outside of the call to {@link FlowController#execute}, and outside of
855      * {@link FlowController#onCreate}, {@link FlowController#beforeAction}, {@link FlowController#afterAction}.
856      */

857     protected final HttpServletRequest JavaDoc getRequest()
858     {
859         if ( _perRequestState == null )
860         {
861             throw new IllegalStateException JavaDoc( "getRequest was called outside of a valid context." );
862         }
863
864         return _perRequestState.getRequest();
865     }
866
867     /**
868      * Get the current HttpServletResponse. This call is only valid during {@link FlowController#execute} (where
869      * any user action method is invoked), and during the lifecycle methods {@link FlowController#onCreate},
870      * {@link FlowController#beforeAction}, {@link FlowController#afterAction}.
871      *
872      * @return the current HttpServletResponse.
873      * @throws IllegalStateException if this method is invoked outside of action method
874      * execution (i.e., outside of the call to {@link FlowController#execute}, and outside of
875      * {@link FlowController#onCreate}, {@link FlowController#beforeAction}, {@link FlowController#afterAction}.
876      */

877     protected final HttpServletResponse JavaDoc getResponse()
878     {
879         if ( _perRequestState == null )
880         {
881             throw new IllegalStateException JavaDoc( "getResponse was called outside of a valid context." );
882         }
883
884         return _perRequestState.getResponse();
885     }
886
887     /**
888      * Get the current Struts ActionMapping, which is information from the Struts-XML &lt;action&gt;
889      * tag that corresponds to the current action being executed. This call is only valid during
890      * {@link FlowController#execute} (where any user action method is invoked), and during the lifecycle
891      * methods {@link FlowController#beforeAction} and {@link FlowController#afterAction}.
892      * @deprecated Use {@link FlowController#getActionMapping} instead.
893      *
894      * @return the current Struts ActionMapping.
895      * @throws IllegalStateException if this method is invoked outside of action method
896      * execution (i.e., outside of the call to {@link FlowController#execute}, and outside of
897      * {@link FlowController#onCreate}, {@link FlowController#beforeAction}, {@link FlowController#afterAction}.
898      */

899     protected final ActionMapping getMapping()
900     {
901         return getActionMapping();
902     }
903
904     /**
905      * Get the current Struts ActionMapping, which is information from the Struts-XML &lt;action&gt;
906      * tag that corresponds to the current action being executed. This call is only valid
907      * during {@link FlowController#execute} (where any user action method is invoked), and during the lifecycle
908      * methods {@link FlowController#beforeAction} and {@link FlowController#afterAction}.
909      *
910      * @return the current Struts ActionMapping.
911      * @throws IllegalStateException if this method is invoked outside of action method
912      * execution (i.e., outside of the call to {@link FlowController#execute}, and outside of
913      * {@link FlowController#onCreate}, {@link FlowController#beforeAction}, {@link FlowController#afterAction}.
914      */

915     protected final ActionMapping getActionMapping()
916     {
917         if ( _perRequestState == null )
918         {
919             throw new IllegalStateException JavaDoc( "getActionMapping was called outside of a valid context." );
920         }
921
922         return _perRequestState.getActionMapping();
923     }
924
925     /**
926      * Get the current user session. This call is only valid during {@link FlowController#execute} (where
927      * any user action method is invoked), and during the lifecycle methods {@link FlowController#onCreate},
928      * {@link FlowController#onDestroy}, {@link FlowController#beforeAction}, {@link FlowController#afterAction}.
929      *
930      * @return the HttpSession for the current user session.
931      * @throws IllegalStateException if this method is invoked outside of action method
932      * execution (i.e., outside of the call to {@link FlowController#execute}, and outside of
933      * {@link FlowController#onCreate}, {@link FlowController#onDestroy}, {@link FlowController#beforeAction}, {@link FlowController#afterAction}.
934      */

935     protected final HttpSession JavaDoc getSession()
936     {
937         if ( _perRequestState == null )
938         {
939             throw new IllegalStateException JavaDoc( "getSession was called outside of a valid context." );
940         }
941
942         return _perRequestState.getRequest().getSession( true );
943     }
944
945     PerRequestState setPerRequestState( PerRequestState state )
946     {
947         if ( state != null )
948         {
949             assert state.getRequest() != null;
950             assert state.getResponse() != null;
951         }
952
953         PerRequestState prevState = _perRequestState;
954         _perRequestState = state;
955         return prevState;
956     }
957
958     /**
959      * Get the Struts ModuleConfig object associated with this FlowController.
960      */

961     public final ModuleConfig getModuleConfig()
962     {
963         assert _moduleConfig != null : "no cached ModuleConfig for " + getClass().getName();
964         return _moduleConfig;
965     }
966     
967     private void initModuleConfig( ServletContext JavaDoc servletContext, HttpServletRequest JavaDoc request )
968     {
969         if ( _moduleConfig == null )
970         {
971             _moduleConfig = InternalUtils.getModuleConfig( getModulePath(), servletContext );
972             
973             if ( _moduleConfig == null )
974             {
975                 //
976
// If we got here, it's possible that we're dynamically registering modules, and that the
977
// module hasn't been registered yet. Try it.
978
//
979
ActionServlet actionServlet = InternalUtils.getActionServlet( servletContext );
980                 if ( actionServlet instanceof AutoRegisterActionServlet )
981                 {
982                     try
983                     {
984                         AutoRegisterActionServlet servlet = ( AutoRegisterActionServlet ) actionServlet;
985                         _moduleConfig = servlet.ensureModuleRegistered( getModulePath(), request );
986                     }
987                     catch ( Exception JavaDoc e )
988                     {
989                         _log.error( "Error while registering module " + getModulePath(), e );
990                     }
991                 }
992             }
993             
994             assert _moduleConfig != null : getModulePath() + "; " + getClass().getName();
995         }
996     }
997     
998     /**
999      * Gets the Struts module configuration associated with this controller.
1000     *
1001     * @param servletContext the current ServletContext.
1002     * @return the Struts ModuleConfig for this controller.
1003     */

1004    public ModuleConfig getModuleConfig( ServletContext JavaDoc servletContext, HttpServletRequest JavaDoc request )
1005    {
1006        initModuleConfig( servletContext, request );
1007        return _moduleConfig;
1008    }
1009
1010    /**
1011     * Resolve the given action name to a URI. This version assumes that the ActionServlet
1012     * class should be {@link PageFlowActionServlet}.
1013     * Note: this method invokes the full action-processing cycle on a {@link ScopedRequest}. Use
1014     * {@link FlowController#resolveAction} to resolve the URI for an action in the current page flow.
1015     * @exclude
1016     * @deprecated Use {@link PageFlowUtils#strutsLookup} instead. This method will be removed in v1.1.
1017     */

1018    public static ActionResult lookup( String JavaDoc actionName, ServletContext JavaDoc context, HttpServletRequest JavaDoc request,
1019                                       HttpServletResponse JavaDoc response )
1020        throws Exception JavaDoc
1021    {
1022        return PageFlowUtils.strutsLookup( context, request, response, actionName, null );
1023    }
1024    
1025    /**
1026     * Resolve the given action name to a URI.
1027     * Note: this method invokes the full action-processing cycle on a {@link ScopedRequest}. Use
1028     * {@link FlowController#resolveAction} to resolve the URI for an action in the current page flow.
1029     * @exclude
1030     * @deprecated Use {@link PageFlowUtils#strutsLookup} instead. This method will be removed in v1.1.
1031     */

1032    public static ActionResult lookup( String JavaDoc actionName, ServletContext JavaDoc context, HttpServletRequest JavaDoc request,
1033                                       HttpServletResponse JavaDoc response, String JavaDoc actionServletClassName )
1034        throws Exception JavaDoc
1035    {
1036        return PageFlowUtils.strutsLookup( context, request, response, actionName, null );
1037    }
1038    
1039    /**
1040     * Call an action and return the result URI.
1041     *
1042     * @param actionName the name of the action to run.
1043     * @param form the form bean instance to pass to the action, or <code>null</code> if none should be passed.
1044     * @return the result webapp-relative URI, as a String.
1045     * @throws ActionNotFoundException when the given action does not exist in this FlowController.
1046     * @throws Exception if the action method throws an Exception.
1047     */

1048    public String JavaDoc resolveAction( String JavaDoc actionName, Object JavaDoc form, HttpServletRequest JavaDoc request,
1049                                 HttpServletResponse JavaDoc response )
1050        throws Exception JavaDoc
1051    {
1052        ActionMapping mapping = ( ActionMapping ) getModuleConfig().findActionConfig( '/' + actionName );
1053        
1054        if ( mapping == null )
1055        {
1056            InternalUtils.throwPageFlowException( new ActionNotFoundException( actionName, this, form ), request );
1057        }
1058        
1059        ActionForward fwd = getActionMethodForward( actionName, form, request, response, mapping );
1060        
1061        if ( fwd instanceof Forward )
1062        {
1063            ( ( Forward ) fwd ).initialize( mapping, this, request );
1064        }
1065        
1066        String JavaDoc path = fwd.getPath();
1067        if ( fwd.getContextRelative() || FileUtils.isAbsoluteURI( path ) )
1068        {
1069            return path;
1070        }
1071        else
1072        {
1073            return getModulePath() + path;
1074        }
1075    }
1076
1077    /**
1078     * Call an action and return the result URI.
1079     *
1080     * @deprecated Use {@link FlowController#resolveAction(String, Object, HttpServletRequest, HttpServletResponse)} instead.
1081     * @param actionName the name of the action to run.
1082     * @param form the form bean instance to pass to the action, or <code>null</code> if none should be passed.
1083     * @return the result webapp-relative URI, as a String.
1084     * @throws ActionNotFoundException when the given action does not exist in this FlowController.
1085     * @throws Exception if the action method throws an Exception.
1086     */

1087    public String JavaDoc resolveAction( String JavaDoc actionName, Object JavaDoc form )
1088        throws Exception JavaDoc
1089    {
1090        return resolveAction( actionName, form, getRequest(), getResponse() );
1091    }
1092
1093    /**
1094     * Get a list of the names of actions handled by methods in this PageFlowController.
1095     *
1096     * @return a String array containing the names of actions handled by methods in this PageFlowController.
1097     */

1098    public String JavaDoc[] getActions()
1099    {
1100        ActionConfig[] actionConfigs = getModuleConfig().findActionConfigs();
1101        ArrayList JavaDoc actionNames = new ArrayList JavaDoc();
1102        
1103        for ( int i = 0; i < actionConfigs.length; i++ )
1104        {
1105            ActionConfig ac = actionConfigs[i];
1106            actionNames.add( ac.getPath().substring( 1 ) ); // every action path has a '/' in front of it
1107
}
1108        
1109        return ( String JavaDoc[] ) actionNames.toArray( new String JavaDoc[0] );
1110    }
1111    
1112    /**
1113     * Tell whether a given String is the name of an action handled by a method in this PageFlowController.
1114     *
1115     * @param name the action-name to query.
1116     * @return <code>true</code> if <code>name</code> is the name of an action handled by a method in this
1117     * PageFlowController.
1118     */

1119    public boolean isAction( String JavaDoc name )
1120    {
1121        return getModuleConfig().findActionConfig( '/' + name ) != null;
1122    }
1123    
1124    /**
1125     * Tell whether this is a {@link PageFlowController}.
1126     *
1127     * @return <code>true</code> if this is a {@link PageFlowController}.
1128     */

1129    public boolean isPageFlow()
1130    {
1131        return false;
1132    }
1133    
1134    /**
1135     * Get the current Struts ActionServlet.
1136     *
1137     * @deprecated This method will be removed with no replacement. In most cases, {@link FlowController#getServletContext()} is
1138     * sufficient; for other cases, the ActionServlet itself is in the ServletContext attribute
1139     * {@link Globals#ACTION_SERVLET_KEY}.
1140     * @return the ActionServlet.
1141     */

1142    protected ActionServlet getServlet()
1143    {
1144        return InternalUtils.getActionServlet( getServletContext() );
1145    }
1146    
1147    /**
1148     * Called on this object for non-lookup (refresh) requests. This is a framework-invoked method that should not
1149     * normally be called directly.
1150     */

1151    public final synchronized void refresh( HttpServletRequest JavaDoc request, HttpServletResponse JavaDoc response )
1152    {
1153        PerRequestState prevState = setPerRequestState( new PerRequestState( request, response, null ) );
1154
1155        try
1156        {
1157            onRefresh();
1158        }
1159        finally
1160        {
1161            setPerRequestState( prevState );
1162        }
1163    }
1164    
1165    /**
1166     * Callback that is invoked when this controller is involved in a refresh request, as can happen in a portal
1167     * environment on a request where no action is run in the current page flow, but a previously-displayed page in the
1168     * page flow is re-rendered.
1169     */

1170    protected void onRefresh()
1171    {
1172    }
1173    
1174    /**
1175     * Remove this instance from the user session.
1176     */

1177    protected void remove()
1178    {
1179        removeFromSession( getRequest() );
1180    }
1181    
1182    /**
1183     * Used by derived classes to store information on the most recent action executed.
1184     */

1185    void savePreviousActionInfo( ActionForm form, HttpServletRequest JavaDoc request, ActionMapping mapping,
1186                                 ServletContext JavaDoc servletContext )
1187    {
1188    }
1189    
1190    /**
1191     * Store information about recent pages displayed. This is a framework-invoked method that should not normally be
1192     * called directly.
1193     */

1194    public void savePreviousPageInfo( ActionForward forward, ActionForm form, ActionMapping mapping,
1195                                      HttpServletRequest JavaDoc request, ServletContext JavaDoc servletContext,
1196                                      boolean isSpecialForward )
1197    {
1198    }
1199
1200    /**
1201     * When this FlowController does not use a {@link org.apache.beehive.netui.pageflow.annotations.Jpf.Forward &#64;Jpf.Forward}
1202     * annotation with a
1203     * <code>navigateTo=</code>{@link org.apache.beehive.netui.pageflow.annotations.Jpf.NavigateTo#previousAction Jpf.NavigateTo.previousAction}
1204     * attribute, the following methods always return <code>null</code> by default.
1205     * <ul>
1206     * <li>getPreviousActionInfo</li>
1207     * <li>getPreviousActionURI</li>
1208     * <li>getPreviousForm</li>
1209     * </ul>
1210     * Override <code>alwaysTrackPreviousAction</code> (which always returns <code>false</code>) to enable these methods
1211     * in all cases.
1212     *
1213     * @return <code>true</code> if the previous action should always be tracked, regardless of whether
1214     * <code>return-to="previousAction"</code> is used.
1215     * @see PageFlowController#getPreviousActionInfo
1216     * @see PageFlowController#getPreviousActionURI
1217     * @see PageFlowController#getPreviousFormBean
1218     */

1219    protected boolean alwaysTrackPreviousAction()
1220    {
1221        return false;
1222    }
1223    
1224    /**
1225     * When this FlowController does not use a {@link org.apache.beehive.netui.pageflow.annotations.Jpf.Forward &#64;Jpf.Forward}
1226     * annotation with either a
1227     * <code>navigateTo</code>={@link org.apache.beehive.netui.pageflow.annotations.Jpf.NavigateTo#currentPage Jpf.NavigateTo.currentPage}
1228     * attribute or a
1229     * <code>navigateTo</code>={@link org.apache.beehive.netui.pageflow.annotations.Jpf.NavigateTo#previousPage Jpf.NavigateTo.previousPage}
1230     * attribute, the following methods always return <code>null</code> by default.
1231     * <ul>
1232     * <li>getCurrentPageInfo</li>
1233     * <li>getPreviousPageInfo</li>
1234     * <li>getCurrentForwardPath</li>
1235     * <li>getPreviousForwardPath</li>
1236     * </ul>
1237     * Override <code>alwaysTrackPreviousPage</code> (which always returns <code>false</code>) to enable these methods
1238     * in all cases.
1239     *
1240     * @return <code>true</code> if the previous page should always be tracked, regardless
1241     * of whether <code>return-to="currentPage"</code> or <code>return-to="previousPage"</code>
1242     * is used.
1243     * @see PageFlowController#getCurrentPageInfo
1244     * @see PageFlowController#getPreviousPageInfo
1245     * @see PageFlowController#getCurrentForwardPath
1246     * @see PageFlowController#getPreviousForwardPath
1247     */

1248    protected boolean alwaysTrackPreviousPage()
1249    {
1250        return false;
1251    }
1252
1253    /**
1254     * Increment the count of concurrent requests to this FlowController. Note that this method
1255     * is not synchronized -- we use it to decide whether to synchronize on this instance,
1256     * or to bail out with an error message about too many concurrent requests.
1257     */

1258    boolean incrementRequestCount( HttpServletRequest JavaDoc request, HttpServletResponse JavaDoc response,
1259                                   ServletContext JavaDoc servletContext )
1260        throws IOException JavaDoc
1261    {
1262        //
1263
// First cache the max-concurrent-request-count value.
1264
//
1265
if ( _maxConcurrentRequestCount == -1 )
1266        {
1267            _maxConcurrentRequestCount = DEFAULT_MAX_CONCURRENT_REQUEST_COUNT;
1268            String JavaDoc countStr = servletContext.getInitParameter( MAX_CONCURRENT_REQUESTS_PARAM );
1269            
1270            if ( countStr != null )
1271            {
1272                try
1273                {
1274                    _maxConcurrentRequestCount = Integer.parseInt( countStr );
1275                }
1276                catch ( NumberFormatException JavaDoc e )
1277                {
1278                    _log.error( "Invalid value for servlet context parameter" + MAX_CONCURRENT_REQUESTS_PARAM
1279                                + ": " + countStr, e );
1280                }
1281                
1282                if ( _maxConcurrentRequestCount < 1 )
1283                {
1284                    _maxConcurrentRequestCount = DEFAULT_MAX_CONCURRENT_REQUEST_COUNT;
1285                    _log.error( "Invalid value for servlet context parameter" + MAX_CONCURRENT_REQUESTS_PARAM
1286                                + ": " + countStr );
1287                }
1288            }
1289        }
1290        
1291        //
1292
// Now, if the current count of concurrent requests to this instance is greater than the max,
1293
// send an error on the response.
1294
//
1295
if ( _requestCount >= _maxConcurrentRequestCount )
1296        {
1297            if ( _log.isDebugEnabled() )
1298            {
1299                _log.debug( "Too many requests to FlowController " + getDisplayName() + " ("
1300                           + ( _requestCount + 1 ) + '>' + _maxConcurrentRequestCount + "); returning error code "
1301                           + EXCEEDED_MAX_CONCURRENT_REQUESTS_ERRORCODE );
1302            }
1303
1304            response.sendError( EXCEEDED_MAX_CONCURRENT_REQUESTS_ERRORCODE );
1305            return false;
1306        }
1307        
1308        //
1309
// We're ok -- increment the count and continue.
1310
//
1311
++_requestCount;
1312        return true;
1313    }
1314    
1315    void decrementRequestCount( HttpServletRequest JavaDoc request )
1316    {
1317        assert _requestCount > 0 : request.getRequestURI();
1318        --_requestCount;
1319    }
1320
1321    /**
1322     * Invoke the given exception handler method. This is a framework-invoked method that should not normally be called
1323     * directly
1324     *
1325     * @param method the action handler method to invoke.
1326     * @param ex the Throwable that is to be handled.
1327     * @param message the String message that is to be passed to the handler method.
1328     * @param formBean the form bean that is associated with the action being processed; may be <code>null</code>.
1329     * @param request the current HttpServletRequest.
1330     * @param response the current HttpServletResponse.
1331     * @param readonly if <code>true</code>, session failover will not be triggered after invoking the method.
1332     * @return the ActionForward returned by the exception handler method.
1333     */

1334    public synchronized ActionForward invokeExceptionHandler(
1335            Method JavaDoc method, Throwable JavaDoc ex, String JavaDoc message, Object JavaDoc formBean, ActionForm wrappedFormBean,
1336            ActionMapping actionMapping, HttpServletRequest JavaDoc request, HttpServletResponse JavaDoc response, boolean readonly )
1337        throws IOException JavaDoc, ServletException JavaDoc
1338    {
1339        PerRequestState prevState = setPerRequestState( new PerRequestState( request, response, actionMapping ) );
1340        
1341        try
1342        {
1343            if ( _log.isDebugEnabled() )
1344            {
1345                _log.debug( "Invoking exception handler method " + method.getName() + '('
1346                           + method.getParameterTypes()[0].getName() + ", ...)" );
1347            }
1348
1349            try
1350            {
1351                ActionForward retVal = null;
1352                String JavaDoc actionName = InternalUtils.getActionName( actionMapping );
1353                
1354                if ( actionName == null && ex instanceof PageFlowException )
1355                {
1356                    actionName = ( ( PageFlowException ) ex ).getActionName();
1357                }
1358            
1359                try
1360                {
1361                    Object JavaDoc[] args = new Object JavaDoc[]{ ex, actionName, message, formBean };
1362                    retVal = ( ActionForward ) method.invoke( this, args );
1363                }
1364                finally
1365                {
1366                    if ( ! readonly )
1367                    {
1368                        ensureFailover( request );
1369                    }
1370                }
1371            
1372                ActionForwardHandler handler = Handlers.get( getServletContext() ).getActionForwardHandler();
1373                return handler.doForward( getHandlerContext(), retVal, actionMapping, actionName, getModuleConfig(),
1374                                          wrappedFormBean );
1375            }
1376            catch ( InvocationTargetException JavaDoc e )
1377            {
1378                Throwable JavaDoc target = e.getTargetException();
1379            
1380                if ( target instanceof Exception JavaDoc )
1381                {
1382                    throw ( Exception JavaDoc ) target;
1383                }
1384                else
1385                {
1386                    throw e;
1387                }
1388            }
1389        }
1390        catch ( Throwable JavaDoc e )
1391        {
1392            _log.error( "Exception while handling exception " + ex.getClass().getName()
1393                        + ". The original exception will be thrown.", e );
1394            
1395            ExceptionsHandler eh = Handlers.get( getServletContext() ).getExceptionsHandler();
1396            FlowControllerHandlerContext context = new FlowControllerHandlerContext( request, response, this );
1397            Throwable JavaDoc unwrapped = eh.unwrapException( context, e );
1398            
1399            if ( ! eh.eatUnhandledException( context, unwrapped ) )
1400            {
1401                if ( ex instanceof ServletException JavaDoc ) throw ( ServletException JavaDoc ) ex;
1402                if ( ex instanceof IOException JavaDoc ) throw ( IOException JavaDoc ) ex;
1403                throw new ServletException JavaDoc( ex );
1404            }
1405            
1406            return null;
1407        }
1408        finally
1409        {
1410            setPerRequestState( prevState );
1411        }
1412    }
1413    
1414    /**
1415     * Add a property-related message that will be shown with the Errors and Error tags.
1416     *
1417     * @param propertyName the name of the property with which to associate this error.
1418     * @param messageKey the message-resources key for the message.
1419     * @param messageArgs zero or more arguments to the message.
1420     */

1421    protected void addActionError( String JavaDoc propertyName, String JavaDoc messageKey, Object JavaDoc[] messageArgs )
1422    {
1423        InternalUtils.addActionError( propertyName, new ActionMessage( messageKey, messageArgs ), getRequest() );
1424    }
1425    
1426    /**
1427     * Add a property-related message as an expression that will be evaluated and shown with the Errors and Error tags.
1428     *
1429     * @param propertyName the name of the property with which to associate this error.
1430     * @param expression the expression that will be evaluated to generate the error message.
1431     * @param messageArgs zero or more arguments to the message; may be expressions.
1432     */

1433    protected void addActionErrorExpression( String JavaDoc propertyName, String JavaDoc expression, Object JavaDoc[] messageArgs )
1434    {
1435        PageFlowUtils.addActionErrorExpression( getRequest(), propertyName, expression, messageArgs );
1436    }
1437    
1438    /**
1439     * Add a validation error that will be shown with the Errors and Error tags.
1440     * @deprecated Use {@link #addActionError} instead.
1441     *
1442     * @param propertyName the name of the property with which to associate this error.
1443     * @param messageKey the message-resources key for the error message.
1444     * @param messageArgs an array of arguments for the error message.
1445     */

1446    protected void addValidationError( String JavaDoc propertyName, String JavaDoc messageKey, Object JavaDoc[] messageArgs )
1447    {
1448        PageFlowUtils.addValidationError( propertyName, messageKey, messageArgs, getRequest() );
1449    }
1450    
1451    /**
1452     * Add a validation error that will be shown with the Errors and Error tags.
1453     * @deprecated Use {@link #addActionError} instead.
1454     *
1455     * @param propertyName the name of the property with which to associate this error.
1456     * @param messageKey the message-resources key for the error message.
1457     */

1458    protected void addValidationError( String JavaDoc propertyName, String JavaDoc messageKey )
1459    {
1460        PageFlowUtils.addValidationError( propertyName, messageKey, getRequest() );
1461    }
1462    
1463    private static ActionForward handleSimpleAction( PageFlowActionMapping mapping,
1464                                                     ActionForm wrappedFormBean,
1465                                                     HttpServletRequest JavaDoc request,
1466                                                     ServletContext JavaDoc servletContext )
1467    {
1468        
1469        Map JavaDoc/*< String, String >*/ conditionalForwards = mapping.getConditionalForwardsMap();
1470        
1471        if ( ! conditionalForwards.isEmpty() )
1472        {
1473            Object JavaDoc formBean = InternalUtils.unwrapFormBean( wrappedFormBean );
1474            
1475            for ( Iterator JavaDoc/*< Map.Entry< String, String > >*/ i = conditionalForwards.entrySet().iterator(); i.hasNext(); )
1476            {
1477                Map.Entry JavaDoc/*< String, String >*/ entry = ( Map.Entry JavaDoc ) i.next();
1478                String JavaDoc expression = ( String JavaDoc ) entry.getKey();
1479                String JavaDoc forwardName = ( String JavaDoc ) entry.getValue();
1480
1481                try
1482                {
1483                    if ( InternalExpressionUtils.evaluateCondition( expression, formBean, request, servletContext ) )
1484                    {
1485                        if ( _log.isTraceEnabled() )
1486                        {
1487                            _log.trace( "Expression '" + expression + "' evaluated to true on simple action "
1488                                        + mapping.getPath() + "; using forward " + forwardName + '.' );
1489                        }
1490
1491                        return new Forward( forwardName );
1492                    }
1493                }
1494                catch( Exception JavaDoc e ) // ELException
1495
{
1496                    if( _log.isErrorEnabled() )
1497                    {
1498                        _log.error( "Exception occurred evaluating navigation expression '" + expression
1499                                    + "'. Cause: " + e.getCause(), e);
1500                    }
1501                }
1502            }
1503        }
1504        
1505        
1506        String JavaDoc defaultForwardName = mapping.getDefaultForward();
1507        assert defaultForwardName != null : "defaultForwardName is null on Simple Action " + mapping.getPath();
1508        
1509        if ( _log.isTraceEnabled() )
1510        {
1511            _log.trace( "No expression evaluated to true on simple action " + mapping.getPath()
1512                        + "; using forward " + defaultForwardName + '.' );
1513        }
1514        
1515        return new Forward( defaultForwardName );
1516    }
1517    
1518    /**
1519     * Get the system default locale.
1520     *
1521     * @return the system default locale.
1522     */

1523    protected static Locale JavaDoc getDefaultLocale()
1524    {
1525        return defaultLocale;
1526    }
1527    
1528    /**
1529     * Return the default data source for the Struts module associated with this FlowController.
1530     *
1531     * @param request the current request.
1532     */

1533    protected DataSource JavaDoc getDataSource( HttpServletRequest JavaDoc request )
1534    {
1535        return getDataSource( request, Globals.DATA_SOURCE_KEY );
1536    }
1537
1538    /**
1539     * Return the specified data source for the current Struts module.
1540     *
1541     * @param request The servlet request we are processing
1542     * @param key The key specified in the
1543     * <code>&lt;message-resources&gt;</code> element for the
1544     * requested bundle
1545     */

1546    protected DataSource JavaDoc getDataSource( HttpServletRequest JavaDoc request, String JavaDoc key )
1547    {
1548        // Return the requested data source instance
1549
return ( DataSource JavaDoc ) getServletContext().getAttribute( key + getModuleConfig().getPrefix() );
1550    }
1551
1552
1553    /**
1554     * Return the user's currently selected Locale.
1555     *
1556     * @param request the current request.
1557     * @return the user's currently selected Locale, stored in the session.
1558     * @deprecated Use {@link #getLocale} or {@link #retrieveUserLocale}.
1559     */

1560    protected Locale JavaDoc getLocale( HttpServletRequest JavaDoc request )
1561    {
1562
1563        HttpSession JavaDoc session = request.getSession();
1564        Locale JavaDoc locale = ( Locale JavaDoc ) session.getAttribute( Globals.LOCALE_KEY );
1565        return locale != null ? locale : DEFAULT_LOCALE;
1566    }
1567
1568    /**
1569     * Get the user's currently selected Locale.
1570     *
1571     * @return the user's currently selected Locale, stored in the session.
1572     */

1573    protected Locale JavaDoc getLocale()
1574    {
1575        return retrieveUserLocale( getRequest(), null );
1576    }
1577
1578    public static Locale JavaDoc retrieveUserLocale( HttpServletRequest JavaDoc request, String JavaDoc locale )
1579    {
1580        if ( locale == null ) locale = Globals.LOCALE_KEY;
1581        HttpSession JavaDoc session = request.getSession( false );
1582        Locale JavaDoc userLocale = null;
1583        if ( session != null ) userLocale = ( Locale JavaDoc ) session.getAttribute( locale );
1584        if ( userLocale == null ) userLocale = DEFAULT_LOCALE;
1585        return userLocale;
1586    }
1587
1588
1589    /**
1590     * Return the message resources for the default module.
1591     *
1592     * @deprecated This method can only return the resources for the default
1593     * module. Use {@link #getMessageResources()} to get the
1594     * resources for this FlowController.
1595     */

1596    protected MessageResources getResources()
1597    {
1598        return ( MessageResources ) getServletContext().getAttribute( Globals.MESSAGES_KEY );
1599    }
1600
1601    /**
1602     * Return the default message resources for the current module.
1603     * @deprecated Use {@link #getMessageResources()} instead.
1604     *
1605     * @param request The servlet request we are processing
1606     */

1607    protected MessageResources getResources( HttpServletRequest JavaDoc request )
1608    {
1609        return getMessageResources();
1610    }
1611
1612
1613    /**
1614     * Return the specified message resources for the current module.
1615     * @deprecated Use {@link #getMessageResources(String)} instead.
1616     *
1617     * @param request the current request.
1618     * @param key The bundle key specified in a
1619     * {@link org.apache.beehive.netui.pageflow.annotations.Jpf.MessageBundle &#64;Jpf.MessageBundle} annotation.
1620     */

1621    protected MessageResources getResources( HttpServletRequest JavaDoc request, String JavaDoc key )
1622    {
1623        return getMessageResources( key );
1624    }
1625    
1626    /**
1627     * Get the default message resources for this FlowController.
1628     */

1629    protected MessageResources getMessageResources()
1630    {
1631        return getMessageResources( Globals.MESSAGES_KEY );
1632    }
1633    
1634    /**
1635     * Get the specified message resources for this FlowController.
1636     *
1637     * @param key The bundle key specified in a
1638     * {@link org.apache.beehive.netui.pageflow.annotations.Jpf.MessageBundle &#64;Jpf.MessageBundle} annotation.
1639     */

1640    protected MessageResources getMessageResources( String JavaDoc key )
1641    {
1642        return ( MessageResources ) getServletContext().getAttribute( key + getModuleConfig().getPrefix() );
1643    }
1644
1645    /**
1646     * <p>Returns <code>true</code> if the current form's cancel button was
1647     * pressed. This method will check if the <code>Globals.CANCEL_KEY</code>
1648     * request attribute has been set, which normally occurs if the cancel
1649     * button generated by the Struts <strong>CancelTag</strong> was pressed by the user
1650     * in the current request. If <code>true</code>, validation performed
1651     * by an <strong>ActionForm</strong>'s <code>validate()</code> method
1652     * will have been skipped by the controller servlet.</p>
1653     * @deprecated This method will be removed without replacement in a future release. The normal method for
1654     * cancelling in a form is to use the <code>action</code> attribute on
1655     * {@link org.apache.beehive.netui.tags.html.Button}, rather than avoiding validation on the current action.
1656     *
1657     * @param request The servlet request we are processing
1658     * @see org.apache.struts.taglib.html.CancelTag
1659     */

1660    protected boolean isCancelled( HttpServletRequest JavaDoc request )
1661    {
1662
1663        return request.getAttribute( Globals.CANCEL_KEY ) != null;
1664
1665    }
1666
1667    /**
1668     * Generate a new transaction token, to be used for enforcing a single request for a particular transaction.
1669     *
1670     * @param request the current request.
1671     * @deprecated Use {@link #generateToken()} instead.
1672     */

1673    protected String JavaDoc generateToken( HttpServletRequest JavaDoc request )
1674    {
1675        return TOKEN_PROCESSOR.generateToken( request );
1676    }
1677    
1678    /**
1679     * Generate a new transaction token, to be used for enforcing a single request for a particular transaction.
1680     *
1681     * @see #isTokenValid()
1682     * @see #isTokenValid(boolean)
1683     * @see #resetToken()
1684     */

1685    protected String JavaDoc generateToken()
1686    {
1687        return TOKEN_PROCESSOR.generateToken( getRequest() );
1688    }
1689    
1690    /**
1691     * Return <code>true</code> if there is a transaction token stored in
1692     * the user's current session, and the value submitted as a request
1693     * parameter with this action matches it. Returns <code>false</code>
1694     * under any of the following circumstances:
1695     * <ul>
1696     * <li>No session associated with this request</li>
1697     * <li>No transaction token saved in the session</li>
1698     * <li>No transaction token included as a request parameter</li>
1699     * <li>The included transaction token value does not match the
1700     * transaction token in the user's session</li>
1701     * </ul>
1702     * @deprecated Use {@link #isTokenValid()} instead.
1703     *
1704     * @param request The servlet request we are processing
1705     */

1706    protected boolean isTokenValid( HttpServletRequest JavaDoc request )
1707    {
1708        
1709        return TOKEN_PROCESSOR.isTokenValid( request, false );
1710        
1711    }
1712    
1713    /**
1714     * Return <code>true</code> if there is a transaction token stored in
1715     * the user's current session, and the value submitted as a request
1716     * parameter with this action matches it. Returns <code>false</code>
1717     * under any of the following circumstances:
1718     * <ul>
1719     * <li>No session associated with this request</li>
1720     * <li>No transaction token saved in the session</li>
1721     * <li>No transaction token included as a request parameter</li>
1722     * <li>The included transaction token value does not match the
1723     * transaction token in the user's session</li>
1724     * </ul>
1725     *
1726     * @see #generateToken()
1727     * @see #resetToken()
1728     */

1729    protected boolean isTokenValid()
1730    {
1731
1732        return TOKEN_PROCESSOR.isTokenValid( getRequest(), false );
1733
1734    }
1735
1736    /**
1737     * Return <code>true</code> if there is a transaction token stored in
1738     * the user's current session, and the value submitted as a request
1739     * parameter with this action matches it. Returns <code>false</code>
1740     * <ul>
1741     * <li>No session associated with this request</li>
1742     * <li>No transaction token saved in the session</li>
1743     * <li>No transaction token included as a request parameter</li>
1744     * <li>The included transaction token value does not match the
1745     * transaction token in the user's session</li>
1746     * </ul>
1747     * @deprecated Use {@link #isTokenValid(boolean)} instead.
1748     *
1749     * @param request The servlet request we are processing
1750     * @param reset Should we reset the token after checking it?
1751     */

1752    protected boolean isTokenValid( HttpServletRequest JavaDoc request, boolean reset )
1753    {
1754        return TOKEN_PROCESSOR.isTokenValid( request, reset );
1755    }
1756    
1757    /**
1758     * Return <code>true</code> if there is a transaction token stored in
1759     * the user's current session, and the value submitted as a request
1760     * parameter with this action matches it. Returns <code>false</code>
1761     * <ul>
1762     * <li>No session associated with this request</li>
1763     * <li>No transaction token saved in the session</li>
1764     * <li>No transaction token included as a request parameter</li>
1765     * <li>The included transaction token value does not match the
1766     * transaction token in the user's session</li>
1767     * </ul>
1768     *
1769     * @param reset Should we reset the token after checking it?
1770     * @see #generateToken()
1771     * @see #resetToken()
1772     */

1773    protected boolean isTokenValid( boolean reset )
1774    {
1775
1776        return TOKEN_PROCESSOR.isTokenValid( getRequest(), reset );
1777    }
1778
1779
1780    /**
1781     * Reset the saved transaction token in the user's session. This
1782     * indicates that transactional token checking will not be needed
1783     * on the next request that is submitted.
1784     * @deprecated Use {@link #resetToken()} instead.
1785     *
1786     * @param request The servlet request we are processing
1787     */

1788    protected void resetToken( HttpServletRequest JavaDoc request )
1789    {
1790        TOKEN_PROCESSOR.resetToken( request );
1791    }
1792    
1793    /**
1794     * Reset the saved transaction token in the user's session. This
1795     * indicates that transactional token checking will not be needed
1796     * on the next request that is submitted.
1797     *
1798     * @see #isTokenValid()
1799     * @see #isTokenValid(boolean)
1800     * @see #generateToken()
1801     */

1802    protected void resetToken()
1803    {
1804        TOKEN_PROCESSOR.resetToken( getRequest() );
1805    }
1806
1807
1808    /**
1809     * Save the specified messages keys into the request for use by the &lt;netui:error&gt; or &lt;netui:errors&gt; tags.
1810     * @deprecated Use {@link #saveActionErrors} instead.
1811     *
1812     * @param errors the ActionMessages to save in the request.
1813     */

1814    protected void saveErrors( HttpServletRequest JavaDoc request, ActionMessages errors )
1815    {
1816        saveActionErrors( errors );
1817    }
1818
1819
1820    /**
1821     * Save the specified messages keys into the appropriate request
1822     * attribute for use by the Struts &lt;html:messages&gt; tag (if
1823     * messages="true" is set), if any messages are required. Otherwise,
1824     * ensure that the request attribute is not created.
1825     * @deprecated This method will be removed without replacement in a future release.
1826     *
1827     * @param request The servlet request we are processing
1828     * @param messages Messages object
1829     */

1830    protected void saveMessages( HttpServletRequest JavaDoc request, ActionMessages messages )
1831    {
1832        
1833        // Remove any messages attribute if none are required
1834
if ( messages == null || messages.isEmpty() )
1835        {
1836            request.removeAttribute( Globals.MESSAGE_KEY );
1837            return;
1838        }
1839        
1840        // Save the messages we need
1841
request.setAttribute( Globals.MESSAGE_KEY, messages );
1842        
1843    }
1844    
1845    /**
1846     * Save the specified messages keys into the request for use by the &lt;netui:error&gt; or &lt;netui:errors&gt; tags.
1847     *
1848     * @param errors the ActionMessages to save in the request.
1849     */

1850    protected void saveActionErrors( ActionMessages errors )
1851    {
1852        // Remove any messages attribute if none are required
1853
if ( errors == null || errors.isEmpty() )
1854        {
1855            getRequest().removeAttribute( Globals.MESSAGE_KEY );
1856        }
1857        else
1858        {
1859            getRequest().setAttribute( Globals.MESSAGE_KEY, errors );
1860        }
1861    }
1862
1863
1864    /**
1865     * Save a new transaction token in the user's current session, creating
1866     * a new session if necessary.
1867     *
1868     * @param request The servlet request we are processing
1869     */

1870    protected void saveToken( HttpServletRequest JavaDoc request )
1871    {
1872        TOKEN_PROCESSOR.saveToken( request );
1873    }
1874
1875
1876    /**
1877     * Set the user's currently selected Locale.
1878     *
1879     * @param request The request we are processing
1880     * @param locale The user's selected Locale to be set, or null
1881     * to select the server's default Locale
1882     * @deprecated Use {@link #setLocale(Locale)}.
1883     */

1884    protected void setLocale( HttpServletRequest JavaDoc request, Locale JavaDoc locale )
1885    {
1886
1887        HttpSession JavaDoc session = request.getSession();
1888        if ( locale == null )
1889        {
1890            locale = getDefaultLocale();
1891        }
1892        session.setAttribute( Globals.LOCALE_KEY, locale );
1893
1894    }
1895
1896    /**
1897     * Set the user's currently selected Locale.
1898     *
1899     * @param locale The user's selected Locale to be set, or null to select the server's default Locale
1900     * @deprecated Use {@link #setLocale(Locale)}.
1901     */

1902    protected void setLocale( Locale JavaDoc locale )
1903    {
1904        if ( locale == null ) locale = getDefaultLocale();
1905        getSession().setAttribute( Globals.LOCALE_KEY, locale );
1906    }
1907    
1908    /**
1909     * Get the flow-scoped form bean member associated with the given ActionMapping. This is a framework-invoked
1910     * method that should not normally be called directly.
1911     */

1912    public ActionForm getFormBean( ActionMapping mapping )
1913    {
1914        if ( mapping instanceof PageFlowActionMapping )
1915        {
1916            PageFlowActionMapping pfam = ( PageFlowActionMapping ) mapping;
1917            String JavaDoc formMember = pfam.getFormMember();
1918            
1919            try
1920            {
1921                if ( formMember != null )
1922                {
1923                    Field JavaDoc field = getClass().getDeclaredField( formMember );
1924                    field.setAccessible( true );
1925                    return InternalUtils.wrapFormBean( field.get( this ) );
1926                }
1927            }
1928            catch ( Exception JavaDoc e )
1929            {
1930                _log.error( "Could not use member field " + formMember + " as the form bean.", e );
1931            }
1932        }
1933        
1934        return null;
1935    }
1936    
1937    PageFlowRequestProcessor getRequestProcessor()
1938    {
1939        ModuleConfig mc = getModuleConfig();
1940        String JavaDoc key = Globals.REQUEST_PROCESSOR_KEY + mc.getPrefix();
1941        RequestProcessor rp = ( RequestProcessor ) getServletContext().getAttribute( key );
1942        
1943        //
1944
// The RequestProcessor may not have been initialized -- if so, just return a new (temporary) one.
1945
//
1946
if ( rp == null )
1947        {
1948            try
1949            {
1950                ControllerConfig cc = mc.getControllerConfig();
1951                rp = ( RequestProcessor ) RequestUtils.applicationInstance( cc.getProcessorClass() );
1952                rp.init( InternalUtils.getActionServlet( getServletContext() ), mc );
1953            }
1954            catch ( Exception JavaDoc e )
1955            {
1956                _log.error( "Could not initialize request processor for module " + mc.getPrefix(), e );
1957            }
1958        }
1959        
1960        assert rp == null || rp instanceof PageFlowRequestProcessor : rp.getClass().getName();
1961        return ( PageFlowRequestProcessor ) rp;
1962    }
1963
1964    /**
1965     * Create a raw action URI, which can be modified before being sent through the registered URL rewriting chain
1966     * using {@link org.apache.beehive.netui.core.urls.URLRewriterService#rewriteURL}.
1967     *
1968     * @param actionName the action name to convert into a MutableURI; may be qualified with a path from the webapp
1969     * root, in which case the parent directory from the current request is <i>not</i> used.
1970     * @return a MutableURI for the given action, suitable for URL rewriting.
1971     * @throws URISyntaxException if there is a problem converting the action URI (derived
1972     * from processing the given action name) into a MutableURI.
1973     * @throws IllegalStateException if this method is invoked outside of action method
1974     * execution (i.e., outside of the call to {@link FlowController#execute},
1975     * and outside of {@link FlowController#onCreate},
1976     * {@link FlowController#beforeAction}, {@link FlowController#afterAction}.
1977     */

1978    public MutableURI getActionURI( String JavaDoc actionName )
1979            throws URISyntaxException JavaDoc
1980    {
1981        if ( _perRequestState == null )
1982        {
1983            throw new IllegalStateException JavaDoc( "getActionURI was called outside of a valid context." );
1984        }
1985        ServletContext JavaDoc servletContext = getServletContext();
1986        HttpServletRequest JavaDoc request = getRequest();
1987        HttpServletResponse JavaDoc response = getResponse();
1988
1989        return PageFlowUtils.getActionURI( servletContext, request, response, actionName );
1990    }
1991
1992    /**
1993     * Create a fully-rewritten URI given an action and parameters.
1994     *
1995     * @param actionName the action name to convert into a fully-rewritten URI; may be qualified with a path from the
1996     * webapp root, in which case the parent directory from the current request is <i>not</i> used.
1997     * @param parameters the additional parameters to include in the URI query.
1998     * @param asValidXml flag indicating that the query of the uri should be written
1999     * using the &quot;&amp;amp;&quot; entity, rather than the character, '&amp;'
2000     * @return a fully-rewritten URI for the given action.
2001     * @throws URISyntaxException if there is a problem converting the action url (derived
2002     * from processing the given action name) into a URI.
2003     * @throws IllegalStateException if this method is invoked outside of action method
2004     * execution (i.e., outside of the call to {@link FlowController#execute},
2005     * and outside of {@link FlowController#onCreate},
2006     * {@link FlowController#beforeAction}, {@link FlowController#afterAction}.
2007     */

2008    public String JavaDoc getRewrittenActionURI( String JavaDoc actionName, Map JavaDoc parameters, boolean asValidXml )
2009            throws URISyntaxException JavaDoc
2010    {
2011        if ( _perRequestState == null )
2012        {
2013            throw new IllegalStateException JavaDoc( "getRewrittenActionURI was called outside of a valid context." );
2014        }
2015        ServletContext JavaDoc servletContext = getServletContext();
2016        HttpServletRequest JavaDoc request = getRequest();
2017        HttpServletResponse JavaDoc response = getResponse();
2018
2019        return PageFlowUtils.getRewrittenActionURI( servletContext, request, response,
2020                                                    actionName, parameters, null, asValidXml );
2021    }
2022    
2023    FlowControllerHandlerContext getHandlerContext()
2024    {
2025        return new FlowControllerHandlerContext( getRequest(), getResponse(), this );
2026    }
2027}
2028
Popular Tags