Send your remarks, comments or wishes to doc team
Subject:
Message:
Your name:
Your email:

JBoss.org Community Documentation

- Prev
- Next

## 4.4. Creating a Renderer

Component functionality typically centers around two actions: decoding and encoding data. Decoding is the process of converting incoming request parameters to the values of the component. Encoding is the process of converting the current values of the component into the corresponding markup. In the following figure you can see decoding and encoding occur in the JSF lifecycle:

Figure 4.3. Decoding and encoding in the JSF lifecycle

Thus, JSF components consist of two parts: the component class and the renderer. The component class is responsible for the state and behavior of a UI component and will be discussed later in the "Configuring component" section.

The Renderer is responsible for the JSF component representation. It generates the appropriate client-side markup, such as HTML, WML, XUL, etc. Renderer is also responsible for the converting information coming from the client to the proper type for the component (for example, a string value from the request is converted to a strongly type `Date` object).

It is necessary to create following renderer classes for the <inputDate> component:

- `InputDateRenderer` class where you should override `encode()` methods for encoding the markup and resources

- `InputDateRendererBase` class where you should override `decode()` method. You could also define associated converter in this class.

You could actually implement the renderer-specific component subclass that exposes client-side attributes such as "style" , "class" , etc. It is common practice to implement the client-specific component subclass to make some aspects of application development easier, but in our case we do not need to do it. The <inputDate> is a simple `UIInput` component, therefore `InputDateRenderer` class generates all the markup itself.

It is a time to start creating the `InputDateRenderer` class. The smartest way to create the `InputDateRenderer` class is a Templating mechanism, one of the most convenient features of the Component Development Kit (CDK).

### 4.4.1. Templating

The Component Development Kit (CDK) allows to use templates for generation Renderer class.

Templates are JSP-like markup pages with special tags that are converted into Renderer by a build script.

It's possible to use evaluated expressions in components templates with the help of scriptlets. It's also possible to create the base class for a template to implement additional functions in it, so as the functions could be called from the template. Hence, in the generated Renderer class there are corresponding function calls on the place of these elements.

Let's create the template for HTML 4.0 markup. At first you should proceed to the inputDate/src/main/templates/org/mycompany directory where htmlInputDate.jspx template file is stored. This file contains a Template Skeleton like this one:

    <?xml version="1.0" encoding="UTF-8"?>

    <f:root

        xmlns:f="http://ajax4jsf.org/cdk/template"

        xmlns:c=" http://java.sun.com/jsf/core"

        xmlns:ui=" http://ajax4jsf.org/cdk/ui"

        xmlns:u=" http://ajax4jsf.org/cdk/u"

        xmlns:x=" http://ajax4jsf.org/cdk/x"

        class="org.mycompany.renderkit.html.InputDateRenderer"

        baseclass="org.ajax4jsf.renderkit.AjaxComponentRendererBase"

        component="org.mycompany.component.UIInputDate"

        >

        <f:clientid var="clientId"/>

        <div id="#{clientId}"

            x:passThruWithExclusions="value,name,type,id"

            >

        </div>

    </f:root>

According to the created UI prototype you need to extend Template Skeleton with proper elements:

- <div>-wrapper element with "title", "id" attributes and with the"caption" facet

      ...

      <div id="#{clientId}" title="#{value}" x:passThruWithExclusions="value,name,type,id">

          ...

      </div>

      ...

- <input> element with "id", "value", "name", "type", "class", "style" attributes. It is possible to use the "icon" facet in order to redefine a default icon of the component.

      ...

      <input  id="#{clientId}"

              name="#{clientId}"

              type="text"

              value="#{this:getValueAsString(context, component)}"

              class="my-inputDate-input #{component.attributes['inputClass']}"

              style="#{component.attributes['inputStyle']}"/>

      ...

- <img> element with "src", "class", "style" attributes which defines a default icon of the component. In order to add an image to the Template you should register it with the help of <f:resource> template tag and bind to a variable specified by the "var" attribute:

      ...

      <f:resource name="/org/mycompany/renderkit/html/images/inputDate.png" var="icon" />

          ...

      <img src="#{icon}" class="my-inputDate-icon #{component.attributes['iconClass']}" style="#{component.attributes['iconStyle']}"/>

      ...

