KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > apache > beehive > netui > tags > html > Form


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.tags.html;
19
20 import org.apache.beehive.netui.util.internal.InternalStringBuilder;
21
22 import org.apache.beehive.netui.core.urls.MutableURI;
23 import org.apache.beehive.netui.core.urls.URIContext;
24 import org.apache.beehive.netui.core.urls.URLType;
25 import org.apache.beehive.netui.core.urls.URLRewriterService;
26 import org.apache.beehive.netui.pageflow.FlowController;
27 import org.apache.beehive.netui.pageflow.PageFlowUtils;
28 import org.apache.beehive.netui.pageflow.handler.Handlers;
29 import org.apache.beehive.netui.pageflow.internal.InternalConstants;
30 import org.apache.beehive.netui.pageflow.internal.InternalUtils;
31 import org.apache.beehive.netui.pageflow.internal.URIContextFactory;
32 import org.apache.beehive.netui.pageflow.scoping.ScopedServletUtils;
33 import org.apache.beehive.netui.script.common.ImplicitObjectUtil;
34 import org.apache.beehive.netui.tags.TagConfig;
35 import org.apache.beehive.netui.tags.internal.PageFlowTagUtils;
36 import org.apache.beehive.netui.tags.javascript.CoreScriptFeature;
37 import org.apache.beehive.netui.tags.javascript.IScriptReporter;
38 import org.apache.beehive.netui.tags.javascript.ScriptRequestState;
39 import org.apache.beehive.netui.tags.rendering.*;
40 import org.apache.beehive.netui.util.Bundle;
41 import org.apache.beehive.netui.util.ParamHelper;
42 import org.apache.beehive.netui.util.logging.Logger;
43 import org.apache.struts.Globals;
44 import org.apache.struts.action.ActionForm;
45 import org.apache.struts.action.ActionMapping;
46 import org.apache.struts.action.ActionServlet;
47 import org.apache.struts.config.FormBeanConfig;
48 import org.apache.struts.config.ModuleConfig;
49 import org.apache.struts.taglib.html.Constants;
50
51 import javax.servlet.ServletContext JavaDoc;
52 import javax.servlet.ServletRequest JavaDoc;
53 import javax.servlet.http.HttpServletRequest JavaDoc;
54 import javax.servlet.http.HttpServletResponse JavaDoc;
55 import javax.servlet.http.HttpSession JavaDoc;
56 import javax.servlet.jsp.JspException JavaDoc;
57 import javax.servlet.jsp.PageContext JavaDoc;
58 import java.net.URISyntaxException JavaDoc;
59 import java.util.*;
60
61 /**
62  * This tag represents an input form, associated with a bean whose
63  * properties correspond to the various fields of the form.
64  * @jsptagref.tagdescription Renders an HTML form that can be submitted to a Java method
65  * in the Controller file for processesing.
66  *
67  * <p><b>Submitting Data</b></p>
68  *
69  * <p>When a &lt;netui:form> is submitted, the form data is passed to a method
70  * for processessing. The data is passed as a Form Bean instance.
71  * The &lt;netui:form>'s input fields correspond to the properties of the Form Bean.
72  * When the form is submitted the following sequence of events occurs:
73  * (1) a new Form Bean instance is created, (2) the form data is loaded into the
74  * corresponding Form Bean properties,
75  * and (3) the Form Bean instance is passed to the method
76  * where the data is processed.
77  *
78  * <p>The <code>action</code> attribute determines the target method of the submission.
79  * The parameter of the target method determines the Form Bean instance
80  * that carries the submitted data.
81  *
82  * <p>For example, if a &lt;netui:form>'s target method is <code>someAction</code> ...
83  *
84  * <pre> &lt;netui:form action="<b>someAction</b>">
85  * //
86  * // input fields go here
87  * //
88  * &lt;netui:button value="Submit" type="submit"/>
89  * &lt;/netui:form></pre>
90  *
91  * <p>...and the <code>someAction</code> method takes a Form Bean parameter of
92  * type <code>SomeFormBean</code>...
93  *
94  * <pre> &#x40;Jpf.Action(
95  * forwards={
96  * &#x40;Jpf.Forward(name="success", path="showData.jsp")
97  * }
98  * )
99  * protected Forward someAction(<b>SomeFormBean form</b>)</pre>
100  *
101  * <p>...then an instance of <code>SomeFormBean</code> will carry the submitted data.
102  *
103  * <p><b>Pre-populating Form Fields with the Session Object</b></p>
104  *
105  * <p>The <code>name</code>, <code>type</code>, and <code>scope</code> attributes can
106  * be used together to pre-populate
107  * the form fields with default values when they are first rendered in the browser.
108  *
109  * <p>In the Controller file, instantiate the appropriate Form Bean, set default values, and
110  * store the Form Bean instance in the Session object.
111  *
112  * <pre> protected void onCreate()
113  * {
114  * // Create a new Form Bean instance
115  * ProcessDataForm formInstance = new ProcessDataForm();
116  *
117  * // Set default values.
118  * formInstance.setAge(32);
119  * formInstance.setName("John");
120  *
121  * // Store the instance in the Session object.
122  * getSession().setAttribute("defaultValues", formInstance);
123  * }</pre>
124  *
125  * <p>Then, use the <code>name</code>, <code>type</code>, and <code>scope</code> attributes to pre-populate the
126  * form fields.
127  *
128  * <pre> &lt;netui:form
129  * action="processData"
130  * name="defaultValues"
131  * type="tagSamples.netui.form.FormController$ProcessDataForm"
132  * scope="session"></pre>
133  *
134  * <p><b>Note:</b> when the data is submitted, the data is passed as a Request-scoped Form
135  * Bean, *not* as the Session-scoped Form Bean used to pre-populate the fields. However, you
136  * may pass the data as a Page Flow-scoped Form Bean, if the annotation
137  * <code>{@link org.apache.beehive.netui.pageflow.annotations.Jpf.Action &#64;Jpf.Action}(
138  * {@link org.apache.beehive.netui.pageflow.annotations.Jpf.Action#useFormBean useFormBean}="someFormBeanMemberVariable"
139  * </code>...<code>)</code> is set on the receiving method.
140  *
141  * <p><b>Pre-populating Form Fields By Passing a Form Bean Instance to the JSP Page</b></p>
142  *
143  * <p>As an alternative to the pre-population technique above, you can set the
144  * pre-population values in a Form Bean instance and then pass that instance to the JSP page.
145  * For example, assume that index.jsp contains the &lt;netui:form> and input elements.
146  * The following action method sets the pre-population values in a Form Bean instance
147  * and passes that instance to the
148  * &lt;netui:form> and its input elements.
149  * Note that the Forward object returned by the method has two parameters, the String "success"
150  * and the pre-populated form.
151  *
152  * <pre> &#x40;Jpf.Action(
153  * forwards={
154  * &#x40;Jpf.Forward(name="success", path="index.jsp")
155  * }
156  * )
157  * protected Forward begin(ProcessDataForm form)
158  * {
159  * form.setAge(44);
160  * form.setName("Mark");
161  * return new Forward("success", form);
162  * }</pre>
163  * @example In this first sample, the
164  * &lt;netui:form> tag invokes the <code>processData</code>
165  * action method in the Controller file when the form is submitted.
166  * <pre> &lt;netui:form action="processData">
167  * Name:
168  * &lt;netui:textBox dataSource="actionForm.name"/>
169  * Age:
170  * &lt;netui:textBox dataSource="actionForm.age"/>
171  * &lt;netui:button value="Submit" type="submit"/>
172  * &lt;/netui:form></pre>
173  *
174  * <p> Notice that the processData action method takes a parameter of
175  * type <code>ProcessDataForm</code>.</p>
176  * <pre> &#x40;Jpf.Action(
177  * forwards={
178  * &#x40;Jpf.Forward(name="success", path="showData.jsp")
179  * }
180  * )
181  * protected Forward processData(ProcessDataForm form)
182  * {
183  * //
184  * // Process the submitted data here.
185  * //
186  *
187  * return new Forward("success");
188  * }</pre>
189  *
190  * <p>This means that the submitted data is loaded into an
191  * instance of ProcessDataForm before
192  * it is passed to the action method.
193  *
194  * <p>In this next sample, the form fields are pre-populated based upon default values
195  * stored in the Session object.
196  * <pre>
197  * &lt;netui:form action="Action" type="corp.Controller$NameBean"
198  * scope="session" name="nameBean">
199  * Name: &lt;netui:textBox dataSource="actionForm.name" />
200  * &lt;netui:button value="Submit"/>
201  * &lt;/netui:form></pre>
202  * @netui:tag name="form" description="Represents an input form, associated with a bean whose properties correspond to the various fields of the form."
203  */

