My JSF Books/Videos My JSF Tutorials OmniFaces/JSF PPTs
JSF 2.3 Tutorial
JSF Caching Tutorial
JSF Navigation Tutorial
JSF Scopes Tutorial
JSF Page Author Beginner's Guide
OmniFaces 2.3 Tutorial Examples
OmniFaces 2.2 Tutorial Examples
JSF Events Tutorial
OmniFaces Callbacks Usages
JSF State Tutorial
JSF and Design Patterns
JSF 2.3 New Features (2.3-m04)
Introduction to OmniFaces
25+ Reasons to use OmniFaces in JSF
OmniFaces Validators
OmniFaces Converters
JSF Design Patterns
Mastering OmniFaces
Reusable and less-verbose JSF code

My JSF Resources ...

Java EE Guardian
Member of JCG Program
Member MVB DZone
Blog curated on ZEEF
OmniFaces is an utility library for JSF, including PrimeFaces, RichFaces, ICEfaces ...

[OmniFaces Utilities] - Find the right JSF OmniFaces 2 utilities methods/functions

Search on blog

Petition by Java EE Guardians

Twitter

marți, 3 februarie 2015

JSF 2.2 - Write Custom RenderKit Skeleton

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

JSF BOOKS COLLECTION

Postări populare

OmniFaces/JSF Fans

Follow by Email

Visitors Starting 4 September 2015

Locations of Site Visitors