Mapper Logo
.

5. General XML Components

5.1 Heirarchy

* class com.taursys.xml.Component (implements com.taursys.util.MapperComponent)

    * class com.taursys.xml.Container
          * class com.taursys.xml.DocumentElement (implements com.taursys.xml.DocumentComponent)
                * class com.taursys.xml.Template
          * class com.taursys.servlet.ServletForm
                * class com.taursys.servlet.DefaultMessageForm
    * class com.taursys.xml.Parameter
          * class com.taursys.xml.AbstractField (implements com.taursys.xml.DocumentComponent)
                * class com.taursys.xml.CheckboxField
                      * class com.taursys.html.HTMLCheckBox
                * class com.taursys.xml.SelectField
                      * class com.taursys.html.HTMLSelect
                * class com.taursys.xml.TextField
                      * class com.taursys.html.HTMLAnchorURL
                      * class com.taursys.html.HTMLInputText
                      * class com.taursys.html.HTMLTextArea
    * class com.taursys.xml.Trigger
          * class com.taursys.xml.Button (implements com.taursys.xml.DocumentComponent)

5.2 Parameter

A Component which receives parameter values. A Parameter is very similar to an input field (AbstractField). The primary difference is WHEN they receive their values. Parameter values are dispatched immediately before the openForm method, whereas input events are dispatched immediately after the openForm method.

Parameters have one primary property which you must set. It is the "parameter" property. This identifies the name of the value which it should listen for and respond to in the request.

By default, a Parameter uses an internal DefaultTextModel with a VariantValueHolder and a default data type of String. You can change the data type when you instantiate the Parameter. The Parameter can also be bound to an external ValueHolder (see previous chapter).

The following is an example of a Parameter which receives a birthdate:

  Parameter birthdate = new Parameter(DataTypes.TYPE_DATE);
  ...
  private void jbInit() throws Exception {
    birthdate.setParameter("birthdate");
    birthdate.setFormat(java.text.SimpleDateFormat.getInstance());
    birthdate.setFormatPattern("MM/dd/yyyy");
    ...
    this.add(birthdate);
  }

  protected void openForm() throws Exception {
    // search for record by birthdate
    PersonVO person = delegate.findByBirthdate(
        (Date)birthdate.getValue());
  }
        

This component can also be bound to an external ValueHolder. An external ValueHolder can be shared by multiple components. The propertyName specifies which property in the ValueHolder will be bound to this component. To bind this component, set the valueHolder and propertyName properties. You do not need to specify a data type when you bind to a ValueHolder. The following is an example of binding:

          Parameter latitude = new Parameter();
          Parameter longitude = new Parameter();
          VOValueHolder holder = new VOValueHolder();

          private void jbInit() throws Exception {
            holder.setValueObjectClass(LocationVO.class);

            latitude.setParameter("latitude");
            latitude.setValueHolder(holder);
            latitude.setPropertyName("physicalLatitude");

            longitude.setParameter("longitude");
            longitude.setValueHolder(holder);
            longitude.setPropertyName("physicalLongitude");
            ...
            this.add(latitude);
            this.add(longitude);
          }

          void showOnMapButton_actionPerformed(TriggerEvent e) throws Exception {
            OutputStream map = delegate.getMap((LocationVO)holder.getValueObject());
            ...
          }
        

5.3 TextField

A component which can receive input and/or render a value to an XML document. This component can function in three different ways, depending on the properties you set:

  • input only - set the parameter property.
  • output only - set the id property.
  • input and output - set both the parameter and id properties.

When used for output, the value is rendered in the XML document as a text node by default. If you want the value to be rendered to an attribute of the node instead, you must change the renderer to an AttributeTextFieldRenderer and the the attribute property to the name of the attribute. The below example demonstrates both cases:

        private TextField projectStatus = new TextField();
        private TextField projectStatusColor = new TextField();

        private void jbInit() throws Exception {
          projectStatus.setId("projectStatus");
          projectStatusColor.setId("projectStatus");
          projectStatusColor.setRenderer(
              new AttributeTextFieldRenderer(projectStatusColor));
          projectStatusColor.setAttribute("bgcolor");
          ...
          this.add(projectStatus);
          this.add(projectStatusColor);
        }

        protected void openForm() throws Exception {
          ...
          projectStatus.setValue("on-schedule");
          projectStatusColor.setValue("green");
          ...
        }
        

After rendering the HTML document would appear as follows:

        ...
        <table>
          <tr>
            <td id="projectStatus" bgcolor="green">on-schedule</td>
            ...
        

When used for input, this component receives its value from the InputDispatcher AFTER the openForm method of the ServletForm by default. If you want this component to receive its input earlier (at the same time as Parameters), set the earlyInputNotify property to true.

