KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > apache > beehive > netui > pageflow > internal > DefaultActionForwardHandler


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.internal;
19
20 import org.apache.beehive.netui.util.internal.InternalStringBuilder;
21
22 import org.apache.struts.action.ActionForward;
23 import org.apache.struts.action.ActionMapping;
24 import org.apache.struts.action.ActionForm;
25 import org.apache.struts.config.ModuleConfig;
26
27 import org.apache.beehive.netui.pageflow.interceptor.action.ActionInterceptor;
28 import org.apache.beehive.netui.pageflow.interceptor.action.AfterNestedInterceptContext;
29 import org.apache.beehive.netui.pageflow.interceptor.action.InterceptorForward;
30 import org.apache.beehive.netui.pageflow.interceptor.InterceptorException;
31 import org.apache.beehive.netui.pageflow.*;
32 import org.apache.beehive.netui.pageflow.handler.FlowControllerHandlerContext;
33 import org.apache.beehive.netui.pageflow.handler.ActionForwardHandler;
34 import org.apache.beehive.netui.util.logging.Logger;
35 import org.apache.beehive.netui.script.common.ImplicitObjectUtil;
36
37
38 import javax.servlet.http.HttpServletRequest JavaDoc;
39 import javax.servlet.http.HttpServletResponse JavaDoc;
40 import javax.servlet.ServletContext JavaDoc;
41
42 public class DefaultActionForwardHandler
43         extends DefaultHandler
44         implements ActionForwardHandler
45 {
46     private static final Logger _log = Logger.getInstance( DefaultActionForwardHandler.class );
47
48     public DefaultActionForwardHandler( ServletContext JavaDoc servletContext )
49     {
50         init( null, null, servletContext );
51     }
52
53     /**
54      * Perform any necessary updates to the request and user session (including updates to the
55      * PageFlowController stack), based on the given ActionForward.
56      *
57      * @param context the current FlowControllerHandlerContext.
58      * @param fwd the Struts ActionForward that determines the next URI to be displayed.
59      * @param mapping the Struts ActionMapping for the current action being processed.
60      * @param actionName the name of the Struts action being processed.
61      * @param altModuleConfig an alternate module config (e.g., Global.app's ModuleConfig) from which to
62      * resolve a forward if it can't be resolved from the given ActionMapping.
63      * @return the ActionForward object to pass to Struts for actual Servlet forwarding.
64      */

65     public ActionForward doForward( FlowControllerHandlerContext context, ActionForward fwd, ActionMapping mapping,
66                                     String JavaDoc actionName, ModuleConfig altModuleConfig, ActionForm form )
67     {
68         boolean isSpecialForward = false;
69         boolean isReturnToCurrentPage = false;
70         assert context.getRequest() instanceof HttpServletRequest JavaDoc : "don't support ServletRequest currently.";
71         HttpServletRequest JavaDoc request = ( HttpServletRequest JavaDoc ) context.getRequest();
72         FlowController flowController = context.getFlowController();
73         
74         //
75
// There is a special forward ("auto"), which signals us to render using a registered ViewRenderer.
76
// This is used as part of popup window support.
77
//
78
if ( fwd != null && PageFlowConstants.AUTO_VIEW_RENDER_FORWARD_NAME.equals( fwd.getName() ) )
79         {
80             return getRegisteredActionForwardHandler().doAutoViewRender( context, mapping, form );
81         }
82         
83         if ( fwd != null && fwd instanceof Forward )
84         {
85             Forward pageFlowFwd = ( Forward ) fwd;
86
87             pageFlowFwd.initialize( mapping, flowController, request );
88             pageFlowFwd.setAlternateModuleConfig( altModuleConfig );
89
90             if ( ! pageFlowFwd.doesResolve() )
91             {
92                 PageFlowException ex =
93                         new UnresolvableForwardException( pageFlowFwd.getName(), actionName, flowController );
94                 InternalUtils.throwPageFlowException( ex, request );
95             }
96
97             //
98
// If it's a return-to-page, do what's necessary to return to the previous page,
99
// with its state intact.
100
//
101
if ( pageFlowFwd.isReturnToPage() )
102             {
103                 isSpecialForward = true;
104                 
105                 //
106
// We need access to _previousPageInfo from the *current PageFlow*. That is
107
// most likely this FlowController, but if it's Global.app, then we don't want
108
// to use that.
109
//
110
PageFlowController curJpf = PageFlowUtils.getCurrentPageFlow( request );
111                 
112                 if ( curJpf == null )
113                 {
114                     PageFlowException ex = new NoCurrentPageFlowException( actionName, pageFlowFwd );
115                     InternalUtils.throwPageFlowException( ex, request );
116                     assert false; // throwPageFlowException() must throw.
117
}
118                 
119                 PreviousPageInfo prevPageInfo;
120                 
121                 switch ( pageFlowFwd.getReturnToType() )
122                 {
123                     case Forward.RETURN_TO_CURRENT_PAGE:
124                         prevPageInfo = curJpf.getCurrentPageInfo();
125                         isReturnToCurrentPage = true;
126                         break;
127                         
128                     case Forward.RETURN_TO_PREVIOUS_PAGE:
129                         prevPageInfo = curJpf.getPreviousPageInfo();
130                         break;
131                     
132                     case Forward.RETURN_TO_PAGE:
133                         prevPageInfo = flowController.getPreviousPageInfoLegacy( curJpf, request );
134                         break;
135                     
136                     default:
137                         assert false : pageFlowFwd.getReturnToType();
138                         prevPageInfo = curJpf.getCurrentPageInfo();
139                 }
140                 
141                 fwd =
142                   getRegisteredActionForwardHandler().doReturnToPage( context, prevPageInfo, curJpf, form, actionName, pageFlowFwd );
143                 
144                 if ( prevPageInfo != null )
145                 {
146                     mapping = prevPageInfo.getMapping();
147                     if ( form == null ) form = prevPageInfo.getForm();
148                 }
149                 
150                 if ( _log.isDebugEnabled() )
151                 {
152                     _log.debug( "return-to-page: " + ( fwd != null ? fwd.getPath() : "[null]" ) );
153                 }
154             }
155             else if ( pageFlowFwd.isReturnToAction() )
156             {
157                 isSpecialForward = true;
158                 fwd = getRegisteredActionForwardHandler().doReturnToAction( context, actionName, pageFlowFwd );
159             }
160             
161             //
162
// See if we should pop the current PageFlowController (done nesting).
163
//
164
if ( pageFlowFwd.isNestedReturn() )
165             {
166                 isSpecialForward = true;
167                 fwd = getRegisteredActionForwardHandler().doNestingReturn( context, pageFlowFwd, mapping, form );
168             }
169
170             //
171
// Set ActionForms specified in the Forward. Note that this overwrites any forms restored
172
// during return-to="page".
173
//
174
PageFlowUtils.setOutputForms( mapping, pageFlowFwd, request );
175             InternalUtils.addActionOutputs( pageFlowFwd.getActionOutputs() , request, true );
176         }
177
178         if ( fwd != null )
179         {
180             if ( _log.isDebugEnabled() )
181             {
182                 if ( fwd.getRedirect() )
183                 {
184                     _log.debug( "Redirecting to " + fwd.getPath() );
185                 }
186                 else
187                 {
188                     _log.debug( "Forwarding to " + fwd.getPath() );
189                 }
190             }
191         }
192         else
193         {
194             _log.debug( "null ActionForward -- not doing any forward or redirect." );
195         }
196         
197         //
198
// Save info on this forward for return-to="currentPage" or return-to="previousPage". But, don't save
199
// the info if the current forward is a return-to="currentPage" -- we don't want this to turn into
200
// the page that's seen for *both* return-to="currentPage" and return-to="previousPage".
201
//
202
if ( ! isReturnToCurrentPage )
203         {
204             flowController.savePreviousPageInfo( fwd, form, mapping, request, getServletContext(), isSpecialForward );
205         }
206         
207         return fwd;
208     }
209     
210     public ActionForward doAutoViewRender( FlowControllerHandlerContext context, ActionMapping mapping, ActionForm form )
211     {
212         assert context.getRequest() instanceof HttpServletRequest JavaDoc : "don't support ServletRequest currently.";
213         assert context.getResponse() instanceof HttpServletResponse JavaDoc : "don't support ServletResponse currently.";
214         HttpServletRequest JavaDoc request = ( HttpServletRequest JavaDoc ) context.getRequest();
215         HttpServletResponse JavaDoc response = ( HttpServletResponse JavaDoc ) context.getResponse();
216         ViewRenderer vr = PageFlowRequestWrapper.get( request ).getViewRenderer();
217         
218         if ( vr != null )
219         {
220             _log.debug( "null ActionForward -- delegating to ViewRenderer " + vr + " to handle response." );
221             
222             try
223             {
224                 vr.renderView( request, response, getServletContext() );
225             }
226             catch ( Throwable JavaDoc th )
227             {
228                 try
229                 {
230                     return context.getFlowController().handleException( th, mapping, form, request, response );
231                 }
232                 catch ( Exception JavaDoc e )
233                 {
234                     _log.error( "Exception thrown while handling exception in ViewRenderer " + vr + ": "
235                                 + e.getMessage(), th );
236                 }
237             }
238             
239         }
240         else
241         {
242             _log.error( "Auto-render forward " + PageFlowConstants.AUTO_VIEW_RENDER_FORWARD_NAME
243                         + " used, but no ViewRenderer " + "was registered -- not doing any forward or redirect." );
244         }
245         
246         return null;
247     }
248     
249     /**
250      * Get an ActionForward to the original page that was visible before the previous action.
251      */

252     public ActionForward doReturnToPage( FlowControllerHandlerContext context, PreviousPageInfo prevPageInfo,
253                                          PageFlowController currentPageFlow, ActionForm currentForm,
254                                          String JavaDoc actionName, Forward pageFlowFwd )
255     {
256         assert context.getRequest() instanceof HttpServletRequest JavaDoc : "don't support ServletRequest currently.";
257         HttpServletRequest JavaDoc request = ( HttpServletRequest JavaDoc ) context.getRequest();
258         
259         if ( prevPageInfo == null )
260         {
261             if ( _log.isInfoEnabled() )
262             {
263                 _log.info( "Attempted return-to-page, but previous page info was missing." );
264             }
265         
266             PageFlowException ex = new NoPreviousPageException( actionName, pageFlowFwd, currentPageFlow );
267             InternalUtils.throwPageFlowException( ex, request );
268         }
269         
270         //
271
// Figure out what URI to return to, and set the original form in the request or session.
272
//
273
ActionForward retFwd = prevPageInfo.getForward();
274         ActionMapping prevMapping = prevPageInfo.getMapping();
275         
276         //
277
// Restore any forms that are specified by this Forward (overwrite the original forms).
278
//
279
if ( retFwd instanceof Forward )
280         {
281             PageFlowUtils.setOutputForms( prevMapping, ( Forward ) retFwd, request, false );
282             InternalUtils.addActionOutputs( ( ( Forward ) retFwd ).getActionOutputs(), request, false );
283         }
284         
285         //
286
// If the user hit the previous page directly (without going through an action), prevMapping will be null.
287
//
288
if ( prevMapping != null )
289         {
290             //
291
// If the currently-posted form is of the right type, initialize the page with that (but we don't overwrite
292
// the form that was set above).
293
//
294
if ( currentForm != null ) PageFlowUtils.setOutputForm( prevMapping, currentForm, request, false );
295         
296             //
297
// Initialize the page with the original form it got forwarded (but we don't overwrite the form that was
298
// set above).
299
//
300
InternalUtils.setFormInScope( prevMapping.getName(), prevPageInfo.getForm(), prevMapping, request, false );
301         }
302             
303         //
304
// If we're forwarding to a page in a different pageflow, we need to make sure the returned ActionForward has
305
// the right module path, and that it has contextRelative=true.
306
//
307
FlowController flowController = context.getFlowController();
308         
309         if ( ! retFwd.getContextRelative() && flowController != currentPageFlow )
310         {
311
312             retFwd = new ActionForward( retFwd.getName(),
313                                         currentPageFlow.getModulePath() + retFwd.getPath(),
314                                         retFwd.getRedirect(),
315                                         true );
316
317         }
318         
319         if ( _log.isDebugEnabled() )
320         {
321             _log.debug( "Return-to-page in PageFlowController " + flowController.getClass().getName()
322                        + ": original URI " + retFwd.getPath() );
323         }
324         
325         if ( retFwd != null )
326         {
327             //
328
// If the new (return-to) Forward specifies a redirect value explicitly, use that; otherwise
329
// use the redirect value from the original Forward.
330
//
331
if ( pageFlowFwd.hasExplicitRedirectValue() ) retFwd.setRedirect( pageFlowFwd.getRedirect() );
332             
333             //
334
// If there's a query string, override the previous query string.
335
//
336
String JavaDoc fwdPath = retFwd.getPath();
337             String JavaDoc newQueryString = pageFlowFwd.getQueryString();
338             int existingQueryPos = fwdPath.indexOf( '?' );
339             
340             //
341
// If the new Forward (the one with Jpf.NavigateTo.currentPage/previousPage) has a query string, use that.
342
// Otherwise, if the old Forward has no query string, restore the one from the PreviousPageInfo if
343
// appropriate.
344
//
345
if ( newQueryString != null )
346             {
347                 // Chop off the old query string if necessary.
348
if ( existingQueryPos != -1 ) fwdPath = fwdPath.substring( 0, existingQueryPos );
349                 retFwd.setPath( fwdPath + newQueryString );
350             }
351             else if ( existingQueryPos == -1 )
352             {
353                 retFwd.setPath( fwdPath + getQueryString( pageFlowFwd, prevPageInfo ) );
354             }
355         }
356         
357         PageFlowRequestWrapper.get( request ).setPreviousPageInfo( prevPageInfo );
358         return retFwd;
359     }
360     
361     public ActionForward doReturnToAction( FlowControllerHandlerContext context, String JavaDoc actionName, Forward pageFlowFwd )
362     {
363         assert context.getRequest() instanceof HttpServletRequest JavaDoc : "don't support ServletRequest currently.";
364         HttpServletRequest JavaDoc request = ( HttpServletRequest JavaDoc ) context.getRequest();
365         
366         //
367
// We need access to _previousPageInfo from the *current PageFlow*. That is
368
// most likely this FlowController, but if it's Global.app, then we don't want
369
// to use that.
370
//
371
PageFlowController curJpf = PageFlowUtils.getCurrentPageFlow( request );
372         
373         if ( curJpf == null )
374         {
375             PageFlowException ex = new NoCurrentPageFlowException( actionName, pageFlowFwd );
376             InternalUtils.throwPageFlowException( ex, request );
377             assert false; // throwPageFlowException() must throw.
378
}
379                         
380         PreviousActionInfo prevActionInfo = curJpf.getPreviousActionInfo();
381         
382         if ( prevActionInfo != null )
383         {
384             String JavaDoc actionURI = prevActionInfo.getActionURI();
385             
386             if ( _log.isDebugEnabled() ) _log.debug( "return-to-action: " + actionURI );
387
388             //
389
// If there's no form specified in this return-to-action forward, then use the original form that was saved
390
// in the action. Only do this if we're not doing a redirect, which precludes request attributes.
391
//
392
if ( ! pageFlowFwd.isRedirect() && prevActionInfo.getForm() != null
393                  && pageFlowFwd.getFirstOutputForm( request ) == null )
394             {
395                 pageFlowFwd.addOutputForm( prevActionInfo.getForm() );
396             }
397             
398             String JavaDoc query = getQueryString( pageFlowFwd, prevActionInfo );
399             ActionForward fwd = new ActionForward( actionURI + query, pageFlowFwd.getRedirect() );
400             fwd.setContextRelative( true );
401             return fwd;
402         }
403         else
404         {
405             if ( _log.isInfoEnabled() )
406             {
407                 _log.info( "Attempted return-to-action, but previous action info was missing." );
408             }
409             
410             PageFlowException ex = new NoPreviousActionException( actionName, pageFlowFwd, curJpf );
411             InternalUtils.throwPageFlowException( ex, request );
412             assert false; // previous method always throws
413
return null;
414         }
415     }
416     
417     private static String JavaDoc getQueryString( Forward pageFlowFwd, PreviousInfo previousInfo )
418     {
419         String JavaDoc query = pageFlowFwd.getQueryString();
420         if ( query == null ) query = "";
421             
422         //
423
// If the restoreQueryString attribute was set, use the query string from the original action URI.
424
//
425
boolean restoreQueryString = pageFlowFwd.doesRestoreQueryString();
426         if ( restoreQueryString )
427         {
428             String JavaDoc prevQuery = previousInfo.getQueryString();
429             if ( prevQuery != null ) query += ( query.length() > 0 ? "&" : "?" ) + prevQuery;
430         }
431         
432         return query;
433     }
434     
435     public ActionForward doNestingReturn( FlowControllerHandlerContext context, Forward pageFlowFwd,
436                                           ActionMapping mapping, ActionForm form )
437     {
438         assert context.getRequest() instanceof HttpServletRequest JavaDoc : "don't support ServletRequest currently.";
439         assert context.getResponse() instanceof HttpServletResponse JavaDoc : "don't support ServletResponse currently.";
440         HttpServletRequest JavaDoc request = ( HttpServletRequest JavaDoc ) context.getRequest();
441         HttpServletResponse JavaDoc response = ( HttpServletResponse JavaDoc ) context.getResponse();
442         
443         PageFlowStack pfStack = PageFlowStack.get( request );
444         String JavaDoc returnAction = pageFlowFwd.getPath();
445                 
446         if ( pfStack.isEmpty() )
447         {
448             PageFlowController curJpf = PageFlowUtils.getCurrentPageFlow( request );
449                     
450             if ( _log.isInfoEnabled() )
451             {
452                 _log.info( "Tried to pop from empty PageFlow stack. Current = "
453                            + curJpf.getClass().getName() );
454             }
455                     
456             if ( _log.isWarnEnabled() )
457             {
458                 InternalStringBuilder msg = new InternalStringBuilder( "Tried to pop from empty PageFlow stack." );
459                 msg.append( " Current page flow is " );
460                 msg.append( curJpf != null ? curJpf.getClass().getName() : null );
461                 _log.warn( msg.append( '.' ).toString() );
462             }
463                     
464             PageFlowException ex = new EmptyNestingStackException( returnAction, curJpf );
465             InternalUtils.throwPageFlowException( ex, request );
466         }
467                 
468         // Only nested PageFlowControllers can have return actions.
469
assert context.getFlowController() instanceof PageFlowController
470                 : context.getFlowController().getClass().getName() + " is not a " + PageFlowController.class.getName();
471         ActionForward exceptionFwd =
472                 ( ( PageFlowController ) context.getFlowController() ).exitNesting( request, response, mapping, form );
473         if ( exceptionFwd != null ) return exceptionFwd;
474                 
475         PageFlowStack.PushedPageFlow pushedPageFlowWrapper = pfStack.pop( request );
476         PageFlowController poppedPageFlow = pushedPageFlowWrapper.getPageFlow();
477
478         if ( _log.isDebugEnabled() )
479         {
480             _log.debug( "Popped PageFlowController " + poppedPageFlow + " from the nesting stack" );
481         }
482
483         InternalUtils.setCurrentPageFlow( poppedPageFlow, request );
484
485                 
486         //
487
// If an ActionInterceptor forwarded to the nested page flow, give it a chance to change the URI as the nested
488
// flow is returning. If it doesn't, we'll go to the originally-intended Forward.
489
//
490
ActionInterceptor interceptor = pushedPageFlowWrapper.getInterceptor();
491                 
492         if ( interceptor != null )
493         {
494             return getRegisteredActionForwardHandler().handleInterceptorReturn( context, poppedPageFlow,
495                                                                                 pushedPageFlowWrapper, returnAction,
496                                                                                 mapping, form, interceptor );
497         }
498
499         //
500
// Raise the returned action on the popped pageflow.
501
//
502
assert returnAction.charAt( 0 ) != '/' : returnAction;
503
504         if ( _log.isDebugEnabled() )
505         {
506             _log.debug( "Action on popped PageFlowController is " + returnAction );
507         }
508
509         InternalStringBuilder returnActionPath = new InternalStringBuilder( poppedPageFlow.getModulePath() );
510         returnActionPath.append( '/' ).append( returnAction ).append( PageFlowConstants.ACTION_EXTENSION );
511
512         //
513
// Store the returned form in the request.
514
//
515
ActionForm retForm = pageFlowFwd.getFirstOutputForm( request );
516         if ( retForm != null )
517         {
518             InternalUtils.setForwardedFormBean( request, retForm );
519             ImplicitObjectUtil.loadOutputFormBean( request, InternalUtils.unwrapFormBean( retForm ) );
520         }
521                 
522         // TODO: delete this deprecated feature (following line). This is the Jpf.NavigateTo.page value.
523
request.setAttribute( InternalConstants.RETURNING_FROM_NESTING_ATTR, Boolean.TRUE );
524         
525         //
526
// Forward to the return-action on the nesting page flow.
527
//
528
ActionForward fwd = new ActionForward( returnActionPath.toString(), false );
529         fwd.setContextRelative( true );
530         return fwd;
531     }
532     
533     public ActionForward handleInterceptorReturn( FlowControllerHandlerContext context,
534                                                   PageFlowController poppedPageFlow,
535                                                   PageFlowStack.PushedPageFlow pushedPageFlowWrapper,
536                                                   String JavaDoc returnAction, ActionMapping actionMapping,
537                                                   ActionForm form, ActionInterceptor interceptor )
538     {
539         assert context.getRequest() instanceof HttpServletRequest JavaDoc : "don't support ServletRequest currently.";
540         assert context.getResponse() instanceof HttpServletResponse JavaDoc : "don't support ServletResponse currently.";
541         HttpServletRequest JavaDoc request = ( HttpServletRequest JavaDoc ) context.getRequest();
542         HttpServletResponse JavaDoc response = ( HttpServletResponse JavaDoc ) context.getResponse();
543         
544         PageFlowRequestWrapper.get( request ).setReturningFromActionIntercept( true );
545         
546         try
547         {
548             AfterNestedInterceptContext interceptorContext =
549                     new AfterNestedInterceptContext( request, response, getServletContext(), poppedPageFlow,
550                                                      pushedPageFlowWrapper.getInterceptedForward(),
551                                                      pushedPageFlowWrapper.getInterceptedActionName(),
552                                                      returnAction );
553             
554             interceptor.afterNestedIntercept( interceptorContext );
555             
556             if ( interceptorContext.hasInterceptorForward() )
557             {
558                 InterceptorForward fwd = interceptorContext.getInterceptorForward();
559                 
560                 if ( _log.isDebugEnabled() )
561                 {
562                     InternalStringBuilder message = new InternalStringBuilder();
563                     message.append( "Interceptor " );
564                     message.append( interceptor.getClass().getName() );
565                     message.append( " after nested page flow: " );
566                     
567                     if ( fwd != null )
568                     {
569                         message.append( "forwarding to " );
570                         message.append( fwd.getPath() );
571                     }
572                     else
573                     {
574                         message.append( "returned InterceptorForward is null." );
575                     }
576                     
577                     _log.debug( message.toString() );
578                 }
579                 
580                 if ( fwd != null ) fwd.rehydrateRequest( request );
581                 return fwd;
582             }
583         }
584         catch ( InterceptorException e )
585         {
586             _log.error( "Exception in " + interceptor.getClass().getName() + ".afterNestedIntercept", e );
587             
588             try
589             {
590                 return poppedPageFlow.handleException( e, actionMapping, form, request, response );
591             }
592             catch ( Exception JavaDoc anotherException )
593             {
594                 _log.error( "Exception thrown while handling exception.", anotherException );
595             }
596         }
597         
598         //
599
// The interceptor declined to forward us anywhere -- just go to the originally-intended Forward.
600
//
601
return pushedPageFlowWrapper.getInterceptedForward();
602     }
603     
604     public ActionForwardHandler getRegisteredActionForwardHandler()
605     {
606         return ( ActionForwardHandler ) super.getRegisteredHandler();
607     }
608 }
609
Popular Tags