KickJava   Java API By Example, From Geeks To Geeks.

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


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

18 package org.apache.beehive.netui.pageflow;
19
20 import org.apache.beehive.netui.util.internal.InternalStringBuilder;
21
22 import org.apache.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 javax.servlet.http.HttpServletRequest JavaDoc;
28 import javax.servlet.ServletContext JavaDoc;
29 import javax.servlet.ServletRequest JavaDoc;
30 import java.util.List JavaDoc;
31 import java.util.ArrayList JavaDoc;
32 import java.util.Map JavaDoc;
33 import java.util.HashMap JavaDoc;
34 import java.lang.reflect.Field JavaDoc;
35 import java.net.URI JavaDoc;
36 import java.net.URL JavaDoc;
37
38 import org.apache.beehive.netui.util.logging.Logger;
39 import org.apache.beehive.netui.util.internal.FileUtils;
40 import org.apache.beehive.netui.pageflow.config.PageFlowActionForward;
41 import org.apache.beehive.netui.pageflow.internal.InternalUtils;
42 import org.apache.beehive.netui.pageflow.internal.AdapterManager;
43 import org.apache.beehive.netui.pageflow.handler.ReloadableClassHandler;
44 import org.apache.beehive.netui.pageflow.handler.Handlers;
45
46
47 /**
48  * An object of this type is returned from an action methods in a {@link PageFlowController} to
49  * determine the next URI to be displayed. It is constructed on the name of a forward defined
50  * by the @{@link org.apache.beehive.netui.pageflow.annotations.Jpf.Forward @Jpf.Forward} annotation, and resolves to the URI
51  * specified in that forward.
52  */

