Table of Contents

Chapter 9: Customizing
Editors
Editors configuration
Multiple values editors
Custom editors and stereotypes for displaying combos
Custom JSP view and OpenXava taglibs
Example
xava:editor
xava:action, xava:link, xava:image, xava:button
xava:message (new in v2.0.3)
xava:descriptionsList (new in v2.0.3)

Chapter 9: Customizing

User Interface generated by OpenXava is good for most cases, but sometimes you may need customizing some part of the user interface (creating your own editors) or create your own handmade user interface (using custom JSP views) completly.

Editors

Editors configuration

You see that the level of abstraction used to define views is high, you specify the properties to be shown and how to layout them, but not how to render them. To render properties OpenXava uses editors.
An editor indicates how to render a property. It consists of an XML definition put together with a JSP fragment.
To refine the behavior of the OpenXava editors or to add your custom editors you must create in the folder xava of you project a file called editors.xml. This file looks like this:
<?xml version = "1.0" encoding = "ISO-8859-1"?>
 
<!DOCTYPE editors SYSTEM "dtds/editors.dtd">
 
<editors>
    <editor .../> ...
</editors>
Simply it contains the definition of a group of editors, and an editor is defined like this:
<editor
    url="url"                          <!-- 1 -->
    format="true|false"                <!-- 2 -->
    depends-stereotypes="stereotypes"  <!-- 3 -->
    depends-properties="properties"    <!-- 4 -->
    frame="true|false"                 <!-- 5 -->
>
    <property ... /> ...               <!-- 6 -->
    <formatter ... />                  <!-- 7 -->
    <for-stereotype ... /> ...         <!-- 8 -->
    <for-type ... /> ...               <!-- 8 -->
    <for-model-property ... /> ...     <!-- 8 -->
</editor>
  1. url (required): URL of JSP fragment that implements editor.
  2. format (optional): If true, then OpenXava has the responsibility of formatting the data from HTML to Java and vice versa; if false, then the responsibility of this is for the editor itself (generally getting the data from request and assigning it to org.openxava.view.View and vice versa). The default is true.
  3. depends-stereotypes (optional): List of stereotypes (comma separated) which this editor depends on. If in the same view there are some editors for these stereotypes they throw a change value event if its values change.
  4. depends-properties (optional): List of properties (comma separated) on which this editor depends. If in the same view there are some editors for these properties they throw a change value event if its values change.
  5. frame (optional): If true, then the editor will be displayed inside a frame. The default is false. Useful for big editors (more than one line) that can be prettier this way.
  6. property (several, optional): Set values in the editor; this way you can configure your editor and use it several times in different cases.
  7. formatter (one, optional): Java class to define the conversion from Java to HTML and from HTML to Java.
  8. for-stereotype or for-type or for-model-property (required one of these, but only one): Associates this editor with a stereotype, type or a concrete property of a model. The preference order is: first model property, then stereotype and finally type.
Let's see an example of an editor definition. This example is an editor that comes with OpenXava, but it is a good example to learn how to make your custom editors:
<editor url="textEditor.jsp">
    <for-type type="java.lang.String"/>
    <for-type type="java.math.BigDecimal"/>
    <for-type type="int"/>
    <for-type type="java.lang.Integer"/>
    <for-type type="long"/>
    <for-type type="java.lang.Long"/>
</editor>
Here a group of basic types is assigned to the editor textEditor.jsp. The JSP code of this editor is:
<%@ page import="org.openxava.model.meta.MetaProperty" %>
 
<%
String propertyKey = request.getParameter("propertyKey");                            // 1
MetaProperty p = (MetaProperty) request.getAttribute(propertyKey);                   // 2
String fvalue = (String) request.getAttribute(propertyKey + ".fvalue");              // 3
String align = p.isNumber()?"right":"left";                                          // 4
boolean editable="true".equals(request.getParameter("editable"));                    // 5
String disabled=editable?"":"disabled";                                              // 5
String script = request.getParameter("script");                                      // 6
boolean label = org.openxava.util.XavaPreferences.getInstance().isReadOnlyAsLabel();
if (editable || !label) {                                                            // 5
%>
<input name="<%=propertyKey%>" class=editor                                        <!-- 1 -->
    type="text"
    title="<%=p.getDescription(request)%>"
    align='<%=align%>'                                                             <!-- 4 -->
    maxlength="<%=p.getSize()%>"
    size="<%=p.getSize()%>"
    value="<%=fvalue%>"                                                            <!-- 3 -->
    <%=disabled%>                                                                  <!-- 5 -->
    <%=script%>                                                                    <!-- 6 -->
    />
<%
} else {
%>
<%=fvalue%>&nbsp;
<%
}
%>
<% if (!editable) { %>
    <input type="hidden" name="<%=propertyKey%>" value="<%=fvalue%>">
<% } %>
A JSP editor receives a set of parameters and has access to attributes that allows to configure it in order to work suitably with OpenXava. First you can see how it gets propertyKey (1) that is used as HTML id. From this id you can access to MetaProperty (2) (that contains meta information of the property to edit). The fvalue (3) attribute contains the value already formated and ready to be displayed. Align (4) and editable (5) are obtained too. Also you need to obtain a JavaScript (6) fragment to put in the HTML editor.
Although creating an editor directly with JSP is easy it is not usual to do it. It's more common to configure existing JSPs. For example, in your xava/editors.xml you can write:
<editor url="textEditor.jsp">
    <formatter class="org.openxava.formatters.UpperCaseFormatter"/>
    <for-type type="java.lang.String"/>
