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

luni, 2 februarie 2015

JSF 2.2 - Write Custom Renderer Skeleton

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-type and renderer-type artifacts as level of annotations or with the <render-kit>  and <renderer> tags in faces-config.xml. A detailed dissertation about them is the OmniFacesCustom Components Approach post. OmniFaces provides solid techniques for writing custom components and renderers!

How do I usually write a Renderer skeleton ?
·         when you write a brand new component (extending UIComponentBase), you will extend the Renderer class 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.

e.g. Create and render a brand new component - GitHubComplete Code [CustomRendererSkeleton_1]

DummyComponent 
@FacesComponent(value = DummyComponent.COMPONENT_TYPE, createTag = true)
public class DummyComponent extends UIComponentBase {

 public static final String COMPONENT_FAMILY = "jsf.components";
 public static final String COMPONENT_TYPE = "jsf.components.DummyComponent";

 public DummyComponent() {
  setRendererType(DummyRenderer.RENDERER_TYPE);
 }

 @Override
 public String getFamily() {
  return COMPONENT_FAMILY;
 }
}

DummyRenderer
@FacesRenderer(componentFamily = DummyComponent.COMPONENT_FAMILY, rendererType = DummyRenderer.RENDERER_TYPE)
public class DummyRenderer extends Renderer {

 public static final String RENDERER_TYPE = "jsf.renderers.DummyRenderer";
 private static final Logger LOG = Logger.getLogger(DummyRenderer.class.getName());

 public DummyRenderer(){       
 }
   
 @Override
 public Object getConvertedValue(FacesContext context, UIComponent component, Object submittedValue) throws ConverterException {
  return super.getConvertedValue(context, component, submittedValue);
 }

 @Override
 public boolean getRendersChildren() {
  return super.getRendersChildren();
 }

 @Override
 public String convertClientId(FacesContext context, String clientId) {
  return super.convertClientId(context, clientId);
 }   

 @Override
 public void encodeBegin(FacesContext context, UIComponent component) throws IOException {
  LOG.info("--- Rendering DummyComponent - encodeBegin() method ---");
  super.encodeBegin(context, component);
 }
   
 @Override
 public void encodeChildren(FacesContext context, UIComponent component) throws IOException {
  LOG.info("--- Rendering DummyComponent - encodeChildren() method ---");
  super.encodeChildren(context, component);
 }
   
 @Override
 public void encodeEnd(FacesContext context, UIComponent component) throws IOException {
  LOG.info("--- Rendering DummyComponent - encodeEnd() method ---");
  super.encodeEnd(context, component);
 } 

 @Override
 public void decode(FacesContext context, UIComponent component) {
  LOG.info("--- Rendering DummyComponent - decode() method ---");
  super.decode(context, component);
 }
}
·         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.

e.g. Create and render a component that extends the UIOutput -  GitHubComplete Code [CustomRendererSkeleton_2]

DummyComponent
@FacesComponent(createTag = true)
public class DummyComponent extends UIOutput { 
   
 // inherits the UIOutput component-family: javax.faces.Output
 //default renderer-type: javax.faces.Text is replaced by DummyRenderer
   
 public DummyComponent() {
  setRendererType(DummyRenderer.RENDERER_TYPE);        
 }       
}

DummyRenderer
@FacesRenderer(componentFamily = DummyComponent.COMPONENT_FAMILY, rendererType = DummyRenderer.RENDERER_TYPE)
public class DummyRenderer extends TextRenderer {

 private static final Logger LOG = Logger.getLogger(DummyRenderer.class.getName());
 public static final String RENDERER_TYPE = "jsf.renderers.DummyRenderer";

 public DummyRenderer(){          
 }

 @Override
 public void encodeChildren(FacesContext context, UIComponent component) throws IOException {
  LOG.info("--- Rendering DummyComponent - encodeChildren() method ---");
  super.encodeChildren(context, component); // calls the TextRenderer#encodeChildren()
 }

 @Override
 public boolean getRendersChildren() {
  LOG.info("--- Rendering DummyComponent - getRendersChildren() method ---");
  return super.getRendersChildren(); // calls the TextRenderer#getRendersChildren()
 }

 @Override
 protected void getEndTextToRender(FacesContext context, UIComponent component, String currentValue) throws IOException {
  LOG.info("--- Rendering DummyComponent - getEndTextToRender() method ---");
  super.getEndTextToRender(context, component, currentValue); // calls the TextRenderer#getEndTextToRender()
 }

 @Override
 public void encodeBegin(FacesContext context, UIComponent component) throws IOException {
  LOG.info("--- Rendering DummyComponent - encodeBegin() method ---");
  super.encodeBegin(context, component); // calls the TextRenderer#encodeBegin()
 }       
}

·         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 UIOutput component, GitHub Complete Code [CustomRendererSkeleton_3]

DummyRenderer
public class DummyRenderer extends TextRenderer {

 private static final Logger LOG = Logger.getLogger(DummyRenderer.class.getName());
 public static final String RENDERER_TYPE = "jsf.renderers.DummyRenderer";

 public DummyRenderer(){           
 }

 @Override
 public void encodeChildren(FacesContext context, UIComponent component) throws IOException {
  LOG.info("--- Rendering DummyComponent - encodeChildren() method ---");
  super.encodeChildren(context, component); // calls the TextRenderer#encodeChildren()
 }

 @Override
 public boolean getRendersChildren() {
  LOG.info("--- Rendering DummyComponent - getRendersChildren() method ---");
  return super.getRendersChildren(); // calls the TextRenderer#getRendersChildren()
 }

 @Override
 protected void getEndTextToRender(FacesContext context, UIComponent component, String currentValue) throws IOException {
  LOG.info("--- Rendering DummyComponent - getEndTextToRender() method ---");
  super.getEndTextToRender(context, component, currentValue); // calls the TextRenderer#getEndTextToRender()
 }

 @Override
 public void encodeBegin(FacesContext context, UIComponent component) throws IOException {
  LOG.info("--- Rendering DummyComponent - encodeBegin() method ---");
  super.encodeBegin(context, component); // calls the TextRenderer#encodeBegin()
 }       
}

faces-config.xml
...
<application>
 <render-kit>           
  <renderer>
   <component-family>javax.faces.Output</component-family>
   <renderer-type>javax.faces.Text</renderer-type>
   <renderer-class>jsf.renderers.DummyRenderer</renderer-class>
  </renderer>
 </render-kit>
</application>
...

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