You may also want to see:
What is the main goal of a RenderKit ?
·
While the Renderer class converts the
internal representation of UI components into markup (e.g. HTML), RenderKit
represents a collection of Renderer instances 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, RenderKit
registers renderers via RenderKit.addRenderer() method based on the component-family,
renderer-type
and 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 RenderKit to instruct
JSF to delegate renderers in a specific approach. Per example, a custom RenderKit
can choose the right renderer depending on device (PC, tablet, iPhone, etc).
Or, you may have a custom Renderer that extends the RendererWrapper,
and use a custom RenderKit to pass an instance of an existing Renderer
to the custom Renderer.
Or, you can write a custom RenderKit to add support for HTML5 specific
attributes, like the OmniFaces Html5RenderKit.
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.xml
via <render-kit>
tag
e.g. log how
JSF renderers are added/delegated by JSF - GitHub Complete Code [CustomRenderKitSkeleton_1]
DummyRenderKit
public class
DummyRenderKit extends RenderKitWrapper {
private static final Logger LOG =
Logger.getLogger(DummyRenderKit.class.getName());
private RenderKit renderKit;
public DummyRenderKit() {
}
public DummyRenderKit(RenderKit renderKit) {
LOG.log(Level.INFO, "Default RenderKit
instance provided by JSF: {0}", renderKit.getClass().getSimpleName());
this.renderKit = renderKit;
}
@Override
public Renderer getRenderer(String family,
String rendererType) {
LOG.log(Level.INFO, "--- Delegating
renderer of type {0} for component in family {1} ---", new
Object[]{rendererType, family});
return getWrapped().getRenderer(family,
rendererType);
}
@Override
public void addRenderer(String family, String
rendererType, Renderer renderer) {
LOG.log(Level.INFO, "--- Adding the
renderer of type {0} for component in family {1} ---", new
Object[]{rendererType, family});
getWrapped().addRenderer(family,
rendererType, renderer);
}
@Override
public RenderKit getWrapped() {
return
renderKit;
}
}
faces-config.xml
...
<render-kit>
<render-kit-class>
jsf.renderkits.DummyRenderKit
</render-kit-class>
</render-kit>
...
e.g. 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.Input
family) - GitHub Complete Code [CustomRenderKitSkeleton_3]
DummyRenderer
@ResourceDependencies({
@ResourceDependency(name =
"css/styles.css", library = "default", target =
"head")
})
@FacesRenderer(componentFamily
= "javax.faces.all.Input", rendererType =
DummyRenderer.RENDERER_TYPE)
public class
DummyRenderer extends RendererWrapper {
private static final Logger LOG =
Logger.getLogger(DummyRenderer.class.getName());
public static final String RENDERER_TYPE =
"javax.faces.all";
private Renderer renderer;
public DummyRenderer() {
}
public DummyRenderer(Renderer renderer) {
this.renderer = renderer;
}
@Override
public boolean getRendersChildren() {
LOG.info("--- Rendering DummyComponent -
getRendersChildren() method ---");
return getWrapped().getRendersChildren(); //
calls the wrapped#getRendersChildren()
}
@Override
public void encodeBegin(FacesContext context,
UIComponent component) throws IOException {
LOG.info("--- Rendering DummyComponent -
encodeBegin() method ---");
getWrapped().encodeBegin(context, component);
// calls the wrapped#encodeBegin()
}
@Override
public void encodeChildren(FacesContext
context, UIComponent component) throws IOException {
LOG.info("--- Rendering DummyComponent -
encodeChildren() method ---");
getWrapped().encodeChildren(context,
component); // calls the wrapped#encodeChildren()
}
@Override
public void encodeEnd(FacesContext context,
UIComponent component) throws IOException {
LOG.info("--- Rendering DummyComponent -
encodeEnd() method [adding the common CSS style] ---");
ResponseWriter responseWriter =
context.getResponseWriter();
responseWriter.writeAttribute("class", "inputs",
"class");
getWrapped().encodeEnd(context, component);
// calls the wrapped#encodeChildren()
}
@Override
public Renderer getWrapped() {
return renderer;
}
}
DummyRenderKit
public class
DummyRenderKit extends RenderKitWrapper {
private static final Logger LOG =
Logger.getLogger(DummyRenderKit.class.getName());
private RenderKit renderKit;
public DummyRenderKit() {
}
public DummyRenderKit(RenderKit renderKit) {
LOG.log(Level.INFO, "Default RenderKit
instance provided by JSF: {0}", renderKit.getClass().getSimpleName());
this.renderKit = renderKit;
}
@Override
public Renderer getRenderer(String family,
String rendererType) {
//
instruct JSF to use the DummyRenderer for each component that belongs to the
"javax.faces.Input" family
if
(family.equals("javax.faces.Input")) {
LOG.log(Level.INFO, "--- Delegating
renderer of type {0} for component in family {1} ---", new
Object[]{rendererType, family});
Renderer renderer =
getWrapped().getRenderer(family, rendererType);
return new DummyRenderer(renderer);
}
return getWrapped().getRenderer(family,
rendererType);
}
@Override
public RenderKit getWrapped() {
return
renderKit;
}
}
e.g. instruct
JSF to render UIOutput
components via a custom renderer that was registered for other type of
components, but pass to it an instance of the original renderer - GitHubComplete Code [CustomRenderKitSkeleton_2]
DummyRenderer
@FacesRenderer(componentFamily
= "javax.faces.cool.Output", rendererType =
DummyRenderer.RENDERER_TYPE)
public class
DummyRenderer extends RendererWrapper {
private static final Logger LOG = Logger.getLogger(DummyRenderer.class.getName());
public static final String RENDERER_TYPE =
"javax.faces.cool.Text";
private Renderer renderer;
public DummyRenderer() {
}
public DummyRenderer(Renderer renderer) {
this.renderer = renderer;
}
@Override
public boolean getRendersChildren() {
LOG.info("--- Rendering DummyComponent -
getRendersChildren() method ---");
return getWrapped().getRendersChildren(); //
calls the TextRenderer#getRendersChildren()
}
@Override
public void encodeBegin(FacesContext context,
UIComponent component) throws IOException {
LOG.info("--- Rendering DummyComponent -
encodeBegin() method ---");
getWrapped().encodeBegin(context, component);
// calls the TextRenderer#encodeBegin()
}
@Override
public void encodeChildren(FacesContext
context, UIComponent component) throws IOException {
LOG.info("--- Rendering DummyComponent -
encodeChildren() method ---");
getWrapped().encodeChildren(context,
component); // calls the TextRenderer#encodeChildren()
}
@Override
public void encodeEnd(FacesContext context,
UIComponent component) throws IOException {
LOG.info("---
Rendering DummyComponent - encodeEnd() method ---");
getWrapped().encodeEnd(context, component);
// calls the TextRenderer#encodeEnd()
}
@Override
public Renderer getWrapped() {
return
renderer;
}
}
DummyRenderKit
public class
DummyRenderKit extends RenderKitWrapper {
private static final Logger LOG =
Logger.getLogger(DummyRenderKit.class.getName());
private RenderKit renderKit;
public DummyRenderKit() {
}
public DummyRenderKit(RenderKit renderKit) {
LOG.log(Level.INFO, "Default RenderKit
instance provided by JSF: {0}", renderKit.getClass().getSimpleName());
this.renderKit = renderKit;
}
@Override
public void addRenderer(String family, String
rendererType, Renderer renderer) {
//
notify when our custom dummy renderer is registered by JSF
if(family.equals("javax.faces.cool.Output")
&&(rendererType.equals(DummyRenderer.RENDERER_TYPE))){
LOG.info("Your dummy renderer was
registered !");
}
super.addRenderer(family, rendererType,
renderer);
}
@Override
public Renderer getRenderer(String family,
String rendererType) {
// instruct JSF to use the DummyRenderer
instead of TextRenderer, but pass a TextRenderer instance to it
if
(family.equals("javax.faces.Output") &&
(rendererType.equals("javax.faces.Text"))) {
LOG.log(Level.INFO, "--- Delegating
renderer of type {0} for component in family {1} ---", new
Object[]{rendererType, family});
Renderer renderer = getWrapped().getRenderer(family, rendererType);
return new DummyRenderer(renderer);
}
return getWrapped().getRenderer(family,
rendererType);
}
@Override
public RenderKit getWrapped() {
return renderKit;
}
}
Niciun comentariu :
Trimiteți un comentariu