</editor>
In this way you are overwriting the OpenXava behavior for properties of String type, now all Strings are displayed and accepted in upper-cases. Let's see the code of the formatter:
package org.openxava.formatters;
 
import javax.servlet.http.*;
 
/**
 * @author Javier Paniza
 */
 
public class UpperCaseFormatter implements IFormatter {                // 1
 
    public String format(HttpServletRequest request, Object string) {  // 2
        return string==null?"":string.toString().toUpperCase();
    }
 
    public Object parse(HttpServletRequest request, String string) {   // 3
        return string==null?"":string.toString().toUpperCase();
    }
 
}
A formatter must implement IFormatter (1), this forces you to write a format() (2) method to convert the property value (that can be a Java object) to a string to be rendered in HTML; and a parse() (3) method to convert the string received from the submitted HTML form into an object suitable to be assigned to the property.

Multiple values editors

Defining an editor for editing multiple values is alike to define a single value editor. Let's see it.
For example if you want to define a stereotype REGIONS that allows the user to select more than one region for a single property. You may use the stereotype in this way:
@Stereotype("REGIONS")
private String [] regions;
 
Then you need to add the next entry to your stereotype-type-default.xml file:
<for stereotype="REGIONS" type="String []"/>
And to define in your editor in your editors.xml file:
<editor url="regionsEditor.jsp">                                                <!-- 1 -->
    <property name="regionsCount" value="3"/>                                   <!-- 2 -->
    <formatter class="org.openxava.formatters.MultipleValuesByPassFormatter"/>  <!-- 3 -->
    <for-stereotype stereotype="REGIONS"/>
</editor>
regionsEditor.jsp (1) is the JSP file to render the editor. You can define properties that will be sent to the JSP as request parameters (2). And the formatter must implement IMultipleValuesFormatter, that is similar to IFormatter but it uses String [] instead of String. In this case we are using a generic formatter that simply do a bypass.
The last is to write your JSP editor:
<%@ page import="java.util.Collection" %>
<%@ page import="java.util.Collections" %>
<%@ page import="java.util.Arrays" %>
<%@ page import="org.openxava.util.Labels" %>
 
<jsp:useBean id="style" class="org.openxava.web.style.Style" scope="request"/>
 
<%
String propertyKey = request.getParameter("propertyKey");
String [] fvalues = (String []) request.getAttribute(propertyKey + ".fvalue");  // 1
boolean editable="true".equals(request.getParameter("editable"));
String disabled=editable?"":"disabled";
String script = request.getParameter("script");
boolean label = org.openxava.util.XavaPreferences.getInstance().isReadOnlyAsLabel();
if (editable || !label) {
    String sregionsCount = request.getParameter("regionsCount");
    int regionsCount = sregionsCount == null?5:Integer.parseInt(sregionsCount);
    Collection regions = fvalues==null?Collections.EMPTY_LIST:Arrays.asList(fvalues);
%>
<select name="<%=propertyKey%>" multiple="multiple"
    class=<%=style.getEditor()%>
    <%=disabled%>
    <%=script%>>
    <%
    for (int i=1; i<regionsCount+1; i++) {
        String selected = regions.contains(Integer.toString(i))?"selected":"";
    %>
    <option
        value="<%=i%>" <%=selected%>>
        <%=Labels.get("regions." + i, request.getLocale())%>
    </option>
    <%
    }
    %>
</select>
<%
}
else {
    for (int i=0; i<fvalues.length; i++) {
%>
<%=Labels.get("regions." + fvalues[i], request.getLocale())%>
<%
    }
}
%>
 
<%
if (!editable) {
    for (int i=0; i<fvalues.length; i++) {
%>
        <input type="hidden" name="<%=propertyKey%>" value="<%=fvalues[i]%>">
<%
    }
}
%>
As you see it is like defining a single value editor, the main difference is that the formatted value (1) is an array of strings (String []) instead of a simple string (String).

