Class Form

java.lang.Object
fc.web.forms.Form

public class Form extends Object
Represents an HTML form. It is possible to instantiate a different form object per user and store each form in that users session scope. However, more typically, instances of this object are instantiated once per unique form and stored in web application scope.

Method in this class are thread safe since form processing is done entirely within various methods and the form processing results in the creation of seperate FormData objects for each request.

Various Fields can be added to the form at form creation time. Some fields (like Hidden can also be added per user/request, dynamically, to the FormData object. This is useful while saving some user or request specific information.

A form collects data from the front-end/web-client and often saves it to a back end database entity. Form data validation can be done in 2 ways:

  1. at the form level where the form collects data and validates it via validators associated with the form object.
  2. at the field level where the form itself does no higher level validation but populates a field and then asks that field to validate itself.
In both cases, any errors associated with the form can be shown back to the user. This framework allows both types of validation methods to be used. Using validation and/or showing validation errors is optional. This framework can simply be used to maintain form state and validation can be done via other ad-hoc code (outside of this framework) as needed.

An HTML form presented to the user can contain fields from more than 1 database table. For example, there could to 2 database tables, say "person" and "office" both with a "other" column. Since each field contained in the form object must have a unique name, there will be a name clash between the fields/attributes of the entities when 2 fields with the name "other" are added to the form.

There are 2 general approaches to solving this problem.

  1. Seperate database tables should be represented by seperate Form objects (all of which can be rendered in the same HTML document shown to the user). Different instances of form objects (say 1 per table) act as seperate name-spaces and fields having the same name can exist in these seperate instances. However, the dynamic server page where the form object is rendered/submitted has to obtain these seperate instances from the application object (or wherever all forms are stored) -- which adds some complexity.
  2. Create 1 instance of a form object containing fields from more than one table. In this case, some or all field names can be prepended (or suffixed) with the name of the database table. This removes any name clashes if done only for clashing fields; if done for every field may help in documenting which table that field belongs to. There is more typing involved with this approach.
Either of the above approaches is valid.

Sometimes, other methods need to obtain a field (for a particular table) by name. For example, the managers generated by Generate have a addValidators(form) method that extract the fields for a particular table and add validators to that field. This method in particular need to be passed either the appropriate form object in which that field exists (if there are multiple form objects) or in the case of only 1 form object, passed the prefix for that particular field, if that field was added with a prefix to it's name.

  • Field Details

  • Constructor Details

  • Method Details

    • destroy

      public void destroy()
      This method should be called when the form is removed from session or application scope. It is very important to do this if there are background update tasks because this method stops such background refresh timer thread (which would otherwise continue to run).
    • remove

      public Object remove(Field field)
      Removes the specified field from the form. See Map.remove(Object) for the general contract.
      Parameters:
      field - the field to remove from the form.
    • add

      public Form add(Field field)
      Adds the specified element to the form. The added field can later be retrieved via it's name. The field iteration order will be the same order in which fields are added via this method.

      Note, field names have to be unique. "Grouped" fields (such as HTML form checkboxes or radio buttons) which require the same field name are encapsulated by a single appropriate grouped field object such as RadioGroup and CheckboxGroup. This field object itself should have a unique name.

      Returns:
      A reference to this form as a convenience for method chaining
      Throws:
      IllegalArgumentException - if an element with the same name already exists in this form.
    • add

      public Form add(Dependency d)
      Adds the specified dependency to the form.
    • add

      public Form add(FieldRef ref)
      Adds a FieldRef to this Form. This is useful when to track a set of related fields in a form. (Note: those fields must also directly be added to the form).
    • addError

      public void addError(FormData fd, String errorKey, String errorMessage)
      Adds a form level validation error message. This method is needed when form level validation is done via classes that are not subclasses of FormValidator (these classes are used outside of the validation framework and their error message still needs to be added to the form data).

      This is a very useful method for adding the results of arbitrary code to this form.

      Parameters:
      fd - form data
      errorKey - an arbitrary/optional validation key which allows to later retrieve and display a particular form error. Specify null for no key.
      errorMessage - the form error message
      See Also:
    • addError

      public void addError(FormData fd, String errorMessage)
      Convenience method that invokes addError with an empty validation errorKey.
    • addDynamicField

      public void addDynamicField(FormData fd, Hidden f)
      Adds a Hidden field to this form. This field exists only for the duration of this form data object and is useful for request specific data.
    • addValidator

      public void addValidator(FormValidator validator)
      Adds a form level validator to this form. Note, validator names have to be unique and not clash with other form level validator names.
      Throws:
      IllegalArgumentException - if a validator with the same name already exists in this form.
    • addMessage

      public void addMessage(FormData fd, String key, String value)
      Adds an arbitrary message for this request. Messages can include arbitrary warnings, usage help etc.
    • containsField

      public boolean containsField(String fieldName)
      Returns true if the form contains the specified field.
    • getMessage

      public String getMessage(FormData fd, String key)
      Retrieves a previously added message or null if the speccified form data was null or if the message was not found.
    • addSubmitHackedHandler

    • handleSubmit

      public FormData handleSubmit(jakarta.servlet.http.HttpServletRequest req) throws jakarta.servlet.ServletException, IOException
      Processes the submitted form. This method must be called after each form submission by the servlet or page code that handles form submits. This method does the following:
      1. populates the fields of the form from the submitted request.
      2. if the form has any dependencies and if the dependencies need updating, then those dependencies are updated. Validation is not carried out in this case since the form has changed and the user needs to typically carry out some other action before submitting the form.
      3. if there are no updated dependencies, validates the form via any validators attached to the form and it's fields.
      Note: To see if there were any validation errors, invoke the hasError(fc.web.forms.FormData) method with the formdata returned by this method. Seeing validation errors is optional of course, and so is using validators in the first place.
      Parameters:
      req - the HttpServletRequest corresponding to the request being processed by this form.
      Returns:
      a FormData object containing populated field data and the results of the validation.
      Throws:
      jakarta.servlet.ServletException
      IOException
    • handleSubmit

      public FormData handleSubmit(jakarta.servlet.http.HttpServletRequest req, Connection con) throws jakarta.servlet.ServletException, IOException
      This method is similar to handleSubmit(jakarta.servlet.http.HttpServletRequest) except it stores the specified connection in the form data. This connection can be used by any attached dependency classes for database queries when updating form depedencies.

      Note, we can set arbitrary objects in the HttpServletRequest via it's

      invalid reference
      setAttribute
      method. However, specifying and storing the connection in the FormData is easier to remember and use.

      There are 2 cases:

      1. The dependent fields (if any) will internally use
        invalid reference
        WebApp#getConnection
        to obtain a connection and no connection has to be set in the form data.
      2. The handleSubmit(jakarta.servlet.http.HttpServletRequest) can then be used.
      3. The dependent fields (if any) classes will expect a connection in the form data. In that case, this method should be invoked.
      If there are no dependent fields, then the handleSubmit(jakarta.servlet.http.HttpServletRequest) is sufficient.
      Parameters:
      req - the HttpServletRequest corresponding to the request being processed by this form.
      con - a connection object. The connection is not closed and it is the callers responsiblity to do so.
      Throws:
      jakarta.servlet.ServletException
      IOException
    • refresh

      public FormData refresh(jakarta.servlet.http.HttpServletRequest req) throws jakarta.servlet.ServletException, IOException
      Throws:
      jakarta.servlet.ServletException
      IOException
    • refresh

      public FormData refresh(jakarta.servlet.http.HttpServletRequest req, Connection con) throws jakarta.servlet.ServletException, IOException
      Refreshes the form for this request by running all attached refreshers and dependencies. Maintains form state. Does not run any validatators. Useful for re-displaying a form when lookup fields have changed in the database.

      To refresh the form for all users/requests from this point onwards, create a new instance of the form and replace the existing instance of the form with the newly created instance.

      Throws:
      jakarta.servlet.ServletException
      IOException
    • hasError

      public static boolean hasError(FormData fd)
      Returns true if validation did not succeed.
    • renderError

      public void renderError(FormData fd, Writer writer) throws IOException
      Convenience method to render form-level validation errors. This method writes validation error message for the specified form level validator. The error messages are encapulated in a html <div> tag and the class of this tag is set to form-errmsg. Each error message within this div is assigned it's own div with class set to form-errmsg-item
      Parameters:
      writer - the Writer to render errors to
      Throws:
      IOException
    • renderErrorFor

      public void renderErrorFor(FormData fd, Writer writer, String formValidatorName) throws IOException
      Convenience method to render a validation error for a particluar form level validator. The error messages are encapulated in a html <div> tag and the class of this tag is set to form-errmsg.
      Parameters:
      writer - the Writer to render errors to
      formValidatorName - the name of a form level validator
      Throws:
      IOException
    • getFieldErrors

      Parameters:
      fd - a non-null form data object
      Returns:
      a map containing field names as keys and the field's validation error as the value. The data type of each value is that returned by the Field.getValidateErrors(FormData) method
    • getFormErrorsCollection

      Parameters:
      fd - a non-null form data object
      Returns:
      a list containing form level errors. The data type of each value is that returned by the FormValidator.getErrorMessage() method
    • getFormErrorsFor

      public List getFormErrorsFor(FormData fd, String formValidatorName)
      Returns a list containing all form-level errors for the specified validator. If there are no errors for the specified validator, returns an empty list.
      Parameters:
      fd - a non-null form data object
      formValidatorName - a form validator name
    • renderDynamicFields

      Renders all dynamically added hidden fields of the form. Dynamic fields are created/ added per user per submit to the FormData if/as needed.

      Note: Dynamic fields are not part of a form's fields and are not available via

      Throws:
      SQLException
      IOException
    • getName

      public String getName()
      Returns the name of this form
    • setActionURL

      public void setActionURL(String url)
      Sets an arbitrary application specific string that can later be retrieved. Some applications may find this method useful.
    • getActionURL

      public String getActionURL()
      Returns the action URL string. Returns null if no url has been set.
    • setDisplayURL

      public void setDisplayURL(String url)
      Sets an arbitrary application specific string. Intended to store the URL to the jsp or front end page that will render this form for the user.
    • getDisplayURL

      Returns the display URL string. Returns null if no display url has been set.
    • getAllFields

      Returns a collection view of all the fields contained in this form.
    • get

      public Field get(String name)
      Returns the form field with the specified name.
      Parameters:
      name - the name of the field
      Returns:
      the field or null if no element with that name was found in this form.
    • getDynamicField

      public Hidden getDynamicField(FormData fd, String fieldName)
      Gets a Hidden field added to the form data object. Returns null if the form data object is null or if the specified field does not exist. Dyanamic fields returned by this method are only available for the duration of the form data object and can not obtain a field from a submitted form. (use
      invalid reference
      getDynamicField(FormData, HttpServletRequest)
      for that purpose.
    • getSubmittedField

      public Hidden getSubmittedField(jakarta.servlet.http.HttpServletRequest req, String name)
      Once the form is displayed to the user (with, say, hidden fields that were added dynamically for that request), then when that form is submitted, those dynamic fields can be retrieved via any of:
      • the ServletRequest.getParameter(String) method (often the easiest way)
      • the
        invalid reference
        #getSubmittedField(HttpServletRequest)
        method (which will attempt to read the request parameter with the specified name and return is as a Hidden field. (this is slightly more convenient if there is more than 1 hidden field with the same name, since all hidden fields with the same name are encapsulated by one object of type Hidden).
    • getContaining

      public List getContaining(String name)
      Returns all the fields that contains the specified name. This is useful when a bunch of fields are created via database lookup tables (and each such field is prefixed/suffixed by say lookup_name + some number).
      Parameters:
      name - the name of the field
      Returns:
      a List containing fields with matching names or or an empty list if no elements containing that name were found in this form.
    • getFieldRef

      public FieldRef getFieldRef(String key)
      Returns the FieldRef with the specified key. This is used to retrieve an arbitrary object added the via
      invalid reference
      #addObject
      method. Returns null if no object is found for the specified key.
    • getTimer

      public Timer getTimer()
    • getSelect

      public Select getSelect(String name)
      Returns the field with the specific name as a Select.
      Throws:
      IllegalArgumentException - if a field with the specified name does not exist or if the field exists but is not of type Select
    • getUpdatableSelect

      Returns the field with the specific name as a RefreshableSelect.
      Throws:
      IllegalArgumentException - if a field with the specified name does not exist or if the field exists but is not of type RefreshableSelect
    • getCheckbox

      public Checkbox getCheckbox(String name)
      Returns the field with the specific name as a Checkbox.
      Throws:
      IllegalArgumentException - if a field with the specified name does not exist or if the field exists but is not of type Checkbox
    • getCheckboxGroup

      Returns the field with the specific name as a Checkbox.
      Throws:
      IllegalArgumentException - if a field with the specified name does not exist or if the field exists but is not of type Checkbox
    • getHidden

      public Hidden getHidden(String name)
      Returns the field with the specific name as a Hidden.
      Throws:
      IllegalArgumentException - if a field with the specified name does not exist or if the field exists but is not of type Hidden
    • getText

      public Text getText(String name)
      Returns the field with the specific name as a Text.
      Throws:
      IllegalArgumentException - if a field with the specified name does not exist or if the field exists but is not of type Text
    • getTextArea

      public TextArea getTextArea(String name)
      Returns the field with the specific name as a TextArea.
      Throws:
      IllegalArgumentException - if a field with the specified name does not exist or if the field exists but is not of type TextArea
    • getPassword

      public Password getPassword(String name)
      Returns the field with the specific name as a Password.
      Throws:
      IllegalArgumentException - if a field with the specified name does not exist or if the field exists but is not of type Password
    • getRadio

      public Radio getRadio(String name)
      Returns the field with the specific name as a Radio.
      Throws:
      IllegalArgumentException - if a field with the specified name does not exist or if the field exists but is not of type Radio
    • getRadioGroup

      Returns the field with the specific name as a Checkbox.
      Throws:
      IllegalArgumentException - if a field with the specified name does not exist or if the field exists but is not of type Checkbox
    • toString

      public String toString()
      Overrides:
      toString in class Object