The <inputDate> component uses styles that should be defined in the template with the help of <h:styles> tag:

    ...

    <h:styles>/org/mycompany/renderkit/html/css/inputDate.xcss</h:styles>

    ...

How to register all resources is explained in the "Component resources registration" chapter.

## Important:

Don't forget to add namespace `xmlns:h=" http://ajax4jsf.org/cdk/h"` to the <f:root> element:

    <?xml version="1.0" encoding="UTF-8"?>

    <f:root

        ...

        xmlns:h=" http://ajax4jsf.org/cdk/h"

        ...

        >

        ...

    </f:root>

Here is a full example of the template for the <inputDate> component: htmlInputDate.jspx.

## Note:

As it is seen in the Template Skeleton the Renderer Baseclass is `org.ajax4jsf.renderkit.AjaxComponentRendererBase`. You need to define Renderer Base class special for the <inputDate> component. In the next section "Creating a Renderer Base class" we will create Renderer Base class `org.mycompany.renderkit.InputDateRendererBase`.

All the Template tags you could find in the "Template tags overview" chapter.

### 4.4.2. Creating a Renderer Base class

After the component tree is restored on the Restore View Phase , each component in the tree extracts its new value from the request parameters by using its `decode()` method. Then the value is stored locally on the component.

In order to create `InputDateRendererBase` class you should proceed to the src/main/java/org/mycompany/renderkit directory and create this class there:

    package org.mycompany.renderkit;

    import java.io.IOException;

    import java.util.Map;

    import java.util.TimeZone;

    import javax.faces.component.UIComponent;

    import javax.faces.context.ExternalContext;

    import javax.faces.context.FacesContext;

    import javax.faces.convert.Converter;

    import javax.faces.convert.ConverterException;

    import javax.faces.convert.DateTimeConverter;

    import org.ajax4jsf.renderkit.HeaderResourcesRendererBase;

    import org.mycompany.component.UIInputDate;

    public abstract class InputDateRendererBase extends HeaderResourcesRendererBase {

        ...

    }

The `InputDateRendererBase` class extends a `HeaderResourcesRendererBase` class. In the `HeaderResourcesRendererBase` class all the `encode()` methods for the right resources encoding are already implemented, so in the `InputDateRendererBase` class you need to override the `decode()` method only:

     ...

    public void decode(FacesContext context, UIComponent component){

        ExternalContext external = context.getExternalContext();

        Map requestParams = external.getRequestParameterMap();

        UIInputDate inputDate = (UIInputDate)component;

        String clientId = inputDate.getClientId(context);

        String submittedValue = (String)requestParams.get(clientId);

        if (submittedValue != null) {

            inputDate.setSubmittedValue(submittedValue);

        }

    }

    ...

As you see in the example above the `decode()` method reads values from request parameters, grabs the `clientId` from the component to identify the request parameter to be looked up. The `clientId` is calculated as the fully qualified name of the component given its container path: nameOfForm:nameOfComponent (for example myForm:inputDate). The last step of the `decode()` method is to store the submitted value locally on the component.

## Note:

By default, the base Renderer implementation returns the `submittedValue` directly without any conversion! If you want to convert submitted value to a strongly typed object you should implement Converter and the `getConvertedValue()` method in your Renderer class (in our case in the `InputDateRendererBase` class).

#### 4.4.2.1. Creating a Converter

As it was mentioned before the <inputDate> component at the Apply Request Values phase takes a value and pushes it to the model as a strongly typed Date object. Therefore you need to implement a Converter in the Renderer Base class and also check whether a Converter has been already attached by the application developer. If the conversion of the value fails, an error message associated with the component is generated and queued on FacesContext.

The `getConverter()` method of the `InputDateRendererBase` class returns the a converter, as shown in the following example:

    ...

    private Converter getConverter(FacesContext context, UIInputDate inputDate){

        Converter converter = inputDate.getConverter();

        if (converter == null){

            // default the converter

            DateTimeConverter datetime = new DateTimeConverter();

            datetime.setLocale(context.getViewRoot().getLocale());

            datetime.setTimeZone(TimeZone.getDefault());

            datetime.setType("date");

            datetime.setDateStyle("medium");

            datetime.setPattern("d/m/y");

            converter = datetime;

        }

        return converter;

    }

    ...

