Download FAQ History |  | API Search Feedback

> ## Delegating Rendering to a Renderer

> For the purpose of illustrating delegated rendering, the image map example includes an `AreaRenderer`, which performs the rendering for the `UIArea` component.

> To delegate rendering, you need to perform these tasks:

> - Create the renderer class
> - Register the renderer with a render kit
> - Identify the renderer type in the component's tag handler

> ### Create the Renderer Class

> When delegating rendering to a renderer, you can delegate all encoding and decoding to the renderer, or you can choose to do part of it in the component class. The `UIArea` component class only requires encoding.

> To delegate the encoding to `AreaRenderer`, the AreaRenderer needs to implement an `encodeEnd` method.

> The encoding methods in a `Renderer` are just like those in a `UIComponent` class except that they accept a `UIComponent` argument as well as a `FacesContext` argument, whereas the `encodeEnd` method defined by `UIComponentBase` only takes a `FacesContext`. The `UIComponent` argument is the component that needs to be rendered. In the case of non-delegated rendering, the component is rendering itself. In the case of delegated rendering, the renderer needs to be told what component it is rendering. So you need to pass the component to the `encodeEnd` method of `AreaRenderer`:

>     public void encodeEnd(FacesContext context,
>       UIComponent component) { ... }

> The `encodeEnd` method of `AreaRenderer` must retrieve the shape, coordinates, and alt values stored in the `ImageArea` model object that is bound to the `UIArea` component. Suppose that the `area` tag currently being rendered has a `valueRef` attribute value of `"fraA"`. The following line from `encodeEnd` gets the `valueRef` value of `"fraA"` and uses it to get the value of the attribute `"fraA"` from the FacesContext.

>     ImageArea ia = (ImageArea)
>       context.getModelValue(component.getvalueRef());

> The attribute value is the `ImageArea` model object instance, which contains the shape, coordinates, and alt values associated with the `fraA` `UIArea` component instance.

> Simplifying the JSP Page describes how the application stores these values.

> After retrieving the `ImageArea` object, you render the values for `shape`, `coords`, and `alt` by simply calling the associated accessor methods and passing the returned values to the `ResponseWriter`, as shown by these lines of code, which write out the shape and coordinates:

>     writer.write("<area shape=\"");
>     writer.write(ia.getShape());
>     writer.write("\"" );
>     writer.write(" coords=\"");
>     writer.write(ia.getCoords());

> The `encodeEnd` method also renders the JavaScript for the `onmouseout`, `onmouseover`, and `onclick` attributes. The page author only needs to provide the path to the images that are to be loaded during an `onmouseover` or `onmouseout` action:

>     <d:area id="France" valueRef="fraA"
>       onmouseover="/cardemo/world_france.jpg"
>       onmouseout="/cardemo/world.jpg"  />

> The `AreaRenderer` class takes care of generating the JavaScript for these actions, as shown in this code from `encodeEnd`:

>     writer.write(" onmouseover=\"");
>     writer.write("document.forms[0].mapImage.src='");
>     imagePath = (String) component.getAttribute("onmouseover");
>     if ('/' == imagePath.charAt(0)) {
>       writer.write(imagePath);
>     } else {
>       writer.write(contextPath + imagePath);
>     }
>     writer.write("';\"");
>     writer.write(" onmouseout=\"");
>     writer.write("document.forms[0].mapImage.src='");
>     imagePath = (String) component.getAttribute("onmouseout");
>     if ('/' == imagePath.charAt(0)) {
>       writer.write(imagePath);
>     } else {
>       writer.write(contextPath + imagePath);
>     }

> The JavaScript that `AreaRenderer` generates for the `onclick` action sets the value of the hidden variable, `selectedArea`, to the value of the current area's component ID and submits the page:

>     writer.write("\"
>       onclick=\"document.forms[0].selectedArea.value='");
>     writer.write(component.getComponentId());
>     writer.write("'; document.forms[0].submit()\"");
>     writer.write(" onmouseover=\"");
>     writer.write("document.forms[0].mapImage.src='");

> By submitting the page, this code causes the JavaServer Faces lifecycle to return back to the Reconstitute Component Tree phase. This phase saves any state information--including the value of the `selectedArea` hidden variable--so that a new request component tree is constructed. This value is retrieved by the `decode` method of the `UIMap` component class. This `decode` method is called by the JavaServer Faces implementation during the Apply Request Values phase, which follows the Reconstitute Request Tree phase.

> In addition to the `encodeEnd` method, `AreaRenderer` also contains an empty constructor. This will be used to create an instance of `AreaRenderer` so that it can be added to the render kit.

> `AreaRenderer` also must implement the `decode` method and the other encoding methods, whether or not they are needed.

> Finally, `AreaRenderer` requires an implementation of `supportsComponentType`:

>     public boolean supportsComponentType(String componentType) {
>       if ( componentType == null ) {
>         throw new NullPointerException();
>       }
>       return (componentType.equals(UIArea.TYPE));
>     }

> This method returns `true` when `componentType` equals `UIArea`'s component type, indicating that `AreaRenderer` supports the `UIArea` component.

> Note that `AreaRenderer` extends `BaseRenderer`, which in turn extends `Renderer`. The `BaseRenderer` class is included in the RI of JavaServer Faces technology. It contains definitions of the `Renderer` class methods so that you don't have to include them in your renderer class.

> ### Register the Renderer with a Render Kit

> For every UI component that a render kit supports, the render kit defines a set of `Renderer` objects that can render the component in different ways to the client supported by the render kit. For example, the standard `UISelectOne` component class defines a component that allows a user to select one item out of a group of items. This component can be rendered with the `Listbox` renderer, the `Menu` renderer, or the `Radio` renderer. Each renderer produces a different appearance for the component. The `Listbox` renderer renders a menu that displays all possible values. The `Menu` renderer renders a subset of all possible values. The `Radio` renderer renders a set of radio buttons.

> When you create a custom renderer, you need to register it with the appropriate render kit. Since the image map application implements an HTML image map, `AreaRenderer` should be registered with the HTML render kit.

> You register the renderer using the application configuration file (see Application Configuration):

>     <render-kit>
>       <renderer>
>         <renderer-type>Area</renderer-type>
>         <renderer-class>
>           components.renderkit.AreaRenderer
>         </renderer-class>
>       </renderer>
>     </render-kit>

> The `render-kit` element represents a `RenderKit` implementation. If no `render-kit-id` is specified, the default HTML render kit is assumed. The renderer element represents a `Renderer` implementation. By nesting the `renderer` element inside the `render-kit` element, you are registering the renderer with the `RenderKit` associated with the `render-kit` element.

> The `renderer-type` will be used by the tag handler, as explained in the next section. The `renderer-class` is the fully-qualified classname of the `Renderer`.

> ### Identify the Renderer Type

> During the Render Response phase, the JavaServer Faces implementation calls the `getRendererType` method of the component's tag to determine which renderer to invoke, if there is one.

> The `getRendererType` method of `AreaTag` must return the type associated with `AreaRenderer`. Recall that you identified this type when you registered `AreaRenderer` with the render kit. Here is the `getRendererType` method from the `cardemo` application's `AreaTag` class:

>     public String getRendererType() { return "Area";}

Download FAQ History |  | API Search Feedback

All of the material in The Java(TM) Web Services Tutorial is copyright-protected and may not be published in other works without express written permission from Sun Microsystems.