Orbeon Forms User Guide

Using Orbeon Forms with JavaServerâ„¢ Faces (JSF)

1. Introduction

JavaServer Faces (JSF) is a server-side GUI component framework developed through the Java Community Process under JSR-127. JSF is primarily designed to build Web applications.

This chapter explains how to integrate Orbeon Forms with JSF. Most of this documentation also applies to the standalone distribution of the XML RenderKit for JavaServer Faces. It may also be a good read for anyone interested in using XML technologies such as XSLT with JSP and JSF.

Note

At the time of writing, the JSF specification is still not final: the version used is the JavaServer Faces Specification, 1.0 Public Review Draft 2, and the JavaServer Faces Reference implementation version 1.0 Early Access 4 (EA 4). The specification as well as the implementation may be subject to change before the final 1.0 version is released.

2. Rationale

The JSF Standard HTML RenderKit outputs raw HTML. Using this RenderKit, the HTML output can be configured with:

  • CSS classes assigned to the generated HTML tags by setting yyyClass attributes on the components, where yyy is the component name in lowercase without the "UI" prefix. For example, setting a commandClass attribute on a UICommand component generates a class attribute on the resulting HTML <input> element.

  • A certain number of additional attributes on components are passed without modification to the resulting HTML element. Those attributes do not appear to be documented in the current JSF specification. Examples include size, cols, JavaScript event handlers, etc. They may modify the appearance and/or behavior of a component.

Often, CSS classes and other HTML attributes are not sufficient to completely customize the appearance of a component. For example:

  • Support for multiple devices. Rendering a component differently depending on the targeted device. For example, a PDA browser typically needs to render a component in a much simpler way, due to the limited space on its small screen.

  • Advanced internationalization. For example, implementing right-to-left layouts for languages such as Arabic or Hebrew. In such cases, component captions must be placed on the other side of components and a grid (table) must be rendered right-to-left.

  • Advanced look and feels and support for older clients. For example, rendering an HTML table with a colored border in an old Web browser such as Netscape 4. This requires embedding two HTML tables within each other. You may decide that all your HTML dropdowns must be surrounded by an HTML table.

The classical solution to those problems is to:

  • Write a new JSF RenderKit in Java
  • Write one JSP page for each different layout

The Orbeon Forms approach allows you to address this problem elegantly:

  • Write an XML RenderKit once and for all. Note that if you use only the JSF Standard User Interface Components, you don't have to write your own renderer: you can use the one that comes with Orbeon Forms. This means that you don't have to write a single line of Java to customize the appearance of JSF components.

  • Minimize the number of JSP pages. Write one JSP page that generates XML, instead of duplicating JSP code and writing one page per device or language. This approach reduces the number of pages you need to write and maintain.

  • Centralize your look and feel. Customize one or several XSLT stylesheets to change the appearance of components. This is a key advantage when requirements change: you go to one location to reflect you changes instead of having to go through an impact analysis and multiple changes.

3. JSP and XML

The JSP technology is well-suited to generate well-formed XML, but it does not enforce well-formed XML output. To achieve this, the following conditions must be met:

  1. JSP pages must contain only well-formed template text markup. It is recommended (but not mandatory) to write JSP documents instead of regular JSP pages. A JSP document is similar to a JSP page, but is a well-formed XML document. A JSP document in JSP 2.0 usually ends with the extension .jspx, since JSP 2.0 engines automatically recognize this extension. With JSP 1.2, they usually end with .jsp, like regular JSP pages.

    Note
    Some JSP engines have trouble generating XML documents with namespaces from JSP documents. Tomcat 4.1.x does not appear to exhibit such problems, but WebLogic does.
  2. Tag libraries used in the JSP pages / documents must generate well-formed XML. The JSF Standard HTML RenderKit Tag Library generates output through the RenderKit associated with the components. Since the output of the standard RenderKit is HTML and not XML, it is necessary to fix it. One way of doing this is to switch to an XML RenderKit instead. Orbeon Forms comes with such an XML RenderKit implementation for the JSF Standard User Interface Components.

    NOTE: Another possibility is to use an HTML parser on the HTML output of the document. Using an XML RenderKit offers additional benefits, as explained below.

    NOTE: Not all tag libraries generate output directly. For example, JSTL iterators and conditionals do not generate any output of their own.

