KickJava   Java API By Example, From Geeks To Geeks.

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


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

18 package org.apache.beehive.netui.pageflow;
19
20 import org.apache.beehive.netui.util.internal.InternalStringBuilder;
21
22 import org.apache.beehive.netui.core.urls.FreezableMutableURI;
23 import org.apache.beehive.netui.core.urls.MutableURI;
24 import org.apache.beehive.netui.core.urls.URIContext;
25 import org.apache.beehive.netui.core.urls.URLRewriterService;
26 import org.apache.beehive.netui.core.urls.URLType;
27 import org.apache.beehive.netui.core.urltemplates.URLTemplateDescriptor;
28 import org.apache.beehive.netui.pageflow.internal.ActionResultImpl;
29 import org.apache.beehive.netui.pageflow.internal.InternalUtils;
30 import org.apache.beehive.netui.pageflow.internal.InternalConstants;
31 import org.apache.beehive.netui.pageflow.internal.AdapterManager;
32 import org.apache.beehive.netui.pageflow.internal.PageFlowRequestWrapper;
33 import org.apache.beehive.netui.pageflow.internal.URIContextFactory;
34 import org.apache.beehive.netui.pageflow.scoping.ScopedRequest;
35 import org.apache.beehive.netui.pageflow.scoping.ScopedResponse;
36 import org.apache.beehive.netui.pageflow.scoping.ScopedServletUtils;
37 import org.apache.beehive.netui.util.internal.FileUtils;
38 import org.apache.beehive.netui.util.internal.ServletUtils;
39 import org.apache.beehive.netui.util.config.ConfigUtil;
40 import org.apache.beehive.netui.util.config.bean.UrlConfig;
41 import org.apache.beehive.netui.util.logging.Logger;
42 import org.apache.beehive.netui.script.common.ImplicitObjectUtil;
43 import org.apache.struts.action.ActionForm;
44 import org.apache.struts.action.ActionMapping;
45 import org.apache.struts.action.ActionServlet;
46 import org.apache.struts.action.ActionMessage;
47 import org.apache.struts.config.FormBeanConfig;
48 import org.apache.struts.config.ModuleConfig;
49 import org.apache.struts.upload.MultipartRequestWrapper;
50 import org.apache.struts.util.RequestUtils;
51
52 import javax.servlet.ServletContext JavaDoc;
53 import javax.servlet.ServletRequest JavaDoc;
54 import javax.servlet.http.HttpServletRequest JavaDoc;
55 import javax.servlet.http.HttpServletResponse JavaDoc;
56 import javax.servlet.http.HttpSession JavaDoc;
57 import java.io.PrintStream JavaDoc;
58 import java.net.URISyntaxException JavaDoc;
59 import java.util.Collections JavaDoc;
60 import java.util.HashMap JavaDoc;
61 import java.util.Map JavaDoc;
62 import java.util.Stack JavaDoc;
63 import java.util.List JavaDoc;
64 import java.util.ArrayList JavaDoc;
65 import java.util.Iterator JavaDoc;
66
67 import org.apache.beehive.netui.util.internal.concurrent.InternalConcurrentHashMap;
68
69
70
71 /**
72  * Utility methods related to Page Flow.
73  */

