Get Even More Visitors To Your Blog, Upgrade To A Business Listing >>

JSF linking together components, renderers and render kits

Introduction

In order to understand what a render kit is we have to be aware of some major notions that are very important in this context. For a better understanding please check out the below picture and identify the notions described here, and the relationships between them. The subject of this picture is the OmniFaces DeferredScriptcomponent, but don't worry, you don't have to understand that component. The role and functionality of this component is not our goal. We use it because it is a professional approach for writing custom components and sustains the topic of this article by exposing best practices of accomplishing such tasks.


A JSF component is annotated with @FacesComponent and it is characterized by three coordinates (we won't take here into account the declarative approach):

component-family -This is a piece of information that groups more components under the same family/category (e.g. ScriptFamily - a family of components that deals with scripts). Typically, a family of components are logically related, but there is no written rule. Nevertheless, a family name can be represented by the package name that holds the classes of the related components (e.g. org.omnifaces.component.script). It is a common practice that the classes of the components that are related to be placed in the same package, so the package name can be considered a family. But, again, there is no rule to sustain this practice. In order to expose into public is family a component will override the getFamily() method. Since JSF 2.2, the component-type can be omitted in @FacesComponent, because JSF will determine it like this (ComponentConfigHandler class):

...
String value = ((FacesComponent) annotation).value();
if (null == value || 0 == value.length()) {
    value = target.getSimpleName();
    value = Character.toLowerCase(value.charAt(0)) + value.substring(1);
}
...

component-type - This is a piece of information that uniquely identifies a component and can be used as the argument of the Application.createComponent(java.lang.String) method for creating instances of the UIComponent class. JSF uses the component-type for creating components. Typically a component type will be the fully qualified named of the component class (e.g. org.omnifaces.component.script.DeferredScript). There is a common practice to define the component-typeas a static finalstring directly in component class and to name it COMPONENT_TYPE. Some developers tend to place the component-typestring directly in annotation, which somehow restricts the programmatic access to this information, since, by default, there is no public UIComponent.getComponentType()method to override. Components of different types can be grouped in families.

renderer-type - This is a piece of information that uniquely identifies a renderer (e.g. org.omnifaces.DeferredScript). A component will used its setRendererType()method to point to the render-typethat should render this component. Components can call this method as setRendererType(null)to point out that they will render themselves. But, by delegating the rendering to a separate renderer, the component makes itself more versatile because multiple renderers would be able to render it to different clients.

If you extend UIInput, you will inherit its type and family, but if you extend UIComponentBase, then you need to explicitly provide the component-type and component-family.

A Renderer is not selected based on the component-type and renderer-type! Is selected based on component-family and renderer-type, which allows a renderer to be used for multiple components in the same family. The component-typeis used for creating components in view root!

Overview of Renderer

What is the main goal of a renderer ?
Is responsible to decode the values from the incoming request and to encode the values to be displayed by transforming the component tree into the HTML markup that will be displayed to the client machine. Shortly, to transform a JSF component in markup (e.g. HTML, XML, etc).

When you commonly need a custom renderer ?
When you need to render a custom component (brand new or extension of a built-in one), because none of the built-ins do what you want to achieve.

When you want to alter the look/functionality of an built-in component.

What should I know before start writing a custom renderer ?
Mainly you need to know that a renderer extends directly/indirectly the Renderer class.
Starting with JSF 2.2, you can extend RendererWrapper, which is a simple implementation of Renderer. JSF 2.2 comes with many wrappers, which are simple implementations of what they are wrapping, and they help developer to override only the necessary methods, and to provide specialized behavior to an existing wrapped instance (e.g. RendererWrapper can be used for providing specialized behavior to an existing Renderer instance). The wrapped instance is available via the getWrapped()method.

The main three methods of a Renderer are encodeBegin(), encodeChildren() and encodeEnd(). By default, JSF calls them in this order, and the first one usually renders the beginning of the markup - "open" tags (e.g. <head>, <input>, <form>, etc), the second one  renders the children (this is configurable via getRendersChildren()flag), and the last one is ending the markup - "close" tags (e.g. </head>, </input>, </form>).

In order to link a component with a renderer, you should know how to work with the UIComponent.setRenderType()method and with the component-family, component-typeand renderer-typeartifacts as level of annotations or with the <render-kit>  and <renderer> tags in faces-config.xml.

How do I usually write a Renderer skeleton ?
•when you write a brand new component (extending UIComponentBase), you will extend the Rendererclass directly and override most of its methods. Usually in these cases you will link the custom component with the renderer via annotations and setRendererType()method.


More examples:

Create and render a brand new component (source code).

When you write a custom component which extends a built-in component, you usually extend the renderer of the built-in component also - directly (most probably) or indirectly. Usually in these cases you will link the custom component with the renderer via the setRenderType() method. Of course, you can also use the renderer of the built-in component without any modifications (source code).
When you just want to alter a built-in component at rendering level, you usually extend the built-in renderer and you instruct JSF to use your renderer instead of the default one via faces-config.xml, <renderer> tag. E.g. use a custom Renderer for the JSF UIOutputcomponent (source code). In order to run this application you have to keep in mind that we are extending a Mojarra renderer (com.sun.faces.renderkit.html_basic.TextRenderer), so you need to:

- manually install the JSF 2.2 JAR so your IDE will find the TextRenderer.
- in pom.xml, the entry for JSF 2.2 should have its scope set to provided, as it shouldn't be copied into the deployment.

Overview of RenderKit

What is the main goal of a RenderKit ?
While the Rendererclass converts the internal representation of UI components into markup (e.g. HTML), RenderKitrepresents a collection of Rendererinstances capable to render JSF UI component's instances for a specific client (for example, a specific device). Each time JSF needs to render a UI component, it will call the RenderKit.getRenderer()method which is capable of returning an instance of the corresponding renderer based on two arguments that uniquely identifies it: the component-family and the renderer-type. Moreover, RenderKitregisters renderers via RenderKit.addRenderer()method based on the component-family, renderer-typeand Renderer instance. When we write a correct renderer (respecting the JSF specification) JSF will automatically find it and register it for us.

When you commonly need a custom RenderKit ?
You may use a custom RenderKitto instruct JSF to delegate renderers in a specific approach. Per example, a custom RenderKitcan choose the right renderer depending on device (PC, tablet, iPhone, etc). Or, you may have a custom Rendererthat extends the RendererWrapper, and use a custom RenderKitto pass an instance of an existing Renderer to the custom Renderer.

What should I know before start writing a custom RenderKit ?
Mainly, you need to know that a custom RenderKit extends directly/indirectly the RenderKit class.

Starting with JSF 2.0, you can extend RenderKitWrapper, which is a simple implementation of RenderKit. Via RenderKitWrapper, you can provide a specialized behavior to an existing RenderKit instance. The wrapped instance is available via the getWrapped()method.

The main two methods of a RenderKit are addRenderer() and getRenderer(). By overriding these methods, you can take control over the Renderers registration and delegation. Of course, there are many other useful methods listed in documentation.

How do I usually write a RenderKit skeleton ?
Usually, you will extend the RenderKitWrapper class, override the necessary methods, and configure it in the faces-config.xmlvia <render-kit>tag.

So, as you can see in figure below, the RenderKit sits between components and renderers and act as a conductor:

Now, we know that each component is rendered after its component-family and renderer-type passes through the RenderKit.getRenderer()method:

public abstract Renderer getRenderer(java.lang.String family,
                                     java.lang.String rendererType)

This method match the correct renderer , like this:

private ConcurrentHashMap<String, HashMap<String, Renderer>> rendererFamilies =
  new ConcurrentHashMap<String, HashMap<String, Renderer>>();
...
HashMap<String,Renderer> renderers = rendererFamilies.get(family);
return ((renderers != null) ? renderers.get(rendererType) : null);

So, in order to obtain its renderer, each component must reveal its family (COMPONENT_FAMILY) and renderer-typeto this method (with a simple custom RenderKit you can check out the JSF/OmniFaces components families and renderer types). Programmatically, a family, component-family, is obtained via UIComponent.getFamily(), and the renderer-typevia UIComponent.getRendererType():

public abstract java.lang.String getFamily()
public abstract java.lang.String getRendererType()

Now, JSF search through available renderers that was added via RenderKit.addRenderer().  JSF has inspected faces-config.xml file for:

<render-kit>
    <renderer>
        <component-family>component-family</component-family>
        <renderer-type>renderer-type</renderer-type>
        <renderer-class>RendererClass</renderer-class>
    </renderer>
</render-kit>

 and all classes annotated with @FacesRenderer:

@FacesRenderer(componentFamily=ComponentClass.COMPONENT_FAMILY, rendererType= RendererClass.RENDERER_TYPE)
public class RendererClass extends Renderer {
 public static final String RENDERER_TYPE = "renderer-type";
 ...
}

Optionally, Facelets can be also informed by the render type in *taglib.xml. When you do that, you instruct Facelets to create a component of the given component-type. The component class is annotated with @FacesComponent or has been defined in faces-config.xml. In addition Facelets will set to the given renderer type.

<tag>
 ...
 <component>
  <component-type>component-type</component-type>
  <renderer-type>renderer-type</renderer-type>
 </component>
 ...
</tag>

Ok, so now let's have several examples of custom RenderKits:

Log how JSF renderers are added/delegated by JSF (source code).

Instruct JSF to render all components of a family via a common custom renderer (we simply apply a common CSS style to all components from javax.faces.Inputfamily) (source code).

Instruct JSF to render UIOutputcomponents via a custom renderer that was registered for other type of components, but pass to it an instance of the original renderer (source code).

Overview of a RendererKitFactory

What is the main goal of a RenderKitFactory ?
It manages (register/provide) instances of available RenderKits.

When you commonly need a custom RenderKitFactory ?
You may use a custom RenderKitFactoryto instruct JSF to delegate RenderKits in a specific approach. By default, JSF has a single RenderKit, identified by an ID, HTML_BASIC_RENDER_KIT. But, if want to write another RenderKitthen you can programmatically choose between them using a custom RenderKitFactory.

What should I know before start writing a custom RenderKitFactory ?
Mainly, you need to know that a render kit factory extends directly/indirectly the RendererKitFactoryclass.

The main two methods of a RenderKitFactory are addRenderKit() and getRenderKit() . By overriding these methods, you can take control over the RenderKits registration and delegation. The render kits IDs can be obtained via getRenderKitIds()method. If this factory has been decorated, the implementation doing the decorating may override the getWrapped()method to provide access to the implementation being wrapped.

In order to link a component with a renderer, you should know how to work with the UIComponent.setRenderType()method and with the component-family, component-typeand renderer-typeartifacts as level of annotations or with the <render-kit>  and <renderer> tag in faces-config.xml.

How do I usually write a RenderKitFactory skeleton ?
Usually, you will extend the RenderKitFactory class, override the necessary methods, and configure it in the faces-config.xmlvia <render-kit-factory>tag.

For example, replace the default JSF RenderKit with the DummyRenderKit (source code).


This post first appeared on OmniFaces & JSF Fans, please read the originial post: here

Share the post

JSF linking together components, renderers and render kits

×

Subscribe to Omnifaces & Jsf Fans

Get updates delivered right to your inbox!

Thank you for your subscription

×