4. Standalone Control Flow

When the XML RenderKit is used standalone (without Orbeon Forms), the following control flow (compatible with the Model 2X architecture) occurs: a custom Servlet Filter implements a mini-controller, parses the JSP output and applies an XSLT transformation. Such a filter can be modified at will to provide more or less functionality.

  1. HTTP Request
  2. The filter dispatches the request to JSF
  3. The JSF Controller processes the request and forwards it to a JSP page
  4. If necessary using the JSF tag libraries and, indirectly, the XML RenderKit, the JSP page generates XML output
  5. The output from the JSP page is parsed
  6. Through an XSLT transformation, the response is sent to the client

5. Orbeon Forms Control Flow

The current version of Orbeon Forms supports rendering JSF components using XML pipelines. You can use XSLT or other transformation languages. The flow is very similar to the standalone flow, but dispatching the request to JSF and parsing the JSP output is implemented in a generic XML processor in Orbeon Forms called the Servlet Filter Generator. The generator can be connected to any other XML processors. A typical use is to connect its output to an XSLT Transformer.

The following figure illustrates the flow of the request, from the client to Orbeon Forms to JSF and back:

  1. HTTP Request
  2. The Orbeon Forms Controller dispatches the request to an XML pipeline
  3. Using a Servlet Filter Generator, the pipeline calls a JSF tree
  4. The JSF Controller processes the request and forwards it to a JSP page
  5. If necessary using the JSF tag libraries and, indirectly, the XML RenderKit, the JSP page generates XML output
  6. The resulting XML is generated within Orbeon Forms by the Servlet Filter Generator
  7. Through an optional series of transformations, the response is sent to the client

6. The XML RenderKit

Orbeon Forms comes with an XML RenderKit for the JSF Standard User Interface Components. The XML RenderKit can also be used independently from Presentation Server.

6.1. Differences with the HTML RenderKit

The JSF Standard HTML RenderKit generates an output that can be directly interpreted by an HTML client such as a Web browser. For example, a UICommand rendered as a button using the h:command_button tag generates an HTML <input type="text" value="Submit"> HTML tag.

The XML RenderKit does not try to generate output that can be interpreted by an HTML client. Instead, it generates a model of the component that contains all the information necessary to display it. For example, the same button is generated as a <jsf:command_button> element. It is up to an XSLT stylesheet to transform that element into an HTML element.

With this approach it is possible:

  • To use different features on different clients
  • To customize the appearance of a component at will

6.2. Differences with an XHTML RenderKit

The JSF Standard HTML RenderKit is currently not able to generate XHTML (the XML-compliant version of HTML). It may do so in the future, or third-party vendors may implement RenderKits with such functionality. It is important to note that a RenderKit generating XHTML is different from the Orbeon Forms XML RenderKit. An XHTML RenderKit would generate the button above as <input type="text" value="Submit"/>. The only difference with the HTML version is the trailing slash (which is invalid in HTML). Similarly, a checkbox's selected boolean attribute would be rendered in HTML simply as selected, while in XHTML it must be rendered as selected="selected". In summary, XHTML does not add information to HTML: it is simply a slightly different way of representing a document.

With the JSF Standard HTML RenderKit, an output_number and output_date components, once rendered, cannot be discriminated. With the XML RenderKit, the discrimination is possible because the RenderKit generates, for each component, information that allows for the identification of the component type. This way, one can automatically display dates in a specific style by setting a CSS class once and for all in an XSLT stylesheet. With the HTML RenderKit, one would have to set a CSS class on every h:output_date tag.

Another example is the h:output_errors JSF tag. The JSF Standard HTML RenderKit decides how to render the errors. For example, in EA 4, it renders errors separated by tabs: Error1 Error2 ....

If you want to change this, you have to implement your own renderer in Java and from scratch. Instead, the XML RenderKit generates a structured output:

<jsf:output_errors class="my-class"><jsf:errors><jsf:error>Error 1</jsf:error><jsf:error>Error 2</jsf:error></jsf:errors></jsf:output_errors>