Custom editors and stereotypes for displaying combos

You can have simple properties displayed as combos and fill the combos with data from the database.
Let's see this.
You define the properties like this in your entity:
@Stereotype("FAMILY")
private int familyNumber;
 
@Stereotype("SUBFAMILY")
private int subfamilyNumber;
 
And in your editors.xml put:
<editor url="descriptionsEditor.jsp">                                           <!-- 10 -->
    <property name="model" value="Family"/>                                     <!--  1 -->
    <property name="keyProperty" value="number"/>                               <!--  2 -->
    <property name="descriptionProperty" value="description"/>                  <!--  3 -->
    <property name="orderByKey" value="true"/>                                  <!--  4 -->
    <property name="readOnlyAsLabel" value="true"/>                             <!--  5 -->
    <for-stereotype stereotype="FAMILY"/>                                       <!-- 11 -->
</editor>
 
<!-- It is possible to specify dependencies from stereotypes or properties -->
<editor url="descriptionsEditor.jsp"                                            <!-- 10 -->
    depends-stereotypes="FAMILY">                                               <!-- 12 -->
<!--
<editor url="descriptionsEditor.jsp" depends-properties="familyNumber">         <!-- 13 -->
-->
    <property name="model" value="Subfamily"/>                                  <!--  1 -->
    <property name="keyProperty" value="number"/>                               <!--  2 -->
    <property name="descriptionProperties" value="number, description"/>        <!--  3 -->
    <property name="condition" value="${familyNumber} = ?"/>                    <!--  6 -->
    <property name="parameterValuesStereotypes" value="FAMILY"/>                <!--  7 -->
    <!--
    <property name="parameterValuesProperties" value="familyNumber"/>           <!--  8 -->
    -->
    <property name="descriptionsFormatter"                                      <!--  9 -->
        value="org.openxava.test.formatters.FamilyDescriptionsFormatter"/>
    <for-stereotype stereotype="SUBFAMILY"/>                                    <!-- 11 -->
</editor>
When you show a view with this two properties (familyNumber and subfamilyNumber) OpenXava displays a combo for each property, the family combo is filled with all families and the subfamily combo is empty; and when the user chooses a family, then the subfamily combo is filled with all the subfamilies of the chosen family.
In order to do that you need to assign to stereotypes (FAMILY and SUBFAMILY in this case(11)) the descriptionsEditor.jsp (10) editor and you configure it by assigning values to its properties. Some properties that you can set in this editor are:
  1. model: Model to obtain data from. It can be the name of an entity (e.g. Invoice) or the name of the model used in an embedded collection (Invoice.InvoiceDetail).
  2. keyProperty or keyProperties: Key property or list of key properties; this is used to obtain the value to assign to the current property. It is not required that they are the key properties of the model, although this is the typical case.
  3. descriptionProperty or descriptionProperties: Property or list of properties to show in combo.
  4. orderByKey: If it has to be ordered by the key, by default it is ordered by description. You can also use order with an order clause in SQL style if you need it.
  5. readOnlyAsLabel: When it is read only, then it is rendered as label. The default is false.
  6. condition: Condition to limit the data to be displayed. Has SQL format, but you can use the property names with ${}, even qualified properties are supported. You can put arguments with ?. This last case is when this property depends on other ones and only obtain data when these other properties change.
  7. parameterValuesStereotypes: List of stereotypes from which properties depend. It's used to fill the condition arguments and has to match with depends-stereotypes attribute (12).
  8. parameterValuesProperties: List of properties from which properties depends. It's used to fill the condition arguments and has to match with depends-properties attribute (13).
  9. descriptionsFormatter: Formatter for the descriptions displayed in a combo. It must implement IFormatter.
Following this example you can learn how to create your own stereotypes that display a simple property in combo format and with dynamic data. Nevertheless, in most cases it is more convenient to use references displayed as @DescriptionsList; but you always can choose.

Custom JSP view and OpenXava taglibs

Obviously the better way to create user interfaces is using the view annotations explained in chapter 4. But, in extreme cases perhaps you have to define your view using JSP. OpenXava allows you to do it. And in order to help you to do it, you can use some JSP taglibs provided by OpenXava. Let's see an example.

Example

First you have to define in your module that you want to use your own JSP, in application.xml:
<module name="SellersJSP" folder="invoicing.variations">
    <model name="Seller"/>
    <view name="ForCustomJSP"/>                           <!-- 1 -->
    <web-view url="custom-jsp/seller.jsp"/>               <!-- 2 -->
    <controller name="Typical"/>