53 public class Forward extends ActionForward
54 {
55     private static final ActionForm[] EMPTY_ACTION_FORM_ARRAY = new ActionForm[0];
56     
57     public static final int RETURN_TO_NONE = 0;
58     public static final int RETURN_TO_CURRENT_PAGE = 1;
59     public static final int RETURN_TO_PREVIOUS_PAGE = 2;
60     public static final int RETURN_TO_PREVIOUS_ACTION = 3;
61     
62     /**
63      * @deprecated Use {@link #RETURN_TO_CURRENT_PAGE} or {@link #RETURN_TO_PREVIOUS_PAGE} instead.
64      */

65     public static final int RETURN_TO_PAGE = -1;
66     
67     /**
68      * @deprecated Use {@link #RETURN_TO_PREVIOUS_ACTION} instead.
69      */

70     public static final int RETURN_TO_ACTION = -2;
71     
72     private static final Logger _log = Logger.getInstance( Forward.class );
73     
74     private static final String JavaDoc RETURN_TO_CURRENT_PAGE_STR = "currentPage";
75     private static final String JavaDoc RETURN_TO_PREVIOUS_PAGE_STR = "previousPage";
76     private static final String JavaDoc RETURN_TO_PAGE_LEGACY_STR = "page";
77     private static final String JavaDoc RETURN_TO_PREVIOUS_ACTION_STR = "previousAction";
78     private static final String JavaDoc RETURN_TO_ACTION_LEGACY_STR = "action";
79     
80     private static final Map JavaDoc/*< String, Class >*/ PRIMITIVE_TYPES = new HashMap JavaDoc/*< String, Class >*/();
81     
82     static
83     {
84         PRIMITIVE_TYPES.put( "boolean", boolean.class );
85         PRIMITIVE_TYPES.put( "byte", byte.class );
86         PRIMITIVE_TYPES.put( "char", char.class );
87         PRIMITIVE_TYPES.put( "double", double.class );
88         PRIMITIVE_TYPES.put( "float", float.class );
89         PRIMITIVE_TYPES.put( "int", int.class );
90         PRIMITIVE_TYPES.put( "long", long.class );
91         PRIMITIVE_TYPES.put( "short", short.class );
92     }
93
94     private List JavaDoc _outputForms;
95
96     private boolean _isNestedReturn = false;
97     private boolean _init = false;
98     private transient ActionMapping _mapping = null; // will be reinitialized as necessary by PreviousPageInfo
99
private transient FlowController _flowController = null; // will be reinitialized as necessary by PreviousPageInfo
100
private transient ServletContext JavaDoc _servletContext = null; // will be reinitialized as necessary by PreviousPageInfo
101
private String JavaDoc _mappingPath;
102     private InternalStringBuilder _queryString;
103     private boolean _explicitPath = false;
104     private String JavaDoc _returnFormType = null;
105     private Map JavaDoc _actionOutputs = null;
106     private int _returnToType;
107     private boolean _redirectSpecifiedOnAnnotation = false;
108     private boolean _redirectSetThroughMethod = false;
109     private boolean _restoreQueryString = false;
110     private boolean _externalRedirect = false;
111     
112     /**
113      * An alternate ModuleConfig from which to resolve forwards if they are not resolved
114      * from the stored ActionMapping (and its stored ModuleConfig).
115      */

116     private ModuleConfig _altModuleConfig;
117     
118     
119     /**
120      * @exclude
121      */

122     protected Forward( Forward init )
123     {
124         _outputForms = init._outputForms;
125         _init = init._init;
126         _mapping = init._mapping;
127         _mappingPath = init._mappingPath;
128         _queryString = init._queryString;
129         _explicitPath = init._explicitPath;
130         _flowController = init._flowController;
131         _servletContext = init._servletContext;
132         _returnFormType = init._returnFormType;
133         _actionOutputs = init._actionOutputs;
134         _returnToType = init._returnToType;
135         _restoreQueryString = init._restoreQueryString;
136         _externalRedirect = init._externalRedirect;
137         _redirectSpecifiedOnAnnotation = init._redirectSpecifiedOnAnnotation;
138         _redirectSetThroughMethod = init._redirectSetThroughMethod;
139     }
140     
141     /**
142      * @exclude
143      */

144     protected Forward( HttpServletRequest JavaDoc request )
145     {
146         setPath( InternalUtils.getDecodedServletPath( request ) );
147         setContextRelative( true );
148         _explicitPath = true;
149     }
150     
151     /**
152      * Constructor which accepts the name of a forward defined by the
153      * {@link org.apache.beehive.netui.pageflow.annotations.Jpf.Forward &#64;Jpf.Forward}
154      * annotation. The values returned from {@link #getPath}, {@link #getRedirect} and
155      * {@link #contextRelative} are resolved from this forward.
156      *
157      * @param forwardName the name of the forward
158      * ({@link org.apache.beehive.netui.pageflow.annotations.Jpf.Forward &#64;Jpf.Forward}) to resolve.
159      */

160     public Forward( String JavaDoc forwardName )
161     {
162         setName( forwardName );
163     }
164
165     /**
166      * Constructor which accepts the name of a forward defined by the
167      * {@link org.apache.beehive.netui.pageflow.annotations.Jpf.Forward &#64;Jpf.Forward}
168      * annotation. The values returned from {@link #getPath}, {@link #getRedirect} and
169      * {@link #contextRelative} are resolved from this forward. Also accepts a form bean
170      * to make available in the request (or user session, as appropriate).
171      *
172      * @param forwardName the name of the forward
173      * ({@link org.apache.beehive.netui.pageflow.annotations.Jpf.Forward &#64;Jpf.Forward}) to resolve.
174      * @param outputFormBean a form bean instance to make available in the request (or user session, as appropriate).
175      * See {@link #addOutputForm} for details about how this manifests itself.
176      */

177     public Forward( String JavaDoc forwardName, Object JavaDoc outputFormBean )
178     {
179         this( forwardName );
180         
181         if ( outputFormBean != null )
182         {
183             addOutputForm( outputFormBean );
184         }
185     }
186     
187     /**
188      * Constructor which accepts the name of a forward defined by the
189      * {@link org.apache.beehive.netui.pageflow.annotations.Jpf.Forward &#64;Jpf.Forward}
190      * annotation. The values returned from {@link #getPath}, {@link #getRedirect} and
191      * {@link #contextRelative} are resolved from this forward. Also accepts a named action output
192      * to make available in the request, through {@link PageFlowUtils#getActionOutput}..
193      *
194      * @param forwardName the name of the forward
195      * ({@link org.apache.beehive.netui.pageflow.annotations.Jpf.Forward &#64;Jpf.Forward}) to resolve.
196      * @param actionOutputName the name of a action output to make available in the request.
197      * @param actionOutputValue the action output object to make available in the request.
198      */

199     public Forward( String JavaDoc forwardName, String JavaDoc actionOutputName, Object JavaDoc actionOutputValue )
200     {
201         this( forwardName );
202         addActionOutput( actionOutputName, actionOutputValue );
203     }
204
205     /**
206      * Constructs a Forward that returns the given URI for {@link #getPath}. By default
207      * the Forward will cause server forward (not a browser redirect); to change this, use
208      * {@link #setRedirect}.
209      *
210      * @param uri the URI to return for {@link #getPath}.
211      */

212     public Forward( URI JavaDoc uri )
213     {
214         setPath( uri.toString() );
215         setContextRelative( uri.getPath().startsWith( "/" ) );
216         if ( uri.isAbsolute() ) super.setRedirect( true );
217         _explicitPath = true;
218     }
219     
220     /**
221      * Constructs a Forward that returns the given URI for {@link #getPath}.
222      *
223      * @param uri the URI to return for {@link #getPath}.
224      * @param doRedirect set to <code>true</code> if this Forward should cause a browser redirect;
225      * <code>false</code> if it should cause a server forward.
226      */

227     public Forward( URI JavaDoc uri, boolean doRedirect )
228     {
229         if ( ! doRedirect && uri.isAbsolute() )
230         {
231             throw new IllegalStateException JavaDoc( "Redirect value cannot be set to false for an absolute URI." );
232         }
233         
234         setPath( uri.toString() );
235         setRedirect( doRedirect );
236         setContextRelative( uri.getPath().startsWith( "/" ) );
237         _explicitPath = true;
238     }
239     
240     /**
241      * Constructs a Forward that returns the given URL for {@link #getPath}. Because the URL path
242      * is absolute by nature, this Forward will cause a browser redirect.
243      *
244      * @param url the URL to return for {@link #getPath}.
245      */

246     public Forward( URL JavaDoc url )
247     {
248         setPath( url.toString() );
249         super.setRedirect( true );
250         _explicitPath = true;
251     }
252     
253     /**
254      * Internal. Initialize from an existing Struts ActionForward.
255      * @exclude
256      */

257     protected Forward( ActionForward initFwd, ServletContext JavaDoc servletContext )
258     {
259         _servletContext = servletContext;
260         setName( initFwd.getName() );
261         initFrom( initFwd );
262     }
263     
264     /**
265      * Set whether the URI resolved by this Forward should be redirected to.
266      *
267      * @param doRedirect if <code>true</code>, the controller will send a browser redirect to
268      * the URI for this Forward; otherwise, it will do a server forward to
269      * the URI.
270      */

271     public void setRedirect( boolean doRedirect )
272     {
273         super.setRedirect( doRedirect );
274         _redirectSetThroughMethod = true;
275     }
276     
277     /**
278      * Tell whether the URI resolved by this Forward should be redirected to.
279      *
280      * @return <code>true</code> if the controller will send a browser redirect to the URI for
281      * this Forward; <code>false</code> if it will do a server forward to the URI.
282      */

283     public boolean isRedirect()
284     {
285         return super.getRedirect();
286     }
287     
288     /**
289      * Add a form bean that will be made available in the request (or user session, as
290      * appropriate) if this Forward is returned by an action method in a {@link PageFlowController}.
291      * Specifically, each form bean is stored as a request attribute with a name determined by
292      * {@link PageFlowUtils#getFormBeanName}.
293      *
294      * @param formBean the form bean instance to add.
295      */

296     public final void addOutputForm( Object JavaDoc formBean )
297     {
298         assert formBean != null : "The output form bean may not me null.";
299         
300         if ( formBean == null ) throw new IllegalArgumentException JavaDoc( "The output form bean may not be null." );
301         if ( _outputForms == null ) _outputForms = new ArrayList JavaDoc();
302         
303         //
304
// Throw an exception if this is a redirect, and if there was an output form added. Output forms are carried
305
// in the request, and will be lost on redirects.
306
//
307
if ( _init && getRedirect() )
308         {
309             String JavaDoc actionPath = _mappingPath != null ? _mappingPath : "";
310             String JavaDoc descrip = getName() != null ? getName() : getPath();
311             PageFlowException ex = new IllegalRedirectOutputFormException( descrip, actionPath, _flowController,
312                                                                             formBean.getClass().getName() );
313             InternalUtils.throwPageFlowException( ex );
314         }
315
316         _outputForms.add( InternalUtils.wrapFormBean( formBean ) );
317     }
318     
319     /**
320      * Get all form-beans attached to this forward through {@link #addOutputForm} or {@link #Forward(String, Object)}.
321      *
322      * @return an array of ActionForm instances that are attached to this forward.
323      */

324     public final ActionForm[] getOutputForms()
325     {
326         if ( _outputForms == null ) return EMPTY_ACTION_FORM_ARRAY;
327         return ( ActionForm[] ) _outputForms.toArray( EMPTY_ACTION_FORM_ARRAY );
328     }
329
330     /**
331      * Get the first output form bean that was added to this Forward.
332      */

333     public ActionForm getFirstOutputForm( HttpServletRequest JavaDoc request )
334     {
335         if ( _outputForms == null || _outputForms.size() == 0 )
336         {
337             if ( _returnFormType != null )
338             {
339                 try
340                 {
341                     if ( _log.isDebugEnabled() )
342                     {
343                         _log.debug( "Creating form bean of type " + _returnFormType );
344                     }
345                     
346                     ServletContext JavaDoc servletContext = InternalUtils.getServletContext( request );
347                     ReloadableClassHandler rch = Handlers.get( servletContext ).getReloadableClassHandler();
348                     Object JavaDoc formBean = rch.newInstance( _returnFormType );
349                     ActionForm wrappedFormBean = InternalUtils.wrapFormBean( formBean );
350                     addOutputForm( wrappedFormBean );
351                     return wrappedFormBean;
352                 }
353                 catch ( Exception JavaDoc e )
354                 {
355                     _log.error( "Could not create form bean instance of " + _returnFormType, e );
356                 }
357             }
358             
359             return null;
360         }
361         else
362         {
363             return ( ActionForm ) _outputForms.get( 0 );
364         }
365     }
366     
367     /**
368      * Tell whether {@link #getPath} will be successful, i.e., whether one of the following two
369      * conditions is met:
370      * <ul>
371      * <li>the name around which this object was constructed resolves to a path defined
372      * by a {@link org.apache.beehive.netui.pageflow.annotations.Jpf.Forward &#64;Jpf.Forward}, or</li>
373      * <li>this object was constructed around an explicit path, by
374      * {@link #Forward(URI)} or {@link #Forward(URL)}.</li>
375      * </ul>
376      *
377      * @return <code>true</code> if this forward does resolve to a URI path.
378      */

379     public boolean doesResolve()
380     {
381         if ( _explicitPath )
382         {
383             return true;
384         }
385         
386         assert _mapping != null || _altModuleConfig != null : "PageFlow.Forward.doesResolve() called outside of request";
387         return findForward( getName() ) != null;
388     }
389
390     /**
391      * Resolves the forward with the given name, from the stored ActionMapping if possible, or
392      * from the stored alternate ModuleConfig as a last resort.
393      *
394      * @param forwardName the name of the forward to resolve.
395      * @return the resolved ActionForward, or <code>null</code> if none is found.
396      */

397     protected ActionForward findForward( String JavaDoc forwardName )
398     {
399         ActionForward fwd = _mapping != null ? _mapping.findForward( forwardName ) : null;
400         
401         if ( fwd != null )
402         {
403             return fwd;
404         }
405         else if ( _altModuleConfig != null )
406         {
407             return ( ActionForward ) _altModuleConfig.findForwardConfig( forwardName );
408         }
409         
410         return null;
411     }
412     
413     /**
414      * Set an alternate ModuleConfig from which to resolve forwards if they are not resolved
415      * from the stored ActionMapping (and its stored ModuleConfig).
416      *
417      * @exclude
418      */

419     public void setAlternateModuleConfig( ModuleConfig mc )
420     {
421         _altModuleConfig = mc;
422     }
423     
424     private final void init()
425     {
426         if ( ! _init )
427         {
428             if ( _mappingPath == null && _altModuleConfig == null )
429             {
430                 throw new IllegalStateException JavaDoc( "Forward is not initialized. Use initialize()." );
431             }
432             
433             ActionForward fwd = findForward( getName() );
434
435             if ( fwd == null )
436             {
437                 PageFlowException ex = new UnresolvableForwardException( getName(), _mappingPath, _flowController );
438                 InternalUtils.throwPageFlowException( ex );
439             }
440
441             initFrom( fwd );
442             
443             //
444
// Throw an exception if this is a redirect, and if there was an output form or an action output added.
445
// Output forms and action outputs are carried in the request, and will be lost on redirects.
446
//
447
if ( getRedirect() )
448             {
449                 if ( _actionOutputs != null && ! _actionOutputs.isEmpty() )
450                 {
451                     PageFlowException ex =
452                             new IllegalActionOutputException( getName(), _mappingPath, _flowController,
453                                                              ( String JavaDoc ) _actionOutputs.keySet().iterator().next() );
454                     InternalUtils.throwPageFlowException( ex );
455                 }
456                 
457                 if ( _outputForms != null && ! _outputForms.isEmpty() )
458                 {
459                     PageFlowException ex =
460                             new IllegalRedirectOutputFormException( getName(), _mappingPath, _flowController,
461                                                                     _outputForms.get( 0 ).getClass().getName() );
462                     InternalUtils.throwPageFlowException( ex );
463                 }
464             }
465         }
466     }
467     
468     private void initFrom( ActionForward fwd )
469     {
470         setContextRelative( fwd.getContextRelative() );
471
472         //
473
// Add query params to the path.
474
//
475
path = fwd.getPath();
476         if ( _queryString != null ) path += _queryString.toString();
477         
478         if ( fwd instanceof PageFlowActionForward )
479         {
480             PageFlowActionForward fc = ( PageFlowActionForward ) fwd;
481             _isNestedReturn = fc.isNestedReturn();
482             _returnFormType = fc.getReturnFormType();
483             _redirectSpecifiedOnAnnotation = fc.hasExplicitRedirectValue();
484             _restoreQueryString = fc.isRestoreQueryString();
485             _externalRedirect = fc.isExternalRedirect();
486             
487             Class JavaDoc returnFormClass = null;
488             
489             if ( _returnFormType != null )
490             {
491                 try
492                 {
493                     returnFormClass = Class.forName( _returnFormType );
494                 }
495                 catch ( ClassNotFoundException JavaDoc e )
496                 {
497                     // This should never happen -- the JPF compiler ensures that it's a valid class.
498
assert false : e;
499                 }
500             }
501             
502             if ( fc.isReturnToPage() || fc.isReturnToAction() )
503             {
504                 String JavaDoc fwdPath = fc.getPath();
505                 
506                 if ( fwdPath.equals( RETURN_TO_PREVIOUS_PAGE_STR ) )
507                 {
508                     _returnToType = RETURN_TO_PREVIOUS_PAGE;
509                 }
510                 else if ( fwdPath.equals( RETURN_TO_CURRENT_PAGE_STR ) )
511                 {
512                     _returnToType = RETURN_TO_CURRENT_PAGE;
513                 }
514                 else if ( fwdPath.equals( RETURN_TO_PAGE_LEGACY_STR ) )
515                 {
516                     _returnToType = RETURN_TO_PAGE; // legacy
517
}
518                 else if ( fwdPath.equals( RETURN_TO_PREVIOUS_ACTION_STR ) )
519                 {
520                     _returnToType = RETURN_TO_PREVIOUS_ACTION;
521                 }
522                 else if ( fwdPath.equals( RETURN_TO_ACTION_LEGACY_STR ) )
523                 {
524                     _returnToType = RETURN_TO_ACTION; // legacy
525
}
526                 else
527                 {
528                     assert false : "invalid return-to type for forward " + fc.getName() + ": " + fwdPath;
529                     _returnToType = RETURN_TO_CURRENT_PAGE;
530                 }
531             }
532             
533             String JavaDoc retFormMember = fc.getReturnFormMember();
534
535             if ( retFormMember != null )
536             {
537                 try
538                 {
539                     assert _flowController != null; // should be set in initialize()
540
Field JavaDoc field = _flowController.getClass().getDeclaredField( retFormMember );
541                     returnFormClass = field.getType();
542                     field.setAccessible( true );
543                     ActionForm form = InternalUtils.wrapFormBean( field.get( _flowController ) );
544                     
545                     if ( form != null )
546                     {
547                         if ( _log.isDebugEnabled() )
548                         {
549                             _log.debug( "using member " + retFormMember + " for Forward " + getName() );
550                         }
551                         
552                         addOutputForm( form );
553                     }
554                     else
555                     {
556                         if ( _log.isInfoEnabled() )
557                         {
558                             _log.info( "returnFormMember " + retFormMember + " was null." );
559                         }
560                     }
561                 }
562                 catch ( NoSuchFieldException JavaDoc e )
563                 {
564                     assert false : "could not find field " + retFormMember; // compiler should catch this
565
}
566                 catch ( IllegalAccessException JavaDoc e )
567                 {
568                     assert false; // should not get here -- field is accessible.
569
}
570             }
571             
572             //
573
// Make sure that if there's currently an output form, that it confirms to the return-form-type.
574
//
575
if ( returnFormClass != null && _outputForms != null && _outputForms.size() > 0 )
576             {
577                 Object JavaDoc outputForm = InternalUtils.unwrapFormBean( ( ActionForm ) _outputForms.get( 0 ) );
578                 
579                 if ( ! returnFormClass.isInstance( outputForm ) )
580                 {
581                     PageFlowException ex =
582                             new IllegalOutputFormTypeException( getName(), _mappingPath, _flowController,
583                                                                 outputForm.getClass().getName(),
584                                                                 returnFormClass.getName() );
585                     InternalUtils.throwPageFlowException( ex );
586                 }
587             }
588             
589             checkActionOutputs( fc );
590         }
591         
592         if ( ! _redirectSetThroughMethod ) setRedirect( fwd.getRedirect() );
593         
594         _init = true;
595     }
596
597     /**
598      * Make sure required action outputs are present, and are of the right type (only make the latter check when not
599      * in production mode
600      */

601     private void checkActionOutputs( PageFlowActionForward fc )
602     {
603         PageFlowActionForward.ActionOutput[] actionOutputs = fc.getActionOutputs();
604         boolean isInProductionMode =
605                 AdapterManager.getServletContainerAdapter( _servletContext ).isInProductionMode();
606             
607         for ( int i = 0; i < actionOutputs.length; ++i )
608         {
609             PageFlowActionForward.ActionOutput actionOutput = actionOutputs[i];
610                 
611             if ( ! actionOutput.getNullable()
612                  && ( _actionOutputs == null || _actionOutputs.get( actionOutput.getName() ) == null ) )
613             {
614                 PageFlowException ex =
615                     new MissingActionOutputException( _mappingPath, _flowController, actionOutput.getName(), getName() );
616                 InternalUtils.throwPageFlowException( ex );
617             }
618                 
619             //
620
// If we're *not* in production mode, do some (expensive) checks to ensure that the types for the
621
// action outputs match their declared types.
622
//
623
if ( ! isInProductionMode && _actionOutputs != null )
624             {
625                 Object JavaDoc actualActionOutput = _actionOutputs.get( actionOutput.getName() );
626                     
627                 if ( actualActionOutput != null )
628                 {
629                     String JavaDoc expectedTypeName = actionOutput.getType();
630                     int expectedArrayDims = 0;
631                     
632                     while ( expectedTypeName.endsWith( "[]" ) )
633                     {
634                         ++expectedArrayDims;
635                         expectedTypeName = expectedTypeName.substring( 0, expectedTypeName.length() - 2 );
636                     }
637                     
638                     Class JavaDoc expectedType = ( Class JavaDoc ) PRIMITIVE_TYPES.get( expectedTypeName );
639                     
640                     if ( expectedType == null )
641                     {
642                         try
643                         {
644                             expectedType = Class.forName( expectedTypeName );
645                         }
646                         catch ( ClassNotFoundException JavaDoc e )
647                         {
648                             _log.error( "Could not load expected action output type " + expectedTypeName
649                                         + " for action output '" + actionOutput.getName() + "' on forward '"
650                                         + fc.getName() + "'; skipping type check." );
651                             continue;
652                         }
653                     }
654                     
655                     Class JavaDoc actualType = actualActionOutput.getClass();
656                     int actualArrayDims = 0;
657                     InternalStringBuilder arraySuffix = new InternalStringBuilder();
658                     
659                     while ( actualType.isArray() && actualArrayDims <= expectedArrayDims )
660                     {
661                         ++actualArrayDims;
662                         arraySuffix.append( "[]" );
663                         actualType = actualType.getComponentType();
664                     }
665                         
666                     if ( actualArrayDims != expectedArrayDims || ! expectedType.isAssignableFrom( actualType ) )
667                     {
668                         PageFlowException ex =
669                                 new MismatchedActionOutputException( _mappingPath, _flowController,
670                                                                      actionOutput.getName(), getName(),
671                                                                      expectedTypeName,
672                                                                      actualType.getName() + arraySuffix );
673                         InternalUtils.throwPageFlowException( ex );
674                     }
675                 }
676             }
677         }
678     }
679                 
680     /**
681      * Set the current ActionMapping and associated FlowController. Normally, this method is called
682      * by the framework, but you can use it to initialize the Forward object in order to call {@link #getPath}.
683      *
684      * @deprecated Use {@link #initialize(ActionMapping, FlowController, ServletRequest)} instead.
685      * @param mapping the current ActionMapping; this can be obtained from {@link FlowController#getMapping}.
686      * @param flowController the object in which to look for referenced return-form members.
687      */

688     public void initialize( ActionMapping mapping, FlowController flowController )
689     {
690         _mapping = mapping;
691         _mappingPath = mapping != null ? mapping.getPath() : null;
692         _flowController = flowController;
693         _servletContext = flowController.getServletContext();
694     }
695     
696     /**
697      * Set the current ActionMapping and associated FlowController. Normally, this method is called
698      * by the framework, but you can use it to initialize the Forward object in order to call {@link #getPath}.
699      *
700      * @param mapping the current ActionMapping; this can be obtained from {@link FlowController#getMapping}.
701      * @param flowController the object in which to look for referenced return-form members.
702      */

703     public void initialize( ActionMapping mapping, FlowController flowController, ServletRequest JavaDoc request )
704     {
705         _mapping = mapping;
706         _mappingPath = mapping != null ? mapping.getPath() : null;
707         _flowController = flowController;
708         _servletContext = flowController.getServletContext();
709     }
710     
711     /**
712      * Set the path to be returned by {@link #getPath}. This overrides any path or forward name
713      * set in a constructor.
714      *
715      * @param contextRelativePath the path to be returned by {@link #getPath}.
716      */

717     public void setPath( String JavaDoc contextRelativePath )
718     {
719         path = contextRelativePath;
720         _init = true;
721     }
722     
723     boolean isExplicitPath()
724     {
725         return _explicitPath;
726     }
727     
728     /**
729      * Tell whether this Forward was configured explicitly (through
730      * {@link org.apache.beehive.netui.pageflow.annotations.Jpf.Forward#redirect &#64;Jpf.Forward(redirect=...)},
731      * {@link #setRedirect}, or {@link #Forward(URI, boolean)}) to perform a redirect. Otherwise, a redirect is
732      * implied by a URI that does not resolve to the current server.
733      */

734     public boolean hasExplicitRedirectValue()
735     {
736         return _redirectSetThroughMethod || _redirectSpecifiedOnAnnotation;
737     }
738
739     /**
740      * Get the URI path associated with this object. Resolve it from the name of a forward
741      * ({@link org.apache.beehive.netui.pageflow.annotations.Jpf.Forward &#64;Jpf.Forward}) if necessary.
742      *
743      * @return a String that is the URI path.
744      * @see #Forward(String)
745      * @see #Forward(String, Object)
746      * @see #Forward(URI)
747      * @see #Forward(URL)
748      * @see #setPath
749      */

750     public String JavaDoc getPath()
751     {
752         init();
753         return super.getPath();
754     }
755     
756     /**
757      * Tell whether returning this forward from an action method will cause a return from
758      * a nested {@link PageFlowController}.
759      *
760      * @return <code>true</code> if this forward will cause a return from nesting.
761      */

762     public boolean isNestedReturn()
763     {
764         init();
765         return _isNestedReturn;
766     }
767     
768     /**
769      * Tell whether returning this forward from an action method will cause a previous page
770      * to be displayed.
771      *
772      * @return <code>true</code> if returning this forward from an action method will cause
773      * a previous page to be displayed.
774      */

775     public boolean isReturnToPage()
776     {
777         init();
778         return _returnToType == RETURN_TO_PREVIOUS_PAGE || _returnToType == RETURN_TO_CURRENT_PAGE
779                    || _returnToType == RETURN_TO_PAGE;
780     }
781
782     /**
783      * Tell whether returning this forward from an action method will cause the previous action
784      * to be re-run.
785      *
786      * @return <code>true</code> if returning this forward from an action method will cause the
787      * previous action to be re-run, i.e., whether the URI returned by {@link #getPath} will end
788      * in "<i>previous-action-name</i>.do".
789      */

790     public boolean isReturnToAction()
791     {
792         init();
793         return _returnToType == RETURN_TO_PREVIOUS_ACTION || _returnToType == RETURN_TO_ACTION;
794     }
795
796     /**
797      * Tell whether this is a redirect to a URI outside of the current web application.
798      */

799     public boolean isExternalRedirect()
800     {
801         return _externalRedirect;
802     }
803
804     /**
805      * Specify that this is a redirect to a URI outside of the current web application.
806      */

807     public void setExternalRedirect( boolean externalRedirect )
808     {
809         _externalRedirect = externalRedirect;
810         if ( externalRedirect ) setRedirect( true );
811     }
812
813     /**
814      * Tell whether this Forward will store the original query string on the page restored when a
815      * {@link org.apache.beehive.netui.pageflow.annotations.Jpf.Forward &#64;Jpf.Forward},
816      * {@link org.apache.beehive.netui.pageflow.annotations.Jpf.SimpleAction &#64;Jpf.SimpleAction},
817      * or {@link org.apache.beehive.netui.pageflow.annotations.Jpf.ConditionalForward &#64;Jpf.ConditionalForward}
818      * with <code>navigateTo={@link org.apache.beehive.netui.pageflow.annotations.Jpf.NavigateTo#previousAction Jpf.NavigateTo.previousAction}
819      * </code> is used.
820      */

821     public boolean doesRestoreQueryString()
822     {
823         init();
824         return _restoreQueryString;
825     }
826     
827     /**
828      * Tell whether the URI returned by {@link #getPath} is for a page flow.
829      *
830      * @return <code>true</code> if the URI returned by {@link #getPath} is for a page flow, i.e.,
831      * if it ends in ".jpf".
832      */

833     public boolean forwardsToPageFlow()
834     {
835         return FileUtils.osSensitiveEndsWith( getPath(), PageFlowConstants.JPF_EXTENSION );
836     }
837     
838     /**
839      * Set the query string that will be appended to the URI returned by {@link #getPath}.
840      *
841      * @param queryString the query string that will be appended to the URI. If this string does not
842      * start with <code>'?'</code>, then this character will be prepended; if the string is
843      * <code>null</code>, the query string will be removed.
844      */

845     public void setQueryString( String JavaDoc queryString )
846     {
847         if ( queryString == null || queryString.length() == 0 )
848         {
849             _queryString = null;
850         }
851         else if ( queryString.charAt( 0 ) == '?' )
852         {
853             _queryString = new InternalStringBuilder( queryString );
854         }
855         else
856         {
857             _queryString = new InternalStringBuilder( "?" ).append( queryString );
858         }
859     }
860     
861     /**
862      * Get the query string that will be appended to the URI returned by {@link #getPath}.
863      *
864      * @return the query string that will be appended to the URI, or <code>null</code> if there
865      * is no query string.
866      */

867     public String JavaDoc getQueryString()
868     {
869         return _queryString != null ? _queryString.toString() : null;
870     }
871     
872     /**
873      * Add a query parameter to the URI returned by {@link #getPath}.
874      *
875      * @param paramName the name of the query parameter.
876      * @param value the value of the query parameter, or <code>null</code> if there is no value.
877      */

878     public void addQueryParam( String JavaDoc paramName, String JavaDoc value )
879     {
880         if ( _queryString == null )
881         {
882             _queryString = new InternalStringBuilder( "?" );
883         }
884         else
885         {
886             _queryString.append( '&' );
887         }
888         
889         _queryString.append( paramName );
890         
891         if ( value != null )
892         {
893             _queryString.append( '=' ).append( value );
894         }
895     }
896     
897     /**
898      * Add a query parameter with no value to the URI returned by {@link #getPath}.
899      *
900      * @param paramName the name of the query parameter.
901      */

902     public final void addQueryParam( String JavaDoc paramName )
903     {
904         addQueryParam( paramName, null );
905     }
906     
907     /**
908      * Adds an action output that will be made available in the request, through {@link PageFlowUtils#getActionOutput}.
909      *
910      * @deprecated Use {@link #addActionOutput} instead.
911      * @param paramName the name of the action output.
912      * @param value the action output value.
913      */

914     public void addPageInput( String JavaDoc paramName, Object JavaDoc value )
915     {
916         addActionOutput( paramName, value );
917     }
918     
919     /**
920      * Adds an action output that will be made available in the request, through {@link PageFlowUtils#getActionOutput}.
921      *
922      * @param paramName the name of the action output.
923      * @param value the action output value.
924      */

925     public void addActionOutput( String JavaDoc paramName, Object JavaDoc value )
926     {
927         if ( paramName == null || paramName.length() == 0 )
928         {
929             throw new IllegalArgumentException JavaDoc( "An action output name may not be null or empty." );
930         }
931         
932         if ( _actionOutputs == null )
933         {
934             _actionOutputs = new HashMap JavaDoc();
935         }
936         
937         //
938
// Throw an exception if this is a redirect, and if there was an action output. Action outputs are carried
939
// in the request, and will be lost on redirects.
940
//
941
if ( _init && getRedirect() )
942         {
943             String JavaDoc actionPath = _mappingPath != null ? _mappingPath : "";
944             String JavaDoc descrip = getName() != null ? getName() : getPath();
945             PageFlowException ex = new IllegalActionOutputException( descrip, actionPath, _flowController, paramName );
946             InternalUtils.throwPageFlowException( ex );
947         }
948         
949         _actionOutputs.put( paramName, value );
950     }
951     
952     /**
953      * Get all action outputs that have been set on this Forward.
954      *
955      * @deprecated Use {@link #getActionOutputs} instead.
956      * @return a Map of name/value pairs representing all action outputs.
957      * @see #addActionOutput
958      */

959     public Map JavaDoc getPageInputs()
960     {
961         return getActionOutputs();
962     }
963     
964     /**
965      * Get all action outputs that have been set on this Forward.
966      *
967      * @return a Map of name/value pairs representing all action outputs.
968      * @see #addActionOutput
969      */

970     public Map JavaDoc getActionOutputs()
971     {
972         return _actionOutputs;
973     }
974     
975     /**
976      * Get the type of return, if this is a <code>return-to</code> type.
977      *
978      * @return one of the following values: {@link #RETURN_TO_CURRENT_PAGE}, {@link #RETURN_TO_PREVIOUS_PAGE},
979      * {@link #RETURN_TO_PAGE}, {@link #RETURN_TO_PREVIOUS_ACTION}, {@link #RETURN_TO_ACTION}, or
980      * {@link #RETURN_TO_NONE} if this Forward is not a <code>return-to</code> type.
981      * @see #isReturnToAction
982      * @see #isReturnToPage
983      */

984     public int getReturnToType()
985     {
986         return _returnToType;
987     }
988     
989     /**
990      * Get the type of return as a String, if this is a <code>return-to</code> type.
991      *
992      * @return one of the following values: <code>currentPage</code>, <code>previousPage</code>, <code>page</code>,
993      * (deprecated), <code>previousAction</code>, <code>action</code> (deprecated), or <code>null</code>
994      * if this is not a <code>return-to</code> type.
995      * @see #isReturnToAction
996      * @see #isReturnToPage
997      */

998     public String JavaDoc getReturnToTypeAsString()
999     {
1000        switch ( _returnToType )
1001        {
1002            case RETURN_TO_CURRENT_PAGE:
1003                return RETURN_TO_CURRENT_PAGE_STR;
1004            
1005            case RETURN_TO_PREVIOUS_PAGE:
1006                return RETURN_TO_PREVIOUS_PAGE_STR;
1007            
1008            case RETURN_TO_PAGE:
1009                return RETURN_TO_PAGE_LEGACY_STR;
1010                
1011            case RETURN_TO_PREVIOUS_ACTION:
1012                return RETURN_TO_PREVIOUS_ACTION_STR;
1013            
1014            case RETURN_TO_ACTION:
1015                return RETURN_TO_ACTION_LEGACY_STR;
1016        }
1017        
1018        return null;
1019    }
1020    
1021    void reinitialize( FlowController fc )
1022    {
1023        _flowController = fc;
1024        _servletContext = fc.getServletContext();
1025        
1026        if ( _mapping == null && _mappingPath != null )
1027        {
1028            ModuleConfig mc = fc.getModuleConfig();
1029            assert mc != null : "no ModuleConfig found for " + fc.getClass().getName();
1030            _mapping = ( ActionMapping ) mc.findActionConfig( _mappingPath );
1031        }
1032    }
1033}
1034
Popular Tags