Empire-db and Struts2 » Rendering and parsing Download

Input controls part 2 – Rendering and parsing

One of the biggest problems in Web development is that usually the code responsible for rendering data is separated from the code used for parsing and validating data. In most cases the rendering is performed in a JSP page, either by directly embedding string representation of the value in HTML or by a special JSP tag that renders the value according to information provided with attributes on the tag. When the user submits the form the values are usually pushed into a JavaBean or POJO by an interceptor which takes the parameters from the request, looks for an appropriate setter method and then converts the value to fit the setter’s value data type.

This procedure has several disadvantages that are best understood by the following example:
Consider a phone number which is stored in the database in a single field. On the form however you want to display and edit the phone number in three individual text fields: the first for the country code, the second for the city code and the last for the extension code which are separated from each other using a dash. The first problem with traditional Web application frameworks is, that since there is no tag for such behaviour you have to write all the HTML code for those three separate input tags plus the label in your JSP. Even worse however is, that when the form is submitted three individual fields are supplied that you have to assemble to a single value again. Now for this you have several options which are all quite complicated for such a simple task. If you don’t want to provide your own interceptor you will have to provide corresponding setters on your JavaBean and – if you don’t want to rely on the order by which these setters are called - you’d have to add additional post processing code that will put them together again. Still the assembly code must rely on the rendering code which is in the JSP and thus not in the same place. As a third problem you’ll find the task of validation – for which you might have to write your own validation class. At last, all this has to be done for every single phone number field you have in your application. Imagine you have several phone number fields then handling all of them becomes quite a nasty problem.

With Empire-Struts2-Extensions the task of rendering and the task of parsing and validating form values are now put together in one simple class: The input control. The input control is an abstract base class for which you can easily provide your own implementation if necessary by only implementing three simple methods: renderText(), renderInput() and getFieldValue(). For the most common field types there are already implementations provided such as text, select, password, phone, checkbox and more. The major differences to traditional processing are:

  1. The input control has access to field metadata and can thus perform rendering, parsing and validation without additional redundant information provided in the view. However should you ever need it, you may as well override these attributes in your JSPs.
  2. The input control class distinguishes between read only and editable rendering and can thus also be used for list views for example. Consider a field whose value you have to format in a particular way for display. Simply write your own input control class and assign the control type to the corresponding column. Wherever a value for this field is displayed with any of the Empire tags it will be formatted correctly – without any change or additional attributes in the JSPs.
  3. For processing submitted form data the input control uses a pull rather than the usual push approach. This allows the input control to combine two or more fields to one value. This is e.g. used for checkboxes where an additional hidden value is used to detect whether the checkbox has been unchecked. Since the rendering code is in the same object both the splitting and the assembly can easily be kept consistent.

The following graphic shows how the InputControl is the interface between the view and the model:

The list view JSP uses the <e:value> tag (or alternatively an <e:td> tag which extends <e:value>) to render the field's value for display. The form view on contrary uses the <e:control> tag to render a form input control which may be used to change the value. When the form is submitted, an action support class iterates through all fields and gives the corresponding InputControl the opportunity to pull the value(s) off the request and to perform parsing and validation. If successful the field value is written back to the record. For all three tasks access to data and metadata is necessary.

Writing a custom input control

The following example shows, how easily a custom input control type can be created and applied.

Step 1: Write your input control class.

Create a new class, derive it from InputControl and provide an implementation for the three methods renderText(), renderInput() and getFieldValue(). Remember that your class must be fully stateless since one single instance is shared for all fields and threads. However all information you require is provided with the parameters. Here is an outline of what your class may look like:

public class CustomInputControl extends InputControl { 
    @Override 
    public Object getFieldValue(String name, RequestParamProvider request, Locale locale, DBColumn column) { … } 
    @Override 
    public void renderText(HtmlWriter writer, ValueInfo vi) { … } 
    @Override 
    public void renderInput(HtmlWriter writer, ControlInfo ci) { … } 
}

Step 2: Register your class with the InputControlMananger.

To make the Empire-Struts2-Extensions capable of using your input control class you must register it with the input control manager as follows:

// Register Control
InputControlManager.registerControl("custom", new CustomInputControl());

Step 3: Assign your input control type to database columns

Finally, assign your control type to database columns. To do this, use the setControlType() function which is provided with the DBColumn objects. For those fields, your custom input control class will now be used for rendering and form request processing.

MyDatabase db = getDatabase();
db.MYTABLE.MYCOLUMN.setControlType("custom");