</module>
If you use web-view (2) on defining your module, OpenXava uses your JSP to render the detail, instead of generating the view automatically. Optionally you can define an OpenXava view using view (1), this view is used to know the events to throw and the properties to populate, if not it is specified the default view of the entity is used; although it's advisable to create an explicit OpenXava view for your JSP custom view, in this way you can control the events, the properties to populate, the focus order, etc explicitly. You can put your JSP inside web/custom-jsp (or other of your choice) folder of your project, and it can be as this one:
<%@ include file="../xava/imports.jsp"%>
 
<table>
<tr>
    <td>Number: </td>
    <td>
        <xava:editor property="number"/>
    </td>
</tr>
<tr>
    <td>Name: </td>
    <td>
        <xava:editor property="name"/>
    </td>
</tr>
 
<tr>
    <td>Level: </td>
    <td>
        <xava:editor property="level.id"/>
        <xava:editor property="level.description"/>
    </td>
</tr>
</table>
You are free to create your JSP file as you like, but it can be useful to use OpenXava taglibs, in this case, for example the <xava:editor/> taglib is used, this renders an editor suitable for the indicated property, furthermore add the needed javascript to throw the events. If you use <xava:editor/>, you can manage the displayed data using xava_view (of org.openxava.view.View type) object, therefore all standard OpenXava controllers (including CRUD) work.
You can notice that qualified properties are allowed (as level.id or level.description) (new in v2.0.1), furthermore when you fill level.id, level.description is populated with the corresponding value. Yes, all the behaviour of an OpenXava view is available inside your JSP if you use the OpenXava taglibs.
Let's see the OpenXava taglibs.

xava:editor

The <xava:editor/> tag allows you to render an editor (a HTML control) for your property, in the same way that OpenXava does it when it generates the user interface automatically.
<xava:editor
    property="propertyName"            <!-- 1 -->
    editable="true|false"              <!-- 2  New in v2.0.1 -->
    throwPropertyChanged="true|false"  <!-- 3  New in v2.0.1 -->
/>
  1. property (required): It's the property of the model associated with the current module
  2. editable (optional): New in v2.0.1. Forces to this editor to be editable, otherwise the appropriate default value is assumed.
  3. throwPropertyChanged (optional): New in v2.0.1. Forces to this editor to throws property changed event, otherwise the appropriate default value is assumed.
This tag generates the needed JavaScript in order to allow your view to work in the same way as an automatic one. The qualified properties (properties of references) are supported (new in v2.0.1).

xava:action, xava:link, xava:image, xava:button

The <xava:action/> tag allows you to render an action (a button or a image that the user can click).
<xava:action action="controller.action" argv="argv"/>
The action attribute indicates the action to execute, and the argv attribute (optional) allows you to put values to some properties of the action before execute it. One example:
<xava:action action="CRUD.save" argv="resetAfter=true"/>
When the user clicks on it, then it executes the action CRUD.save, before it puts true to the resetAfter property of the action.
The action is rendered as an image, if it has an image associated. Otherwise it is rendered as a button. If you want to determine the render style, then you can use directly the next taglibs: <xava:button/>, <xava:image/> or <xava:link/> similars to <xava:action/>.
You can specify an empty string as action (new in v2.2.1), as following:
<xava:action action=""/>
In this case the tag has no effect and no error is produced. This feature may be useful if you fill the name of the action dynamically (that is action=”<%=mycode()%>”), and the value can be empty in some cases.

xava:message (new in v2.0.3)

The <xava:message/> tag allows to show in HTML a message from the i18n resource files of OpenXava.
<xava:message key="message_key" param="messageParam" intParam="messageParam"/>
The message is searched first in the message resource files of your project (YourProject/i18n/YourProject-messages.properties) and if it is not found there then it's searched in the default OpenXava messages (OpenXava/i18n/Messages.properties).
The attributes param and intParam are optional. The attribute intParam is used when the value to send as parameter is of int type. If you use Java 5 you can use always param because int is automatically converted by autoboxing.
This tag only generates the message text, without any formatting HTML tags.
An example:
<xava:message key="list_count" intParam="<%=totalSize%>"/>

xava:descriptionsList (new in v2.0.3)

The <xava:descriptionsList/> tag allows you to render a description list (a HTML combo) for your reference, in the same way that OpenXava does it when it generates the user interface automatically.
<xava:descriptionsList
    reference="referenceName"  <!-- 1 -->
/>
  1. reference (required): It's a reference of the model associated with the current module
This tag generates the needed JavaScript in order to allow your view to work in the same way as an automatic one.
An example:
<tr>
    <td>Level: </td>
    <td>
        <xava:descriptionsList reference="level"/>
    </td>
</tr>
In this case level is a reference of the current model (for example Seller). A combo is shown with all available levels.