With an XSLT template like the following, error handling becomes much more flexible. You can fully customize the display of the errors without changing the RenderKit:

<xsl:template match="jsf:output_errors"><span style="color: red"><xsl:if test="count(jsf:error)"><xsl:for-each select="jsf:error"><xsl:if test="position() > 1"><xsl:text>/</xsl:text></xsl:if><xsl:value-of select="."/></xsl:for-each></xsl:if></span></xsl:template>

In this case, the errors are rendered in red and separated with slashes ('/').

6.3. Sample XSLT Stylesheet

A sample XSLT stylesheet that generates an (X)HTML output for each component ships Orbeon Forms as well as in the standalone distribution of the XML RenderKit for JavaServer Faces. It is also available online:

jsf-theme.xsl

6.4. XML Output Format

As mentioned above, the XML RenderKit generates a structured output that represents the component to be displayed. The following rules are applied:

  • All the elements are in the http://orbeon.org/oxf/xml/jsf-output namespace. The typical prefix associated with this namespace is jsf.
  • Each component is rendered in the form jsf:component_rendertype. The component part is the name of the component in lowercase, without the "UI" prefix. The rendertype part is the render type in lowercase.
  • Most components have a class attribute that is copied from the component's yyyClass attribute when present.
  • Every component label is rendered using the <jsf:label> element.
  • Client ids are copied into the id attribute. It is up to the XSLT stylesheet to use this id to generate, for example, an HTML element name attribute.
  • All resources are looked up in the RenderKit.
  • Date / number formatting and parsing is done in the RenderKit.
  • Most UISelectMany and UISelectOne output identical XML. It is up to the XSLT stylesheet to output the most adequate representation of the component.
  • No JavaScript is produced by the RenderKits. It is up to the XSLT stylesheet to output JavaScript code if needed.
  • Components that can be selected or deselected, such as lists, checkboxes, radio buttons, use a selected attribute set to true or false.

The following table is a comprehensive list of the JSF Standard User Interface Components and Render Types defined in the JavaServer Faces Specification Version 1.0, Public Review Draft 2. For each combination, an informal example of output is shown.