During the converter creation you should check whether the application developer has attached a Converter to the <inputDate> component already (for example, <f:convertDateTime>) . If not you should follow the next steps:

- create a new DateTimeConverter

- get the locale for the client from the context with the help of the `getLocale()` method and set it on the new Converter by means of the `setLocale()` method

- set the time zone, date type, date style, and date pattern on the new converter with the help of `setTimeZone()`, `setType()`, `setDateStyle()`, and `setPattern()` methods respectively

- return the Converter

After the Apply Request Values phase the application enters the Process Validation phase during which the `validate()` method calls the `getConvertedValue()` method on every submitted value and passes the newly submitted value from the decode process.

The `getConvertedValue()` method converts the submitted value to a strongly typed object (in our case Date) using the `getAsObject()` method. Then the new strongly typed object is validated and if there are no errors Process Validation phase ends. Otherwise the `getConvertedValue()` method throws a ConverterException.

Here is the snippet:

    ...

    public Object getConvertedValue(FacesContext context, UIComponent component, Object submittedValue) throws ConverterException{

        UIInputDate inputDate = (UIInputDate)component;

        Converter converter = getConverter(context, inputDate);

        String valueString = (String)submittedValue;

        return converter.getAsObject(context, component, valueString);

    }

    ...

Finally on the Renderer Response phase the value of the component is rendered back to the view. The converter is responsible for transforming the object data back in to a string representation, so you need to implement `getValueAsString()` method:

Here is the example:

    ...

    protected String getValueAsString(FacesContext context, UIComponent component) throws IOException {

        UIInputDate inputDate = (UIInputDate) component;

        String valueString = (String) inputDate.getSubmittedValue();

        if (valueString == null) {

            Object value = inputDate.getValue();

            if (value != null) {

                Converter converter = getConverter(context, inputDate);

                valueString = converter.getAsString(context, component, value);

            }

        }

        return valueString;

    }

    ...

You could find the whole example of the `InputDateRendererBase` class here.

### 4.4.3. Skinnability

One of the significant features of the Component Development Kit (CDK) is a skins-based technology which helps you to create a modern rich user interface look-and-feel. RichFaces has a number of predefined skins you could use wtih the <inputDate> component. But if you want to create your own skin, please, read carefully the "Skinnability" section of the RichFaces Developer Guide. You could find all neccesary information about Built-in skinnability in RichFaces, XCSS file format, Plug-n-Skin feature, etc. there.

It's time to create XCSS file. You should go to the src/main/resources/org/mycompany/renderkit/html/css and create inputDate.xcss file there with the following skeleton:

    <?xml version="1.0" encoding="UTF-8"?>

    <f:template xmlns:f='http:/jsf.exadel.com/template'

       xmlns:u='http:/jsf.exadel.com/template/util'

       xmlns="http://www.w3.org/1999/xhtml">

        ...

    </f:template>

According to the <inputDate> markup you need to define following selectors and classes in the inputDate.xcss:

- `.my-inputDate-input`, `.my-inputDate-icon` selectors

      ...

      <u:selector name=".my-inputDate-input">

          <u:style name="border-color" skin="panelBorderColor"/>

          <u:style name="background-color" skin="controlBackgroundColor"/>

          <u:style name="color" skin="controlTextColor"/>

          <u:style name="font-family" skin="generalFamilyFont"/>

          <u:style name="font-size" skin="generalSizeFont"/>

      </u:selector>

      <u:selector name=".my-inputDate-icon">

          <u:style name="border-color" skin="panelBorderColor"/>

          <u:style name="background-image">

              <f:resource f:key="/org/mycompany/renderkit/html/images/inputDate.png" />

          </u:style>

      </u:selector>

      ...

- `.my-inputDate-input`, `.my-inputDate-icon`, and `.my-inputDate-caption` classes

      ...

      .my-inputDate-input{

      background-color: #EBEBE4;

      border: 1px solid #7F9DB9;

      float:left;

      }

      .my-inputDate-icon{

      margin-left: 3px;

      }

      .my-inputDate-caption{

      color: #000000;

      }

      ...

You could find a complete inputDate.xcss here.

- Prev4.3. Creating a UI prototype
- Top of page
- Front page
- Next4.5. Component resources registration