204 public class Form extends HtmlBaseTag
205         implements IUrlParams
206 {
207     private static final Logger logger = Logger.getInstance(Form.class);
208
209     // unique name of the form
210
private static String JavaDoc FORM_ID = "Netui_Form_";
211
212     // The form state
213
private FormTag.State _state = new FormTag.State();
214
215     // state variable for any hidden values
216
private InputHiddenTag.State _hiddenState = new InputHiddenTag.State();
217
218     private String JavaDoc _focus = null; // The name of the field to receive focus, if any.
219
private String JavaDoc _location = null; // The location hash to append to the url.
220
private String JavaDoc _text = null; // The body content of this tag (if any).
221

222     private String JavaDoc _beanName = null; // The name of the form bean to (create and) use.
223
private boolean _explicitBeanType = false; // Flag indicating that the BeanType was set by setting the attribute
224
private String JavaDoc _beanType = null; // The type of the form bean to (create and) use.
225
private String JavaDoc _beanScope = null; // The scope of the form bean to (create and) use.
226

227     private String JavaDoc _realName = null; // This is the real name of the form if it is to be output
228
private boolean _setRealName = false; // Force the RealName to be output. Contained tags can cause this
229

230     private String JavaDoc _targetScope; // target page flow scope; see comments on setTargetScope()
231

232     private ActionMapping _mapping = null; // The ActionMapping defining where we will be submitting this form
233
private ActionServlet _servlet = null; // The ActionServlet instance we are associated with
234
private HashMap _focusMap; // Map allowing setting focus on one of the controls
235
private ModuleConfig _appConfig = null; // The application configuration for our module.
236
private FlowController _flowController = null; // The flow controller (page flow or shared flow).
237
private boolean _formSubmit = false;
238     private Map _params;
239     private String JavaDoc _actionUrl; // The generated action URL.
240
private LinkedHashMap/*<String, List<String>>*/ _extraHiddenParams = null; // hidden form fields based on URL parameters
241

242     /**
243      * Return the name of the Tag.
244      */

245     public String JavaDoc getTagName()
246     {
247         return "Form";
248     }
249
250     /**
251      * This method will return the state associated with the tag. This is used by this
252      * base class to access the individual state objects created by the tags.
253      * @return a subclass of the <code>AbstractHtmlState</code> class.
254      */

255     protected AbstractHtmlState getState()
256     {
257         return _state;
258     }
259
260     /**
261      * Base support for the attribute tag. This is overridden to prevent setting the <code>action</code>,
262      * and <code>method</code> attributes.
263      * @param name The name of the attribute. This value may not be null or the empty string.
264      * @param value The value of the attribute. This may contain an expression.
265      * @param facet The name of a facet to which the attribute will be applied. This is optional.
266      * @throws JspException A JspException may be thrown if there is an error setting the attribute.
267      */

268     public void setAttribute(String JavaDoc name, String JavaDoc value, String JavaDoc facet)
269             throws JspException JavaDoc
270     {
271         if (name != null) {
272             if (name.equals(ACTION) || name.equals(METHOD)) {
273                 String JavaDoc s = Bundle.getString("Tags_AttributeMayNotBeSet", new Object JavaDoc[]{name});
274                 registerTagError(s, null);
275             }
276         }
277         super.setAttribute(name, value, facet);
278     }
279
280     /**
281      * Return the action of the Form.
282      * @return a String representing the action name of the Form.
283      */

284     public String JavaDoc getAction()
285     {
286         return _state.action;
287     }
288
289     /**
290      * Set the name of the action for the Form.
291      * @param action the name of the action to set for the Form.
292      * @jsptagref.attributedescription Required. The action method invoked on form submit. Form data is passed to this method.
293      * @jsptagref.databindable false
294      * @jsptagref.attributesyntaxvalue <i>string_action</i>
295      * @netui:attribute required="true" rtexprvalue="true"
296      * description="The action method invoked on form submit. Form data is passed to this method."
297      */

298     public void setAction(String JavaDoc action)
299             throws JspException JavaDoc
300     {
301         _state.action = setRequiredValueAttribute(action, "action");
302     }
303
304     /**
305      * Set the content encoding to be used on a post submit.
306      * @param enctype the content encoding type.
307      * @jsptagref.attributedescription The content encoding to be used on a POST submit.
308      * @jsptagref.databindable false
309      * @jsptagref.attributesyntaxvalue <i>string_enctype</i>
310      * @netui:attribute required="false" rtexprvalue="true"
311      * description="The content encoding to be used on a POST submit."
312      */

313     public void setEnctype(String JavaDoc enctype)
314     {
315         _state.registerAttribute(AbstractHtmlState.ATTR_GENERAL, ENCTYPE, enctype);
316     }
317
318     /**
319      * This method will return the real id that will be written out by the form. This is
320      * either the current state qualified tagId or the _realName if tagId is not specified.
321      * @return the value of the id attribute written by the form.
322      */

323     public String JavaDoc getRealFormId()
324     {
325         return _realName;
326     }
327
328     /**
329      * This method will insure that a real id is written out even if a tagId is not
330      * set for the form.
331      */

332     public void insureRealId()
333     {
334         _setRealName = true;
335     }
336
337     /**
338      * Set the name of the field to receive focus.
339      * @param focus the focus field name.
340      * @jsptagref.attributedescription The <code>tagID</code> of an input field which should receive initial focus.
341      * @jsptagref.databindable false
342      * @jsptagref.attributesyntaxvalue <i>string_focus</i>
343      * @netui:attribute required="false" rtexprvalue="true"
344      * description="The tagID of an input field which should receive initial focus."
345      */

346     public void setFocus(String JavaDoc focus)
347     {
348         _focus = setNonEmptyValueAttribute(focus);
349         insureRealId();
350     }
351
352     /**
353      * Get the focus flag.
354      * @return <code>true</code> if the focus has been set. <code>false</code> otherwise.
355      */

356     public boolean isFocusSet() {
357         return (_focus != null);
358     }
359
360     /**
361      * Set the location hash to append to the url.
362      * @param location the location hash
363      * @jsptagref.attributedescription The location hash to append to the URL.
364      * @jsptagref.databindable false
365      * @jsptagref.attributesyntaxvalue <i>string_location</i>
366      * @netui:attribute required="false" rtexprvalue="true"
367      * description="The location hash to append to the URL."
368      */

369     public void setLocation(String JavaDoc location)
370     {
371         _location = location;
372     }
373
374     /**
375      * Return the value of the location.
376      * @return The value of the location.
377      */

378     public String JavaDoc getLocation() {
379         return _location;
380     }
381
382     /**
383      * Set the request method used when submitting this form.
384      * @param method the request method
385      * @jsptagref.attributedescription The request method used when submitting this form.
386      * @jsptagref.databindable false
387      * @jsptagref.attributesyntaxvalue <i>string_method</i>
388      * @netui:attribute required="false" rtexprvalue="true"
389      * description="The request method used when submitting this form."
390      */

391     public void setMethod(String JavaDoc method)
392             throws JspException JavaDoc
393     {
394         if (FORM_POST.equals(method) || FORM_GET.equals(method)) {
395             _state.method = method;
396             return;
397         }
398         String JavaDoc s = Bundle.getString("Tags_FormMethodError", new Object JavaDoc[]{method});
399         registerTagError(s, null);
400     }
401
402     /**
403      * Set the attribute key under which our associated bean is stored.
404      * @param name the attribute key name
405      * @jsptagref.attributedescription The attribute key under which the associated Form Bean used to populate the input form is stored.
406      * This Form Bean is found in the scope defined by the <code>scope</code> attribute.
407      * @jsptagref.databindable false
408      * @jsptagref.attributesyntaxvalue <i>string_name</i>
409      * @netui:attribute required="false" rtexprvalue="true"
410      * description="The attribute key under which the associated Form Bean used to populate the input form is stored.
411      * This Form Bean is found in the scope defined by the scope attribute."
412      */

413     public void setBeanName(String JavaDoc name)
414             throws JspException JavaDoc
415     {
416         // @todo: we need to verify what happens if this is null and type is set.
417
_beanName = setRequiredValueAttribute(name, "beanName");
418     }
419
420     /**
421      * Set the target "scope" for the form's action. Multiple active page flows may exist concurrently within named
422      * scopes. This attribute selects which named scope to use. If omitted, the default scope is assumed.
423      * @param targetScope the name of the target scope in which the associated action's page flow resides.
424      * @jsptagref.attributedescription The target scope in which the associated action's page flow resides.
425      * @jsptagref.databindable true
426      * @jsptagref.attributesyntaxvalue <i>string_targetScope</i>
427      * @netui:attribute required="false" rtexprvalue="true"
428      * description="The target scope in which the associated action's page flow resides"
429      */

430     public void setTargetScope(String JavaDoc targetScope)
431     {
432         _targetScope = targetScope;
433     }
434
435     /**
436      * Sets the onReset javascript event.
437      * @param onReset the onReset event.
438      * @jsptagref.attributedescription The JavaScript onReset event.
439      * @jsptagref.databindable false
440      * @jsptagref.attributesyntaxvalue <i>string_onSubmit</i>
441      * @netui:attribute required="false" rtexprvalue="true"
442      * description="The JavaScript onReset event."
443      */

444     public void setOnReset(String JavaDoc onReset)
445     {
446         _state.registerAttribute(AbstractHtmlState.ATTR_JAVASCRIPT, ONRESET, onReset);
447     }
448
449     /**
450      * Sets the onSubmit javascript event.
451      * @param onSubmit the onReset event.
452      * @jsptagref.attributedescription The JavaScript onSubmit event.
453      * @jsptagref.databindable false
454      * @jsptagref.attributesyntaxvalue <i>string_onSumbit</i>
455      * @netui:attribute required="false" rtexprvalue="true"
456      * description="The JavaScript onSubmit event."
457      */

458     public void setOnSubmit(String JavaDoc onSubmit)
459     {
460         _state.registerAttribute(AbstractHtmlState.ATTR_JAVASCRIPT, ONSUBMIT, onSubmit);
461     }
462
463     /**
464      * Sets the scope (request or session) under which the associated bean
465      * is stored.
466      * @param scope the scope.
467      * @jsptagref.attributedescription The scope (<code>request</code> or <code>session</code>) under which the associated Form Bean
468      * used to populate the form input fields is stored.
469      * Using the <code>name</code>, <code>type</code> and <code>scope</code> attributes defines
470      * the Form Bean used.
471      * @jsptagref.databindable false
472      * @jsptagref.attributesyntaxvalue <i>string_scope</i>
473      * @netui:attribute required="false" rtexprvalue="true"
474      * description="The scope (request or session) under which the associated Form Bean
475      * used to populate the form input fields is stored.
476      * Using the name, type and scope attributes defines
477      * the Form Bean used."
478      */

479     public void setBeanScope(String JavaDoc scope)
480             throws JspException JavaDoc
481     {
482         _beanScope = setRequiredValueAttribute(scope, "beanScope");
483     }
484
485     /**
486      * Sets the window target.
487      * @param target the window target.
488      * @jsptagref.attributedescription The window target
489      * @jsptagref.databindable false
490      * @jsptagref.attributesyntaxvalue <i>string_windowTarget</i>
491      * @netui:attribute required="false" rtexprvalue="true"
492      * description="The window target"
493      */

494     public void setTarget(String JavaDoc target)
495     {
496         _state.registerAttribute(AbstractHtmlState.ATTR_GENERAL, TARGET, target);
497     }
498
499     /**
500      * Sets the Java class name of the bean to be created, if necessary.
501      * @param type the class name
502      * @jsptagref.attributedescription The Java class name of the Form Bean to be created, if necessary.
503      * This Form Bean will be created if the <code>name</code> and <code>scope</code> attributes are set.
504      * The Form Bean is then used to populate the form input fields.
505      * @jsptagref.databindable false
506      * @jsptagref.attributesyntaxvalue <i>string_type</i>
507      * @netui:attribute required="false" rtexprvalue="true"
508      * description="The Java class name of the Form Bean to be created, if necessary.
509      * This Form Bean will be created if the name and scope attributes are set.
510      * The Form Bean is then used to populate the form input fields."
511      */

512     public void setBeanType(String JavaDoc type)
513             throws JspException JavaDoc
514     {
515         _beanType = setRequiredValueAttribute(type, "beanType");
516         _explicitBeanType = true;
517     }
518
519     /**
520      * Generate the JavaScript which will submit a form. This is usually generated if the
521      * form contains anchors that are used to submit the form. This will make sure the JavaScript is
522      * always generated.
523      * @param formSubmit boolean value indicating that the form submit JavaScript should be generated. Default is false.
524      * @jsptagref.attributedescription Generate the form submit JavaScript even if the form does not
525      * contain anchors. Default is <code>false</code>.
526      * @jsptagref.databindable false
527      * @jsptagref.attributesyntaxvalue <i>boolean_formSubmit</i>
528      * @netui:attribute required="false" rtexprvalue="true" type="boolean"
529      * description="Generate the form submit JavaScript even if the form does not contain anchors."
530      */

531     public void setGenJavaScriptFormSubmit(boolean formSubmit)
532     {
533         _formSubmit = formSubmit;
534         _setRealName = true;
535     }
536
537     /**
538      * Adds a URL parameter to the generated hyperlink.
539      * @param name the name of the parameter to be added.
540      * @param value the value of the parameter to be added (a String or String[]).
541      * @param facet
542      */

543     public void addParameter(String JavaDoc name, Object JavaDoc value, String JavaDoc facet) throws JspException JavaDoc
544     {
545         assert(name != null) : "Parameter 'name' must not be null";
546
547         if (_params == null) {
548             _params = new HashMap();
549         }
550         ParamHelper.addParam(_params, name, value);
551     }
552
553     /**
554      * Adds a tagId and name to the Form's focusMap.
555      * @param tagID the tagID of a child tag.
556      * @param name the name of a child tag.
557      */

558     public void addTagID(String JavaDoc tagID, String JavaDoc name)
559     {
560         if (_focusMap == null) {
561             _focusMap = new HashMap();
562         }
563         _focusMap.put(tagID, name);
564     }
565
566     //********************************************* Do the Work *******************************************************
567
/**
568      * Render the beginning of this form.
569      * @throws JspException if a JSP exception has occurred
570      */

571     public int doStartTag() throws JspException JavaDoc
572     {
573         if (hasErrors())
574             return SKIP_BODY;
575         
576         // Error out if there is a parent form
577
if (getNearestForm() != null) {
578             registerTagError(Bundle.getString("Tags_FormParentForm"), null);
579         }
580
581         // Look up the form bean name, scope, and type if necessary
582
HttpServletRequest JavaDoc request = (HttpServletRequest JavaDoc) pageContext.getRequest();
583         ServletContext JavaDoc servletContext = pageContext.getServletContext();
584
585         // find the beanName, beanType and beanScope
586
lookupBeanScopeAndName(request, servletContext);
587         if (hasErrors())
588             return SKIP_BODY;
589
590         // Generate the real name. We generate it here so we can return it to any contained tags if
591
// they need it. If they access it, the most likely will cause the realName to be output
592
if (_state.id != null) {
593             _realName = getIdForTagId(_state.id);
594         }
595         else {
596             String JavaDoc formId = FORM_ID + getNextId(request);
597             _realName = getIdForTagId(formId);
598         }
599
600         // Store this tag itself as a page attribute
601
pageContext.setAttribute(Constants.FORM_KEY, this, PageContext.REQUEST_SCOPE);
602
603         // Locate or create the bean associated with our form
604
int scope = PageContext.SESSION_SCOPE;
605         if ("request".equals(_beanScope)) {
606             scope = PageContext.REQUEST_SCOPE;
607         }
608
609         // setup the Bean
610
Object JavaDoc bean = null;
611         if (_beanName != null)
612             bean = pageContext.getAttribute(_beanName, scope);
613         if (bean == null) {
614             if (_explicitBeanType) {
615                 // Backwards compatibility - use explicitly specified values
616
try {
617                     Handlers handlers = Handlers.get(pageContext.getServletContext());
618                     bean = handlers.getReloadableClassHandler().newInstance(_beanType);
619                     if (bean != null) {
620                         ((ActionForm) bean).setServlet(_servlet);
621                     }
622                 }
623                 catch (Exception JavaDoc e) {
624                     registerTagError(Bundle.getString("Tags_FormNameBadType"), e);
625                 }
626             }
627             else {
628                 // New and improved - use the values from the action mapping
629

630                 // First, check to see if this is a page flow-scoped form bean. If so, use the current value
631
// from the member field in the page flow (or shared flow).
632
if (_flowController != null) {
633                     bean = _flowController.getFormBean(_mapping);
634                 }
635
636                 if (bean == null) {
637                     bean = InternalUtils.createActionForm(_mapping, _appConfig, _servlet, servletContext);
638                 }
639             }
640
641             if (hasErrors())
642                 return SKIP_BODY;
643
644             // Call the reset method if we have an ActionForm
645
if (bean instanceof ActionForm) {
646                 ((ActionForm) bean).reset(_mapping, request);
647             }
648             if (bean != null) {
649                 pageContext.setAttribute(_beanName, bean, scope);
650             }
651         }
652         if (bean != null) {
653             pageContext.setAttribute(Constants.BEAN_KEY, bean, PageContext.REQUEST_SCOPE);
654             ImplicitObjectUtil.loadActionForm(pageContext, bean);
655         }
656         
657         // Create the action URL here, so child tags can access it.
658
try {
659             HttpServletResponse JavaDoc response = (HttpServletResponse JavaDoc) pageContext.getResponse();
660             _extraHiddenParams = new LinkedHashMap/*<String, List<String>>*/();
661             _actionUrl = rewriteActionURL(servletContext, request, response, _extraHiddenParams);
662         }
663         catch (URISyntaxException JavaDoc e) {
664             // report the error...
665
logger.error(Bundle.getString("Tags_URISyntaxException"));
666             String JavaDoc s = Bundle.getString("Tags_Form_URLException",
667                     new Object JavaDoc[]{_state.action, e.getMessage()});
668             registerTagError(s, e);
669         }
670
671         // Continue processing this page
672
return EVAL_BODY_BUFFERED;
673     }
674
675     /**
676      * Save the body content of the Form.
677      * @throws JspException if a JSP exception has occurred
678      */

679     public int doAfterBody() throws JspException JavaDoc
680     {
681         if (bodyContent != null) {
682             String JavaDoc value = bodyContent.getString();
683             bodyContent.clearBody();
684             if (value.length() > 0)
685                 _text = value;
686         }
687         return SKIP_BODY;
688     }
689
690     /**
691      * Render the end of this form.
692      * @throws JspException if a JSP exception has occurred
693      */

694     public int doEndTag() throws JspException JavaDoc
695     {
696         if (hasErrors())
697             return reportAndExit(EVAL_PAGE);
698
699         String JavaDoc idScript = null;
700
701         // Create an appropriate "form" element based on our parameters
702
HttpServletRequest JavaDoc request = (HttpServletRequest JavaDoc) pageContext.getRequest();
703         ServletContext JavaDoc servletContext = pageContext.getServletContext();
704
705         // if we have an Id or a tag is forcing the name, then set the state and generate
706
// the JavaScript
707
if (_state.id != null || _setRealName) {
708             String JavaDoc id = _state.id;
709             _state.name = _realName;
710             _state.id = _realName;
711             idScript = renderNameAndId(request, id);
712         }
713
714         if (_state.method == null)
715             _state.method = FORM_POST;
716
717         // Encode the action
718
// If the rewritten form action contains request parameters, turn them into hidden fields --
719
// it's not legal to include them in the action URI on a GET.
720
HttpServletResponse JavaDoc response = (HttpServletResponse JavaDoc) pageContext.getResponse();
721
722         if (_actionUrl != null) {
723             _state.action = response.encodeURL(_actionUrl);
724         }
725
726         WriteRenderAppender writer = new WriteRenderAppender(pageContext);
727         TagRenderingBase br = TagRenderingBase.Factory.getRendering(TagRenderingBase.FORM_TAG, request);
728         br.doStartTag(writer, _state);
729
730         // If the action we're submitting to is checking for double-submits, save a token in the session.
731
// This will be written out as a hidden param (below), and will be checked in PageFlowRequestProcessor.
732
String JavaDoc token = PageFlowTagUtils.getToken(request, _mapping);
733
734         // Add a transaction token (if present in our session)
735
HttpSession JavaDoc session = pageContext.getSession();
736         if (session != null) {
737             if (token == null) {
738                 token = (String JavaDoc) session.getAttribute(Globals.TRANSACTION_TOKEN_KEY);
739             }
740             if (token != null) {
741                 String JavaDoc name = URLRewriterService.getNamePrefix(servletContext, request, Constants.TOKEN_KEY)
742                               + Constants.TOKEN_KEY;
743                 writeHiddenParam(name, token, writer, request, true);
744             }
745         }
746
747         // add a hidden value for each parameter
748
if (_params != null) {
749             Iterator paramKeys = _params.keySet().iterator();
750             while (paramKeys.hasNext()) {
751                 Object JavaDoc paramKey = paramKeys.next();
752                 Object JavaDoc paramValue = _params.get(paramKey);
753                 if (paramValue instanceof String JavaDoc[]) {
754                     String JavaDoc[] paramValArray = (String JavaDoc[]) paramValue;
755                     for (int i = 0; i < paramValArray.length; i++) {
756                         String JavaDoc name = paramKey.toString();
757                         String JavaDoc paramName = URLRewriterService.getNamePrefix(servletContext, request, name) + name;
758                         writeHiddenParam(paramName, paramValArray[i], writer, request, true);
759                     }
760                 }
761                 else {
762                     String JavaDoc name = paramKey.toString();
763                     String JavaDoc paramName = URLRewriterService.getNamePrefix(servletContext, request, name) + name;
764                     writeHiddenParam(paramName, paramValue.toString(), writer, request, true);
765                 }
766             }
767         }
768
769         // add the extra hidden parameters
770
if (_extraHiddenParams != null && _extraHiddenParams.size() > 0) {
771             for (Iterator i = _extraHiddenParams.keySet().iterator(); i.hasNext();) {
772                 String JavaDoc name = (String JavaDoc) i.next();
773                 for (Iterator j = ((List)_extraHiddenParams.get(name)).iterator(); j.hasNext();) {
774                     String JavaDoc value = (String JavaDoc) j.next();
775                     writeHiddenParam(name, value, writer, request, true);
776                 }
777             }
778         }
779
780         // add the body content
781
if (_text != null)
782             write(_text);
783
784         // Remove the page scope attributes we created
785
pageContext.removeAttribute(Constants.BEAN_KEY, PageContext.REQUEST_SCOPE);
786         pageContext.removeAttribute(Constants.FORM_KEY, PageContext.REQUEST_SCOPE);
787         ImplicitObjectUtil.unloadActionForm(pageContext);
788
789         // Render a tag representing the end of our current form
790
br.doEndTag(writer);
791
792         // Render JavaScript to set the input focus if required
793
if ((_focus != null) && (_focusMap != null)) {
794             String JavaDoc focusName = (String JavaDoc) _focusMap.get(_focus);
795
796             if (focusName != null) {
797                 String JavaDoc formName = _realName;
798                 ScriptRequestState srs = ScriptRequestState.getScriptRequestState(request);
799                 srs.writeFeature(getScriptReporter(), writer, CoreScriptFeature.SET_FOCUS, false, true,
800                         new Object JavaDoc[]{formName, focusName});
801             }
802         }
803
804         if (_formSubmit) {
805             ScriptRequestState srs = ScriptRequestState.getScriptRequestState(request);
806             srs.writeFeature(getScriptReporter(), writer, CoreScriptFeature.ANCHOR_SUBMIT, true, false, null);
807         }
808
809         // output any generated javascript
810
if (idScript != null)
811             write(idScript);
812
813         localRelease();
814         return EVAL_PAGE;
815     }
816
817     /**
818      * This mehtod will render the JavaScript associated with the id lookup if id has
819      * been set.
820      * @param request
821      * @param id
822      * @return
823      */

824     private String JavaDoc renderNameAndId(HttpServletRequest JavaDoc request, String JavaDoc id)
825     {
826         // if id is not set then we need to exit
827
if (id == null)
828             return null;
829
830         // Legacy Java Script support -- This writes out a single table with both the id and names
831
// mixed. This is legacy support to match the pre beehive behavior.
832
String JavaDoc idScript = null;
833         IScriptReporter scriptReporter = getScriptReporter();
834         ScriptRequestState srs = ScriptRequestState.getScriptRequestState(request);
835         if (TagConfig.isLegacyJavaScript()) {
836             idScript = srs.mapLegacyTagId(scriptReporter, id, _state.id);
837         }
838
839         // map the tagId to the real id
840
if (TagConfig.isDefaultJavaScript()) {
841             String JavaDoc script = srs.mapTagId(scriptReporter, id, _state.id, _state.name);
842
843             // if we wrote out script in legacy mode, we need to make sure we preserve it.
844
if (idScript != null) {
845                 idScript = idScript + script;
846             }
847             else {
848                 idScript = script;
849             }
850         }
851         return idScript;
852     }
853
854
855     /**
856      * Write a hidden field for a paramter
857      * @param paramName The name of the parameter
858      * @param paramValue The value of the paramter
859      * @param results The InternalStringBuilder to append the result to
860      * @param req THe servlet request
861      */

862     private void writeHiddenParam(String JavaDoc paramName, String JavaDoc paramValue, AbstractRenderAppender results,
863                                   ServletRequest JavaDoc req, boolean newLine)
864     {
865         // put each hidden on a new line
866
if (newLine)
867             results.append("\n");
868
869         // create the state
870
_hiddenState.clear();
871         _hiddenState.name = paramName;
872         _hiddenState.value = paramValue;
873
874         TagRenderingBase hiddenTag = TagRenderingBase.Factory.getRendering(TagRenderingBase.INPUT_HIDDEN_TAG, req);
875         hiddenTag.doStartTag(results, _hiddenState);
876         hiddenTag.doEndTag(results);
877     }
878
879     /*
880      * We have this local method because the Form may have the condition to manipulate the
881      * URL and write out action parameters as hidden fields.
882      *
883      * This method will rewrite the URL via the rewriter service, then if needed, pull off
884      * extra parameters from the rewritten URL to be turned into hidden fields, and finally
885      * runs the modified URL through the rewriter service's templated URL formatting.
886      */

887     private String JavaDoc rewriteActionURL(ServletContext JavaDoc servletContext, HttpServletRequest JavaDoc request,
888                                     HttpServletResponse JavaDoc response, LinkedHashMap/*<String, List<String>>*/ extraHiddenParams)
889             throws URISyntaxException JavaDoc
890     {
891         String JavaDoc qualifiedAction = InternalUtils.qualifyAction(servletContext, _state.action);
892         String JavaDoc actionUrl = InternalUtils.createActionURL(request, qualifiedAction);
893         MutableURI uri = new MutableURI(actionUrl, true);
894         uri.setFragment(_location);
895         uri.setEncoding(response.getCharacterEncoding());
896
897         boolean needsToBeSecure = PageFlowUtils.needsToBeSecure(servletContext, request, actionUrl, true);
898         URLRewriterService.rewriteURL(servletContext, request, response, uri, URLType.ACTION, needsToBeSecure);
899
900         // Add a scope-ID hidden input, if there's one on this tag, or one in the request.
901
String JavaDoc targetScope = (_targetScope != null) ? _targetScope : request.getParameter(ScopedServletUtils.SCOPE_ID_PARAM);
902         if (targetScope != null) {
903             if (_params == null) {
904                 _params = new HashMap();
905             }
906             _params.put(ScopedServletUtils.SCOPE_ID_PARAM, targetScope);
907             // If there's one on the URL, we're replacing it with a hidden param.
908
if (uri != null) {
909                 uri.removeParameter(ScopedServletUtils.SCOPE_ID_PARAM);
910             }
911         }
912
913         // Check if the rewritten form action contains request parameters that need
914
// to be turned into hidden fields -- shouldn't include them in the action
915
// URI on a GET.
916
boolean forXML = false;
917         if (_state.method != null && _state.method.equalsIgnoreCase(FORM_GET)
918                 && !URLRewriterService.allowParamsOnFormAction(servletContext, request)) {
919             extraHiddenParams.putAll(uri.getParameters());
920         }
921         else {
922             // Params are allowed on the form action so see if this is for XHTML
923
forXML = TagRenderingBase.Factory.isXHTML(request);
924         }
925
926         String JavaDoc key = PageFlowUtils.getURLTemplateKey(URLType.ACTION, needsToBeSecure);
927         URIContext uriContext = URIContextFactory.getInstance(forXML);
928         String JavaDoc rewrittenURI = URLRewriterService.getTemplatedURL(request, uri, key, uriContext);
929         return rewrittenURI;
930     }
931
932     /**
933      * Get the generated action URL, based on the action attribute.
934      */

935     String JavaDoc getActionUrl()
936     {
937         return _actionUrl;
938     }
939
940     /**
941      * Release any acquired resources.
942      */

943     protected void localRelease()
944     {
945         super.localRelease();
946
947         _state.clear();
948         _hiddenState.clear();
949
950         _focus = null;
951         _location = null;
952         _text = null;
953
954         _beanName = null;
955         _explicitBeanType = false;
956         _beanType = null;
957         _beanScope = null;
958
959         _realName = null;
960         _setRealName = false;
961
962         _targetScope = null;
963
964         _mapping = null;
965         _servlet = null;
966         _focusMap = null;
967         _appConfig = null;
968         _flowController = null;
969         _formSubmit = false;
970         _params = null;
971         _actionUrl = null;
972         _extraHiddenParams = null;
973     }
974
975     /**
976      * Look up values for the <code>name</code>, <code>scope</code>, and
977      * <code>type</code> properties if necessary.
978      * @throws JspException if a required value cannot be looked up
979      */

980     private void lookupBeanScopeAndName(HttpServletRequest JavaDoc request, ServletContext JavaDoc servletContext)
981             throws JspException JavaDoc
982     {
983         // Look up the application module configuration information we need
984
_appConfig = (ModuleConfig) request.getAttribute(Globals.MODULE_KEY);
985         if (_appConfig == null) { // Backwards compatibility hack
986
_appConfig = (ModuleConfig) servletContext.getAttribute(Globals.MODULE_KEY);
987         }
988         if (_appConfig == null) {
989             registerTagError(Bundle.getString("Tags_FormNoApplicationConfig"), null);
990             return;
991         }
992         _servlet = (ActionServlet) servletContext.getAttribute(Globals.ACTION_SERVLET_KEY);
993         _flowController = PageFlowUtils.getCurrentPageFlow(request);
994
995         // check to see if this is a bad action
996

997         PageFlowTagUtils.MappingAndController mac = PageFlowTagUtils.getActionMapping(request, _flowController, _state.action);
998         if (mac == null) {
999             FlowController globalApp = PageFlowUtils.getSharedFlow(InternalConstants.GLOBALAPP_CLASSNAME, request);
1000            mac = PageFlowTagUtils.getActionMapping(request, globalApp, _state.action);
1001        }
1002        if (mac == null) {
1003            registerTagError(Bundle.getString("Tags_BadAction", _state.action), null);
1004            return;
1005        }
1006
1007        _flowController = mac.controller;
1008        _mapping = mac.mapping;
1009        assert (_mapping != null) : "Mapping not found for controller";
1010        _appConfig = _mapping.getModuleConfig();
1011
1012        // Were the required values already specified?
1013
if (_beanName != null) {
1014            if (!_explicitBeanType) {
1015                registerTagError(Bundle.getString("Tags_FormNameNoType"), null);
1016                return;
1017            }
1018            if (_beanScope == null)
1019                _beanScope = "session";
1020            return;
1021        }
1022
1023        // Look up the form bean definition
1024
FormBeanConfig formBeanConfig = _appConfig.findFormBeanConfig(_mapping.getName());
1025        if (formBeanConfig == null) {
1026            // clear any _beanType
1027
_beanType = null;
1028        }
1029        else {
1030            // Calculate the required values
1031
_beanName = _mapping.getAttribute();
1032            _beanScope = _mapping.getScope();
1033            _beanType = formBeanConfig.getType();
1034        }
1035    }
1036}
1037
Popular Tags