Component Render Type Format
UICommand Button
<jsf:command_button class="class" type="submit|reset" id="client-id"><jsf:label>Label</jsf:label></jsf:command_button>
The id attribute can be used to generate an HTML name attribute on a form submit element.
Hyperlink If the href attribute is present:
<jsf:command_hyperlink class="class" href="http://example.org/test?a=1&b=2&c=3"><jsf:path>http://example.org/test?a=1</jsf:path><jsf:parameters><jsf:parameter><jsf:name>b</jsf:name><jsf:value>2</jsf:value></jsf:parameter><jsf:parameter><jsf:name>c</jsf:name><jsf:value>3</jsf:value></jsf:parameter></jsf:parameters><jsf:label>Label</jsf:label></jsf:command_hyperlink>
otherwise:
<jsf:command_hyperlink class="class" id="client-id" command-name="command-name"><jsf:parameters><jsf:parameter><jsf:name>a</jsf:name><jsf:value>1</jsf:value></jsf:parameter><jsf:parameter><jsf:name>b</jsf:name><jsf:value>2</jsf:value></jsf:parameter></jsf:parameters><jsf:label>Label</jsf:label></jsf:command_hyperlink>
A The request parameters are listed separately even when the href attribute is present, in order to provide more flexibility. A pre-computed href attribute is also generated, built on the href provided by the user and the embedded UIParameter components. The pre-computed href attribute can be rebuilt by appending the parameters to the jsf:path value (taking care of separating them with a '?' or '&' if necessary).
UIForm Form
<jsf:form class="my-class" method="post" action="/faces/test.jsp"/>
UIGraphic Image
<jsf:graphic_image class="my-class" id="client-id" src="/images/test.gif"/>
UIInput Date
<jsf:input_date class="my-class" id="client-id" value="Jun 12 2003"/>
DateTime
<jsf:input_datetime class="my-class" id="client-id" value="Jun 12 17:59:27 2003"/>
Hidden
<jsf:input_hidden id="client-id" value="Hidden Value"/>
Number
<jsf:input_number class="my-class" id="client-id" value="42"/>
Secret
<jsf:input_secret class="my-class" id="client-id" value="password"/>
Text
<jsf:input_text class="my-class" id="client-id" value="JSF rocks!"/>
TextArea
<jsf:input_textarea class="my-class" id="client-id">Content of the text area.</jsf:input_textarea>
UIOutput Date
<jsf:output_date class="my-class">Jun 12 2003</jsf:output_date>
DateTime
<jsf:output_datetime class="my-class">Jun 12 17:59:27 2003</jsf:output_datetime>
Errors
<jsf:output_errors class="my-class"><jsf:errors><jsf:error>Error 1</jsf:error><jsf:error>Error 2</jsf:error></jsf:errors></jsf:output_errors>
Label
<jsf:output_label class="my-class" for="first-name"/>
Message
<jsf:output_message class="my-class">You have 12 new emails in your inbox.</jsf:output_message>
Number
<jsf:output_number class="my-class">42</jsf:output_number>
Text
<jsf:output_text class="my-class">JSF rocks!</jsf:output_text>
Time
<jsf:output_time class="my-class">17:59:27</jsf:output_time>
UIPanel Data N/A
Grid
<jsf:panel_grid><!-- Optional header if header facet is present --><jsf:header class="my-class" colspan="colspan"><!-- Children Components --></jsf:header><!-- Rows and column --><jsf:row class="my-class"><jsf:column class="my-class"><!-- Children Component --></jsf:column></jsf:row><jsf:row class="my-class"><jsf:column class="my-class"><!-- Children Component --></jsf:column></jsf:row><!-- Optional header if footer facet is present --><jsf:footer class="my-class" colspan="colspan"><!-- Children Components --></jsf:footer></jsf:panel_grid>
Group N/A
List Not implememented yet.
UISelectBoolean Checkbox
<jsf:selectboolean_checkbox class="my-class" id="client-id" selected="true"/>
UISelectMany Checkbox
<jsf:selectmany_checkbox class="my-class" id="client-id" layout="PAGE_DIRECTION|LINE_DIRECTION"><jsf:option value="value" selected="true"><jsf:label>Label</jsf:label></jsf:option><jsf:option value="value" selected="false"><jsf:label>Label</jsf:label></jsf:option></jsf:selectmany_checkbox>
Listbox
<jsf:selectmany_listbox class="my-class" id="client-id" layout="PAGE_DIRECTION|LINE_DIRECTION"><jsf:option value="value" selected="true"><jsf:label>Label</jsf:label></jsf:option><jsf:option value="value" selected="false"><jsf:label>Label</jsf:label></jsf:option></jsf:selectmany_listbox>
Menu
<jsf:selectmany_menu class="my-class" id="client-id" layout="PAGE_DIRECTION|LINE_DIRECTION"><jsf:option value="value" selected="true"><jsf:label>Label</jsf:label></jsf:option><jsf:option value="value" selected="false"><jsf:label>Label</jsf:label></jsf:option></jsf:selectmany_menu>
UISelectOne Listbox
<jsf:selectone_listbox class="my-class" id="client-id" layout="PAGE_DIRECTION|LINE_DIRECTION"><jsf:option value="value" selected="true"><jsf:label>Label</jsf:label></jsf:option><jsf:option value="value" selected="false"><jsf:label>Label</jsf:label></jsf:option></jsf:selectone_listbox>
Menu
<jsf:selectone_menu class="my-class" id="client-id" layout="PAGE_DIRECTION|LINE_DIRECTION"><jsf:option value="value" selected="true"><jsf:label>Label</jsf:label></jsf:option><jsf:option value="value" selected="false"><jsf:label>Label</jsf:label></jsf:option></jsf:selectone_menu>
Radio
<jsf:selectone_radio class="my-class" id="client-id" layout="PAGE_DIRECTION|LINE_DIRECTION"><jsf:option value="value" selected="true"><jsf:label>Label</jsf:label></jsf:option><jsf:option value="value" selected="false"><jsf:label>Label</jsf:label></jsf:option></jsf:selectone_radio>