By default, this component uses an internal DefaultTextModel with a VariantValueHolder and a default data type of String. You can specify a different data type when you invoke the constructor of this component. Below is an example:

          TextField salary = new TextField(DataTypes.TYPE_BIGDECIMAL);
        

This component can also be bound to an external ValueHolder. An external ValueHolder can be shared by multiple components. The propertyName specifies which property in the ValueHolder will be bound to this component. To bind this component, set the valueHolder and propertyName properties. You do not need to specify a data type when you bind to a ValueHolder. The following is an example of binding:

          TextField personId = new TextField(DataTypes.TYPE_INT);
          TextField lastName = new TextField();
          TextField city = new TextField();
          VOValueHolder holder = new VOValueHolder();

          private void jbInit() throws Exception {
            holder.setValueObjectClass(PersonVO.class);
            ...
            personId.setParameter("personId");
            personId.setId("personId");
            personId.setEarlyInputNotify(true);
            ...
            lastName.setId("lastName");
            lastName.setValueHolder(holder);
            lastName.setPropertyName("lastName");
            ...
            city.setId("city");
            city.setValueHolder(holder);
            city.setPropertyName("address.city");
            ...
            this.add(lastName);
            this.add(city);
          }

          protected void openForm() throws java.lang.Exception {
            holder.setValueObject(
                delegate.getPerson((Integer)personId.getValue());
            ...
          }
        

Notes: In the above example, the personId field is used as a parameter and display field. By setting its earlyInputNotify property to true, it will have its value available when the openForm method is invoked. It is not bound to the holder. The lastName field functions as a display only field. It is not configured as an input field. The same is true of the city field. Note the city field's property name: "address.city". The PersonVO has an "address" property of type AddressVO. The AddressVO in turn has a "city" property. The dot notation supports multiple levels of indirection.

5.4 SelectField

This component is used to display and change a selection. This component, (using a DefaultSelectModel), can display a selection from a list of objects. It can also change the selection from user input.

This component can be used for a variety of purposes. It can provide a way to display a "description" rather than a "code" for a coded value. It can also serve to scope user input to a subset of values.

The selection is made and displayed using the property indicated by the displayPropertyName. The displayPropertyName is effectively the "selection key". If the displayPropertyName is null or blank, then the toString method is used instead. For example, given a list of Address objects, and a displayPropertyName of "zipCode", the display value for "Juneau, AK 99801 USA" would be "99801". To change the selection, you would supply a different zipCode from the list.

This component can function in three different ways, depending on the properties you set:

  • input only - set the parameter property.
  • output only - set the id property.
  • input and output - set both the parameter and id properties.

When used for output, the value is rendered in the XML document as a text node by default. If you want the value to be rendered to an attribute of the node instead, you must change the renderer to an AttributeTextFieldRenderer and the the attribute property to the name of the attribute. For rendering with an HTML SELECT/OPTION, use the HTMLSelect component.

When used for input, this component receives its value from the InputDispatcher AFTER the openForm method of the ServletForm by default. If you want this component to receive its input earlier (at the same time as Parameters), set the earlyInputNotify property to true.

By default, this component uses a DefaultSelectModel. You can change this by overriding the createDefaultModel method or explicitly setting the model property.

Setting the List

The list must be a type of CollectionValueHolder (example: VOCollectionValueHolder or VOListValueHolder). The holder can contain any type of object (but they must all be instances of the same class).

If the list is an ObjectArrayValueHolder, then the toString() method is used as the display value (regardless of the displayPropertyName). If used in the bound mode, the whole object itself is stored in the target ValueHolder's object (regardless of the property names listed in the setListPropertyNames method). It is important to make sure that the valueHolder property is the same type as the objects in the ObjectArrayValueHolder or a ModelException will occur.

You can also preset the list in the constructor by passing it an array of Objects to be used for the list. The resulting list will be an ObjectArrayValueHolder.

The following is an example of this usage:

          SelectField color = new SelectField(new String[] {
              "Red", "Orange", "Yellow", "Green", "Blue", "Indigo", "Violet",
              });
          ...
          private void jbInit() throws Exception {
            ...
            color.setParameter("color");
            color.setId("color");
            ...
            this.add(color);
          }
        

This component can be used in a variety of ways. It can be used in an un-bound mode, where the current selection is maintained internally. It can also be used in a bound mode where the current selection is propagated to a value holder. When used in the bound mode, either a single property, or multiple properties can be set in the value holder. The following sections describe the required settings to make for each of the modes.

Un-bound Mode (uses internal VariantValueHolder)

When used in this mode this component uses an internal VariantValueHolder to hold the current selection. By default a VariantValueHolder is created with a data type of String. To set a different data type use the constructor which takes a data type as a parameter. (example new SelectField(DataTypes.TYPE_INT)).

To use this component in the un-bound mode, you must set the following properties:

  • list - should be set to a type of CollectionHolder which holds the list of options (see "Setting the List").
  • displayPropertyName - the name of the property to display (property of objects in list). Example: given a list of "Location" objects with a property called "locationName", use setDisplayPropertyName("locationName") to display the zipCode. IMPORTANT - The displayed property choosen must result in a unique list of values, otherwise the intended value may not be selected/displayed.
  • listPropertyNames - set a single source property name in the list objects. Example: Given a list containing "Location" objects which has properties "zipCode", "cityName", "stateAbbr", and "country", to make the zipcode the internal value use setListPropertyNames(new String[] {"zipCode"}).

    If the list is an ObjectArrayValueHolder, then the property name should always be a single "value" (which is the default).

  • propertyName - must be "value" (which is the default).
  • nullDisplay - String to display in list for null selection. Example: "--- Nothing Selected ---"
Bound Mode

To use this component in the bound mode, use the same properties as described in the Un-bound Mode, plus the following additional properties:

  • valueHolder - should be set to the target ValueHolder which contains the current selection and will be updated if the selection is changed.
  • propertyName - set this to the first (or only) ValueHolder object property name which will be bound to the selection. Example: given a ValueHolder with an "Address" object which has a "zipCode" property, use setPropertyName("zipCode") to store the current selection in the "Address.zipCode" property.
  • propertyNames - use this when you want to set more than 1 property in the ValueHolder object. Example: assume you want to set not only the "zipCode" property, but also the "city", "state" and "country" properties, use setPropertyNames(new String[] {"zipCode","city","state","country"})
  • listPropertyNames - set the to the source property name(s) in the list objects. IMPORTANT - The name(s) of the listPropertyNames properties MUST be in the same ORDER as the propertyName(s). The names in the listPropertNames may be different than the names in the propertyNames since they are associated with in objects in the list, not the valueHolder. Example: Given a list containing "Location" objects which has properties "zipCode", "cityName", "stateAbbr", and "country", for a single property use setListPropertyNames(new String[] {"zipCode"}). For multiple properties use setListPropertyNames(new String[] {"zipCode", "cityName", "stateAbbr", "country"})

    If the list is an ObjectArrayValueHolder, then the property name should always be a single "value" (which is the default).

Other Important Information

When a selection is made, the values are copied from the properties in the list to the properties in the valueHolder object. The property names in propertyNames[] and listPropertyNames[] must appear in a corresponding order.

A "null" item will always be added to the displayOptionList. When the "null" item is selected, a null will be assigned to the propertyNames[] in the valueHolder object. The actual "null" item to to display is defined by the nullDisplay (default is "--none--").

The format and formatPattern govern the display property in this component. The getText method returns the formatted display property, while the setText method changes the current selection to one whose display matches the given value. If you attempt to setText for an item that is not in the list, a NotInListException will be thrown.

5.5 CheckboxField

This component is used to display and change a "selected indicator". This component uses a DefaultCheckboxModel to manage the state. There are only two states for this component: selected or not-selected.

To use this component you must first set the the following properties as indicated:

  • selectedValue - the text value which indicates a "selected" state. The default value is "true".
  • unselectedValue - the text value which indicates an "un-selected" state. The default value is "" (blank) which will result in a null value being stored in the valueHolder

This component can function in three different ways, depending on the properties you set:

  • input only - set the parameter property.
  • output only - set the id property.
  • input and output - set both the parameter and id properties.

When used for output, the value is rendered in the XML document as a text node by default. If you want the value to be rendered to an attribute of the node instead, you must change the renderer to an AttributeTextFieldRenderer and the the attribute property to the name of the attribute. For rendering with an HTML input type checkbox, use the HTMLCheckBox component.

When used for input, this component receives its value from the InputDispatcher AFTER the openForm method of the ServletForm by default. If you want this component to receive its input earlier (at the same time as Parameters), set the earlyInputNotify property to true.

By default, this component uses a DefaultCheckboxModel. You can change this by overriding the createDefaultModel method or explicitly setting the model property.

This component can be used in a variety of ways. It can be used in an un-bound mode, where the current selected state is maintained internally. It can also be used in a bound mode where the current selected state is propagated to a value holder. When used in the bound mode a single property can be set in the value holder. The following sections describe the required settings to make for each of the modes.

Un-bound Mode

To use this component in the un-bound mode, you can set the following properties:

  • selectedValue - the text value which indicates a "selected" state. The default value is "true".
  • unselectedValue - the text value which indicates an "un-selected" state. The default value is "" (blank) which will result in a null value being stored in the valueHolder
Bound Mode

To use this component in the bound mode, use the same properties as described in the Un-bound Mode, plus the following additional properties:

  • valueHolder - should be bound to the ValueHolder which contains the current selected state and is to be updated if the state is changed.
  • propertyName - set this to the property name (belonging to the object in the ValueHolder) which will be bound to the selected state. Example: given a ValueHolder with an "Address" object which has a "active" property, use setPropertyName("active") to store the current selected state in the "Address.active" property.

5.6 Trigger

5.7 Button

5.8 Template

A Template is a component used to display and/or input multiple values. It acts as a Container for other components which provide the actual display or input. A typical application for the Template is to display or edit a table of data. The Template is bound to a single tag in the XML document. This tag in turn contains other tags that make up the "template" row. The Template is also bound to a CollectionValueHolder which contains the values. When rendered, the Template will replicate itself (and its child tags) in the XML document for each value in the holder.

The following is an example illustrates a Template used to display a list of names (from a collection of Person objects). A portion of the HTML is listed below along with a portion of the java code. The initForm and openForm methods have been ommitted. The HTMLComponentFactory was not used in this example so that the actual components could be illustrated.

         <h2>List presented in a table</h2>
         <table border="1">
           <tr>
             <td >First Name</td>
             <td >Last Name</td>
           </tr>
           <tr id="People__TEMPLATE_NODE">
             <td id="People__firstName">John</td>
             <td id="People__lastName">Smith</td>
           </tr>
         </table>

        -----------------------------------------------------------------------

        public class TemplatePage extends ServletForm {
          VOCollectionValueHolder people = new VOCollectionValueHolder();
          // ===================================================================
          // The following code can be ommitted if the component factory is used
          // ===================================================================
          TextField firstName = new TextField();
          TextField lastName = new TextField();
          Template report = new Template();
          // ===================================================================

          public TemplatePage() {
            try {
              jbInit();
            } catch(Exception e) {
              e.printStackTrace();
            }
          }

          private void jbInit() throws Exception {
            people.setAlias("People");
            people.setValueObjectClass(Person.class);
            // ===================================================================
            // The following code can be ommitted if the component factory is used
            // ===================================================================
            firstName.setPropertyName(Person.FIRST_NAME);
            firstName.setValueHolder(people);
            firstName.setId("People__firstName");
            lastName.setPropertyName(Person.LAST_NAME);
            lastName.setValueHolder(people);
            lastName.setId("People__lastName");
            report.setId("report");
            report.setCollectionValueHolder(people);
            report.add(firstName);
            report.add(lastName);
            this.add(report);
            // ===================================================================
          }
        

A Template can also be used to input multiple values. The code is essentially the same, except that you will use input type components in the HTML and Java code. The order and count of the values in the request must correspond to the order and count in the holder. The BusinessDelegate that supplies the values should ensure this.

The following example illustrates a form to edit inventory items. A portion of the HTML is listed below along with a portion of the java code. The openForm methods has been ommitted. This example uses the HTMLComponent factory to create the actual components at runtime.


        <h2>List of Inventory Items to Edit</h2>
          <form method="post" action="InventoryEditPage.sf">
            <table border="1" width="100%">
              <tr bgcolor="orange">
                <td>Quantity</td>
                <td>Product ID</td>
                <td>Unit Price</td>
                <td>Extension</td>
              </tr>
              <tr id="Inventory__TEMPLATE_NODE">
                <td>
                  <input type="text" id="Inventory__quantity" name="quantity" value="1"/>
                </td>
                <td id="Inventory__productID">XXXX</td>
                <td>
                  <input type="text" id="Inventory__unitPrice" name="unitPrice" value="0.00"/>
                </td>
                <td id="Inventory__extension">0.00</td>
              </tr>
            </table>
            <br/>
            <input type="submit" name="action" value="Save"/>
          </form>

        -----------------------------------------------------------------------

        public class InventoryEditPage extends ServletForm {
          private VOListValueHolder inventoryHolder = new VOListValueHolder();

          public InventoryEditPage() {
            try {
              jbInit();
            } catch(Exception e) {
              e.printStackTrace();
            }
          }

          private void jbInit() throws Exception {
            inventoryHolder.setAlias("Inventory");
            inventoryHolder.setValueObjectClass(InvoiceItemVO.class);
            this.add(warehouseField);
          }

          protected void initForm() throws java.lang.Exception {
            super.initForm();
            DOMParser parser = new DOMParser();
            InputSource is = new InputSource(
                getClass().getResourceAsStream("InventoryEditPage.html"));
            parser.parse(is);
            this.setDocument(parser.getDocument());
            // Use HTMLComponentFactory to create components
            HTMLComponentFactory.getInstance().createComponents(this,
              new ValueHolder[] {inventoryHolder});
          }
        

Technical Information:

The Template uses a TemplateRenderer to do the actual rendering. Typically, this involves dispatching a RenderEvent to its children, then cloning itself for each item in its collectionValueHolder.

The Template creates specialized dispatchers for Input and Trigger events. These dispatchers iterate over each item in the collection (in the order of the iterator), increment the parameter index and dispatch input to child components.

.