74 public class PageFlowUtils
75         implements PageFlowConstants, InternalConstants
76 {
77     private static final Logger _log = Logger.getInstance( PageFlowUtils.class );
78
79     private static final String JavaDoc ACTION_URI_ATTR = ATTR_PREFIX + "_actionURI";
80     private static final int PAGEFLOW_EXTENSION_LEN = PAGEFLOW_EXTENSION.length();
81     private static final String JavaDoc DEFAULT_AUTORESOLVE_EXTENSIONS[] = new String JavaDoc[]{ ACTION_EXTENSION, PAGEFLOW_EXTENSION };
82     
83     
84     /** Map of Struts module prefix to Map of form-type-name to form-name. */
85     private static Map JavaDoc/*< String, Map< String, List< String > > >*/ _formNameMaps =
86             new InternalConcurrentHashMap/*< String, Map< String, List< String > > >*/();
87
88     
89     /**
90      * Get the Struts module path for a URI. This is the parent directory, relative to the web
91      * application root, of the file referenced by the URI.
92      *
93      * @param request the current HttpServletRequest.
94      * @param requestURI the URI for which to get the Struts module path.
95      */

96     public static String JavaDoc getModulePath( HttpServletRequest JavaDoc request, String JavaDoc requestURI )
97     {
98         return getModulePathForRelativeURI( getRelativeURI( request, requestURI, null ) );
99     }
100
101     /**
102      * Get the Struts module path for the current request URI. This is the parent directory,
103      * relative to the web application root, of the file referenced by the request URI.
104      *
105      * @param request the current HttpServletRequest.
106      */

107     public static String JavaDoc getModulePath( HttpServletRequest JavaDoc request )
108     {
109         return getModulePathForRelativeURI( InternalUtils.getDecodedServletPath( request ) );
110     }
111
112     /**
113      * Get the Struts module path for a URI that is relative to the web application root.
114      *
115      * @param uri the URI for which to get the module path.
116      */

117     public static String JavaDoc getModulePathForRelativeURI( String JavaDoc uri )
118     {
119         assert uri.length() > 0;
120         assert uri.charAt( 0 ) == '/' : uri;
121
122         // Strip off the actual page name (e.g., some_page.jsp)
123
int slash = uri.lastIndexOf( '/' );
124         uri = uri.substring( 0, slash );
125
126         return uri;
127     }
128
129     /**
130      * Get the request URI, relative to the URI of the given PageFlowController.
131      *
132      * @param request the current HttpServletRequest.
133      * @param relativeTo a PageFlowController to which the returned URI should be relative, or
134      * <code>null</code> if the returned URI should be relative to the webapp root.
135      */

136     public static final String JavaDoc getRelativeURI( HttpServletRequest JavaDoc request, PageFlowController relativeTo )
137     {
138         if ( relativeTo == null ) return InternalUtils.getDecodedServletPath( request );
139         return getRelativeURI( request, InternalUtils.getDecodedURI( request ), relativeTo );
140     }
141
142     /**
143      * Get a URI relative to the URI of the given PageFlowController.
144      *
145      * @param request the current HttpServletRequest.
146      * @param uri the URI which should be made relative.
147      * @param relativeTo a PageFlowController to which the returned URI should be relative, or
148      * <code>null</code> if the returned URI should be relative to the webapp root.
149      */

150     public static final String JavaDoc getRelativeURI( HttpServletRequest JavaDoc request, String JavaDoc uri, PageFlowController relativeTo )
151     {
152         String JavaDoc contextPath = request.getContextPath();
153         if ( relativeTo != null ) contextPath += relativeTo.getModulePath();
154         int overlap = uri.indexOf( contextPath + '/' );
155         if ( overlap == -1 ) return null;
156         return uri.substring( overlap + contextPath.length() );
157     }
158
159     /**
160      * Get a URI for the "begin" action in the PageFlowController associated with the given
161      * request URI.
162      *
163      * @return a String that is the URI for the "begin" action in the PageFlowController associated
164      * with the given request URI.
165      */

166     public static String JavaDoc getBeginActionURI( String JavaDoc requestURI )
167     {
168         // Translate this to a request for the begin action ("begin.do") for this PageFlowController.
169
InternalStringBuilder retVal = new InternalStringBuilder();
170         int lastSlash = requestURI.lastIndexOf( '/' );
171
172         if ( lastSlash != -1 )
173         {
174             retVal.append( requestURI.substring( 0, lastSlash ) );
175         }
176
177         retVal.append( '/' ).append( BEGIN_ACTION_NAME ).append( ACTION_EXTENSION );
178         return retVal.toString();
179     }
180
181     /**
182      * Get the stack of nested page flows for the current user session. Create and store an empty
183      * stack if none exists.
184      *
185      * @deprecated Use {@link PageFlowStack#get} instead.
186      *
187      * @param request the current HttpServletRequest
188      * @return a {@link PageFlowStack} of nested page flows ({@link PageFlowController}s) for the current user session.
189      */

190     public static final Stack JavaDoc getPageFlowStack( HttpServletRequest JavaDoc request )
191     {
192         return PageFlowStack.get( request, true ).getLegacyStack();
193     }
194     
195     /**
196      * Destroys the stack of {@link PageFlowController}s that have invoked nested page flows.
197      *
198      * @deprecated Use {@link PageFlowStack#destroy} instead.
199      *
200      * @param request the current HttpServletRequest.
201      */

202     public static void destroyPageFlowStack( HttpServletRequest JavaDoc request )
203     {
204         PageFlowStack.destroy( request );
205     }
206     
207     /**
208      * Get the {@link PageFlowController} that is nesting the current one.
209      *
210      * @param request the current HttpServletRequest.
211      * @return the nesting {@link PageFlowController}, or <code>null</code> if the current one
212      * is not being nested.
213      */

214     public static PageFlowController getNestingPageFlow( HttpServletRequest JavaDoc request )
215     {
216         PageFlowStack jpfStack = PageFlowStack.get( request, false );
217         
218         if ( jpfStack != null && ! jpfStack.isEmpty() )
219         {
220             PageFlowController top = jpfStack.peek().getPageFlow();
221             return top;
222         }
223         
224         return null;
225     }
226
227     /**
228      * Get the current PageFlowController.
229      *
230      * @param request the current HttpServletRequest.
231      * @return the current PageFlowController from the user session, or <code>null</code>
232      * if there is none.
233      */

234     public static final PageFlowController getCurrentPageFlow( HttpServletRequest JavaDoc request )
235     {
236         ActionResolver cur = getCurrentActionResolver( request );
237         return cur != null && cur.isPageFlow() ? ( PageFlowController ) cur : null;
238     }
239     
240     /**
241      * Get the current ActionResolver ({@link PageFlowController}).
242      *
243      * @return the current ActionResolver from the user session, or <code>null</code> if there is none.
244      */

245     public static ActionResolver getCurrentActionResolver( HttpServletRequest JavaDoc request )
246     {
247         //
248
// First see if the current page flow is a long-lived, which is stored in its own attribute.
249
//
250
HttpServletRequest JavaDoc unwrappedRequest = unwrapMultipart( request );
251         String JavaDoc currentLongLivedModulePath =
252                 ( String JavaDoc ) ScopedServletUtils.getScopedSessionAttr( CURRENT_LONGLIVED_ATTR, unwrappedRequest );
253         ActionResolver retVal;
254         
255         if ( currentLongLivedModulePath != null )
256         {
257             retVal = getLongLivedPageFlow( currentLongLivedModulePath, unwrappedRequest );
258         }
259         else
260         {
261             retVal = ( ActionResolver ) ScopedServletUtils.getScopedSessionAttr( CURRENT_JPF_ATTR, unwrappedRequest );
262         }
263         
264         return retVal;
265     }
266     
267     /**
268      * Get the current {@link GlobalApp} instance.
269      *
270      * @deprecated Use {@link #getSharedFlow} instead.
271      * @param request the current HttpServletRequest.
272      * @return the current {@link GlobalApp} from the user session, or <code>null</code> if none
273      * exists.
274      */

275     public static GlobalApp getGlobalApp( HttpServletRequest JavaDoc request )
276     {
277         SharedFlowController sf = getSharedFlow( InternalConstants.GLOBALAPP_CLASSNAME, request );
278         return sf instanceof GlobalApp ? ( GlobalApp ) sf : null;
279     }
280
281     /**
282      * Get the a map of shared flow name to shared flow instance, based on the names defined in the
283      * {@link org.apache.beehive.netui.pageflow.annotations.Jpf.Controller#sharedFlowRefs sharedFlowRefs} attribute
284      * of the {@link org.apache.beehive.netui.pageflow.annotations.Jpf.Controller &#64;Jpf.Controller} annotation on the
285      * <strong>current page flow</strong>.
286      *
287      * @param request the current HttpServletRequest, which is used to determine the current page flow.
288      * @return a Map of shared flow name (string) to shared flow instance ({@link SharedFlowController}).
289      */

290     public static Map JavaDoc/*< String, SharedFlowController >*/ getSharedFlows( HttpServletRequest JavaDoc request )
291     {
292         Map JavaDoc/*< String, SharedFlowController >*/ sharedFlows = ImplicitObjectUtil.getSharedFlow( request );
293         return sharedFlows != null ? sharedFlows : Collections.EMPTY_MAP;
294     }
295     
296     /**
297      * Get the shared flow with the given class name.
298      *
299      * @param sharedFlowClassName the class name of the shared flow to remove.
300      * @param request the current HttpServletRequest.
301      * @return the {@link SharedFlowController} of the given class name which is stored in the user session.
302      */

303     public static SharedFlowController getSharedFlow( String JavaDoc sharedFlowClassName, HttpServletRequest JavaDoc request )
304     {
305         HttpSession JavaDoc session = request.getSession( false );
306         
307         if ( session != null )
308         {
309             return ( SharedFlowController ) session.getAttribute( SHARED_FLOW_ATTR_PREFIX + sharedFlowClassName );
310         }
311         
312         return null;
313     }
314     
315     /**
316      * Destroy the current {@link SharedFlowController} of the given class name.
317      * @param sharedFlowClassName the class name of the current SharedFlowController to destroy.
318      * @param request the current HttpServletRequest.
319      */

320     public static void removeSharedFlow( String JavaDoc sharedFlowClassName, HttpServletRequest JavaDoc request )
321     {
322         HttpSession JavaDoc session = request.getSession( false );
323         if ( session != null ) request.getSession().removeAttribute( SHARED_FLOW_ATTR_PREFIX + sharedFlowClassName );
324     }
325     
326     
327     /**
328      * Remove a "long-lived" page flow from the session. Once it is created, a long-lived page flow
329      * is never removed from the session unless this method or {@link PageFlowController#remove} is
330      * called. Navigating to another page flow hides the current long-lived controller, but does not
331      * remove it.
332      */

333     public static void removeLongLivedPageFlow( String JavaDoc modulePath, HttpServletRequest JavaDoc request )
334     {
335         HttpServletRequest JavaDoc unwrappedRequest = unwrapMultipart( request );
336         String JavaDoc attrName = InternalUtils.getLongLivedFlowAttr( modulePath );
337         ScopedServletUtils.removeScopedSessionAttr( attrName, unwrappedRequest );
338
339         //
340
// Now, if the current page flow is long-lived, remove the reference.
341
//
342
String JavaDoc currentLongLivedModulePath =
343                 ( String JavaDoc ) ScopedServletUtils.getScopedSessionAttr( CURRENT_LONGLIVED_ATTR, unwrappedRequest );
344         
345         if ( modulePath.equals( currentLongLivedModulePath ) )
346         {
347             ScopedServletUtils.removeScopedSessionAttr( CURRENT_LONGLIVED_ATTR, unwrappedRequest );
348         }
349     }
350     
351     /**
352      * Get the long-lived page flow instance associated with the given module (directory) path.
353      *
354      * @param modulePath the webapp-relative path to the directory containing the long-lived page flow.
355      * @param request the current HttpServletRequest.
356      * @return the long-lived page flow instance associated with the given module, or <code>null</code> if none is found.
357      */

358     public static PageFlowController getLongLivedPageFlow( String JavaDoc modulePath, HttpServletRequest JavaDoc request )
359     {
360         String JavaDoc attr = InternalUtils.getLongLivedFlowAttr( modulePath );
361         PageFlowController retVal = ( PageFlowController )
362                 ScopedServletUtils.getScopedSessionAttr( attr, unwrapMultipart( request ) );
363         return retVal;
364     }
365     
366     /**
367      * Make any form beans in the given {@link Forward} object available as attributets in the
368      * request/session (as appropriate).
369      *
370      * @param mapping the ActionMapping for the current Struts action being processed.
371      * @param fwd the {@link Forward} object that contains the ActionForm instances to be
372      * made available in the request/session (as appropriate).
373      * @param request the current HttpServletRequest.
374      * @param overwrite if <code>false</code> a form from <code>fwd</code> will only be set
375      * in the request if there is no existing form with the same name.
376      */

377     public static void setOutputForms( ActionMapping mapping, Forward fwd, HttpServletRequest JavaDoc request,
378                                        boolean overwrite )
379     {
380         if ( fwd == null ) return;
381         
382         //
383
// *If* there is a target action mapping, set output forms for it.
384
//
385
if ( mapping != null ) setOutputForms( mapping, fwd.getOutputForms(), request, overwrite );
386         
387         InternalUtils.setForwardedFormBean( request, fwd.getFirstOutputForm( request ) );
388     }
389     
390     /**
391      * Make any form beans in the given {@link Forward} object available as attributets in the
392      * request/session (as appropriate).
393      *
394      * @param mapping the ActionMapping for the current Struts action being processed.
395      * @param fwd the {@link Forward} object that contains the ActionForm instances to be
396      * made available in the request/session (as appropriate).
397      * @param request the current HttpServletRequest.
398      */

399     public static void setOutputForms( ActionMapping mapping, Forward fwd, HttpServletRequest JavaDoc request )
400     {
401         if ( fwd == null )
402         {
403             return;
404         }
405
406         if ( mapping != null )
407         {
408             setOutputForms( mapping, fwd.getOutputForms(), request );
409         }
410
411         InternalUtils.setForwardedFormBean( request, fwd.getFirstOutputForm( request ) );
412     }
413
414     /**
415      * Make a set of form beans available as attributets in the request/session (as appropriate).
416      *
417      * @param mapping the ActionMapping for the current Struts action being processed.
418      * @param outputForms an array of ActionForm instances to be made available in the
419      * request/session (as appropriate).
420      * @param request the current HttpServletRequest.
421      */

422     public static void setOutputForms( ActionMapping mapping, ActionForm[] outputForms,
423                                        HttpServletRequest JavaDoc request )
424     {
425         setOutputForms( mapping, outputForms, request, true );
426     }
427     
428     /**
429      * Make a set of form beans available as attributets in the request/session (as appropriate).
430      *
431      * @param mapping the ActionMapping for the current Struts action being processed.
432      * @param outputForms an array of ActionForm instances to be made available in the
433      * request/session (as appropriate).
434      * @param overwrite if <code>false</code> a form from <code>fwd</code> will only be set
435      * in the request if there is no existing form with the same name.
436      * @param request the current HttpServletRequest.
437      */

438     public static void setOutputForms( ActionMapping mapping, ActionForm[] outputForms,
439                                        HttpServletRequest JavaDoc request, boolean overwrite )
440     {
441         try
442         {
443             //
444
// Now set any output forms in the request or session, as appropriate.
445
//
446
assert mapping.getScope() == null
447                     || mapping.getScope().equals( "request" )
448                     || mapping.getScope().equals( "session" )
449                 : mapping.getScope();
450
451             
452             for ( int i = 0; i < outputForms.length; ++i )
453             {
454                 setOutputForm( mapping, outputForms[i], request, overwrite );
455             }
456         }
457         catch ( Exception JavaDoc e )
458         {
459             _log.error( "Error while setting Struts form-beans", e );
460         }
461     }
462
463     private static List JavaDoc/*< String >*/ getFormNamesFromModuleConfig( String JavaDoc formBeanClassName, ModuleConfig moduleConfig )
464     {
465         String JavaDoc modulePrefix = moduleConfig.getPrefix();
466         Map JavaDoc/*< String, List< String > >*/ formNameMap = ( Map JavaDoc ) _formNameMaps.get( modulePrefix ); // map of form-type-name to form-name
467

468         if ( formNameMap == null )
469         {
470             formNameMap = new HashMap JavaDoc/*< String, List< String > >*/();
471             FormBeanConfig[] formBeans = moduleConfig.findFormBeanConfigs();
472             
473             for ( int j = 0; j < formBeans.length; ++j )
474             {
475                 assert formBeans[j] != null;
476                 String JavaDoc formBeanType = InternalUtils.getFormBeanType( formBeans[j] );
477                 List JavaDoc/*< String >*/ formBeanNames = ( List JavaDoc ) formNameMap.get( formBeanType );
478                 
479                 if ( formBeanNames == null )
480                 {
481                     formBeanNames = new ArrayList JavaDoc/*< String >*/();
482                     formNameMap.put( formBeanType, formBeanNames );
483                 }
484                 
485                 formBeanNames.add( formBeans[j].getName() );
486             }
487             
488             _formNameMaps.put( modulePrefix, formNameMap );
489         }
490         
491         return ( List JavaDoc ) formNameMap.get( formBeanClassName );
492     }
493     
494     /**
495      * Make a form bean available as an attributet in the request/session (as appropriate).
496      *
497      * @param mapping the ActionMapping for the current Struts action being processed.
498      * @param form an ActionForm instance to be made available in the request/session
499      * (as appropriate).
500      * @param overwrite if <code>false</code> a form from <code>fwd</code> will only be set
501      * in the request if there is no existing form with the same name.
502      * @param request the current HttpServletRequest.
503      */

504     public static void setOutputForm( ActionMapping mapping, ActionForm form,
505                                       HttpServletRequest JavaDoc request, boolean overwrite )
506     {
507         if ( form != null )
508         {
509             ModuleConfig moduleConfig = mapping.getModuleConfig();
510             Class JavaDoc formClass = InternalUtils.unwrapFormBean( form ).getClass();
511             
512             //
513
// Get the names of *all* form beans of the desired type, and blast out this instance under all those names.
514
//
515
List JavaDoc/*< String >*/ formNames = getFormNamesFromModuleConfig( formClass.getName(), moduleConfig );
516             
517             if ( formNames == null )
518             {
519                 String JavaDoc formName = generateFormBeanName( formClass, request );
520                 InternalUtils.setFormInScope( formName, form, mapping, request, overwrite );
521             }
522             else
523             {
524                 assert formNames.size() > 0; // getFormNamesFromModuleConfig returns null or a nonempty list
525

526                 for ( Iterator JavaDoc ii = formNames.iterator(); ii.hasNext(); )
527                 {
528                     String JavaDoc formName = ( String JavaDoc ) ii.next();
529                     InternalUtils.setFormInScope( formName, form, mapping, request, overwrite );
530                 }
531             }
532         }
533     }
534     
535     /**
536      * Get the name for the type of a ActionForm instance. Use a name looked up from
537      * the current Struts module, or, if none is found, create one.
538      *
539      * @param formInstance the ActionForm instance whose type will determine the name.
540      * @param request the current HttpServletRequest, which contains a reference to the current Struts module.
541      * @return the name found in the Struts module, or, if none is found, a name that is either:
542      * <ul>
543      * <li>a camel-cased version of the base class name (minus any package or outer-class
544      * qualifiers, or, if that name is already taken,</li>
545      * <li>the full class name, with '.' and '$' replaced by '_'.</li>
546      * </ul>
547      */

548     public static String JavaDoc getFormBeanName( ActionForm formInstance, HttpServletRequest JavaDoc request )
549     {
550         return getFormBeanName( formInstance.getClass(), request );
551     }
552
553     /**
554      * Get the name for an ActionForm type. Use a name looked up from the current Struts module, or,
555      * if none is found, create one.
556      *
557      * @param formBeanClass the ActionForm-derived class whose type will determine the name.
558      * @param request the current HttpServletRequest, which contains a reference to the current Struts module.
559      * @return the name found in the Struts module, or, if none is found, a name that is either:
560      * <ul>
561      * <li>a camel-cased version of the base class name (minus any package or outer-class
562      * qualifiers, or, if that name is already taken,</li>
563      * <li>the full class name, with '.' and '$' replaced by '_'.</li>
564      * </ul>
565      */

566     public static String JavaDoc getFormBeanName( Class JavaDoc formBeanClass, HttpServletRequest JavaDoc request )
567     {
568         ModuleConfig moduleConfig = RequestUtils.getRequestModuleConfig( request );
569         List JavaDoc/*< String >*/ names = getFormNamesFromModuleConfig( formBeanClass.getName(), moduleConfig );
570         
571         if ( names != null )
572         {
573             assert names.size() > 0; // getFormNamesFromModuleConfig returns null or a nonempty list
574
return ( String JavaDoc ) names.get( 0 );
575         }
576         
577         return generateFormBeanName( formBeanClass, request );
578     }
579
580     /**
581      * Create the name for a form bean type.
582      *
583      * @param formBeanClass the class whose type will determine the name.
584      * @param request the current HttpServletRequest, which contains a reference to the current Struts module.
585      * @return the name found in the Struts module, or, if none is found, a name that is either:
586      * <ul>
587      * <li>a camel-cased version of the base class name (minus any package or outer-class
588      * qualifiers, or, if that name is already taken,</li>
589      * <li>the full class name, with '.' and '$' replaced by '_'.</li>
590      * </ul>
591      */

592     private static String JavaDoc generateFormBeanName( Class JavaDoc formBeanClass, HttpServletRequest JavaDoc request )
593     {
594         ModuleConfig moduleConfig = RequestUtils.getRequestModuleConfig( request );
595         String JavaDoc formBeanClassName = formBeanClass.getName();
596         
597         //
598
// A form-bean wasn't found for this type, so we'll create a name. First try and create
599
// name that is a camelcased version of the classname without all of its package/outer-class
600
// qualifiers. If one with that name already exists, munge the fully-qualified classname.
601
//
602
String JavaDoc formType = formBeanClassName;
603         int lastQualifier = formType.lastIndexOf( '$' );
604
605         if ( lastQualifier == -1 )
606         {
607             lastQualifier = formType.lastIndexOf( '.' );
608         }
609
610         String JavaDoc formName = formType.substring( lastQualifier + 1 );
611         formName = Character.toLowerCase( formName.charAt( 0 ) ) + formName.substring( 1 );
612
613         if ( moduleConfig.findFormBeanConfig( formName ) != null )
614         {
615             formName = formType.replace( '.', '_' ).replace( '$', '_' );
616             assert moduleConfig.findFormBeanConfig( formName ) == null : formName;
617         }
618         
619         return formName;
620     }
621     
622     /**
623      * Get the class name of a {@link PageFlowController}, given the URI to it.
624      *
625      * @param uri the URI to the {@link PageFlowController}, which should be relative to the
626      * web application root (i.e., it should not include the context path).
627      */

628     public static String JavaDoc getPageFlowClassName( String JavaDoc uri )
629     {
630         assert uri != null;
631         assert uri.length() > 0;
632         
633         if ( uri.charAt( 0 ) == '/' ) uri = uri.substring( 1 );
634         
635         assert FileUtils.osSensitiveEndsWith( uri, PAGEFLOW_EXTENSION ) : uri;
636         if ( FileUtils.osSensitiveEndsWith( uri, PAGEFLOW_EXTENSION ) )
637         {
638             uri = uri.substring( 0, uri.length() - PAGEFLOW_EXTENSION_LEN );
639         }
640         
641         return uri.replace( '/', '.' );
642     }
643     
644     /**
645      * Get the class name of a {@link PageFlowController}, given the URI to it.
646      *
647      * @deprecated Use {@link #getPageFlowClassName(String)} instead.
648      *
649      * @param uri the URI to the {@link PageFlowController}, which should be relative to the
650      * web application root (i.e., it should not include the context path).
651      */

652     public static String JavaDoc getJpfClassName( String JavaDoc uri )
653     {
654         return getPageFlowClassName( uri );
655     }
656     
657     /**
658      * Get the URI for a {@link PageFlowController}, given its class name.
659      *
660      * @param className the name of the {@link PageFlowController} class.
661      * @return a String that is the URI for the {@link PageFlowController}, relative to the web
662      * application root (i.e., not including the context path).
663      */

664     public static String JavaDoc getPageFlowURI( String JavaDoc className )
665     {
666         return '/' + className.replace( '.', '/' ) + PAGEFLOW_EXTENSION;
667     }
668     
669     /**
670      * @deprecated Use {@link PageFlowActionServlet#getModuleConfPath} instead.
671      *
672      * Get the path to the Struts module configration file (e.g.,
673      * "/WEB-INF/.pageflow-struts-generated/jpf-struts-config-someModule") for a given module
674      * path (e.g., "someModule"), according to the PageFlow convention.
675      *
676      * @param modulePath the Struts module path.
677      * @return a String that is the path to the Struts configuration file, relative to the
678      * web application root.
679      */

680     public static String JavaDoc getModuleConfPath( String JavaDoc modulePath )
681     {
682         return new PageFlowActionServlet.DefaultModuleConfigLocator().getModuleConfigPath( modulePath );
683     }
684     
685
686     /**
687      * Get the most recent action URI that was processed by {@link FlowController#execute}.
688      *
689      * @param request the current ServletRequest.
690      * @return a String that is the most recent action URI. This is only valid during a request
691      * that has been forwarded from the action URI.
692      */

693     public static String JavaDoc getActionURI( ServletRequest JavaDoc request )
694     {
695         return ( String JavaDoc ) request.getAttribute( ACTION_URI_ATTR );
696     }
697     
698     /**
699      * Sets the most recent action URI that was processed by {@link FlowController#execute}.
700      */

701     static void setActionURI( HttpServletRequest JavaDoc request )
702     {
703         request.setAttribute( ACTION_URI_ATTR, InternalUtils.getDecodedURI( request ) );
704     }
705     
706     /**
707      * Tell whether a web application resource requires a secure transport protocol. This is
708      * determined from web.xml; for example, the following block specifies that all resources under
709      * /login require a secure transport protocol.
710      * <pre>
711      * &lt;security-constraint&gt;
712      * &lt;web-resource-collection&gt;
713      * &lt;web-resource-name&gt;Secure PageFlow - begin&lt;/web-resource-name&gt;
714      * &lt;url-pattern&gt;/login/*&lt;/url-pattern&gt;
715      * &lt;/web-resource-collection&gt;
716      * &lt;user-data-constraint&gt;
717      * &lt;transport-guarantee&gt;CONFIDENTIAL&lt;/transport-guarantee&gt;
718      * &lt;/user-data-constraint&gt;
719      * &lt;/security-constraint&gt;
720      * </pre>
721      *
722      * @param uri a webapp-relative URI for a resource. There must not be query parameters or a scheme
723      * on the URI.
724      * @param request the current request.
725      * @return <code>Boolean.TRUE</code> if a transport-guarantee of <code>CONFIDENTIAL</code> or
726      * <code>INTEGRAL</code> is associated with the given resource; <code>Boolean.FALSE</code>
727      * a transport-guarantee of <code>NONE</code> is associated with the given resource; or
728      * <code>null</code> if there is no transport-guarantee associated with the given resource.
729      */

730     public static SecurityProtocol getSecurityProtocol( String JavaDoc uri, ServletContext JavaDoc servletContext,
731                                                         HttpServletRequest JavaDoc request )
732     {
733         return AdapterManager.getServletContainerAdapter( servletContext ).getSecurityProtocol( uri, request );
734     }
735     
736     /**
737      * @deprecated Use {@link #getSecurityProtocol(String, ServletContext, HttpServletRequest)} instead.
738      */

739     public static Boolean JavaDoc isSecureResource( String JavaDoc uri, ServletContext JavaDoc context )
740     {
741         // TODO: once DefaultServletContainerAdapter has this functionality, delegate to it.
742
return null;
743     }
744
745     /**
746      * Set a named action output, which corresponds to an input declared by the <code>pageInput</code> JSP tag.
747      * The actual value can be read from within a JSP using the <code>"pageInput"</code> databinding context.
748      *
749      * @deprecated Use {@link #addActionOutput} instead.
750      * @param name the name of the action output.
751      * @param value the value of the action output.
752      * @param request the current ServletRequest.
753      */

754     public static void addPageInput( String JavaDoc name, Object JavaDoc value, ServletRequest JavaDoc request )
755     {
756         addActionOutput( name, value, request );
757     }
758     
759     /**
760      * Set a named action output, which corresponds to an input declared by the <code>pageInput</code> JSP tag.
761      * The actual value can be read from within a JSP using the <code>"pageInput"</code> databinding context.
762      *
763      * @param name the name of the action output.
764      * @param value the value of the action output.
765      * @param request the current ServletRequest.
766      */

767     public static void addActionOutput( String JavaDoc name, Object JavaDoc value, ServletRequest JavaDoc request )
768     {
769         Map JavaDoc map = InternalUtils.getActionOutputMap( request, true );