Alexander Smirnov’s personal Weblog

April 8, 2011

RichFaces CDK: How To Create JSF Renderer

Filed under: Uncategorized — alexsmirnov @ 1:44 pm

JSF Renderer

JSF Renderer responsible for two functions, rendering component as HTML markup and processing request attributes. While processing attributes in the code usually is simple, generating markup in the Java code may be cumbersome for big components. Just by human mind nature, it would be hard to imagine how calls to ResponseWrited converted to HTML, and then imagine the second transformation, from html and CSS to visual representation.
Also, each element and attribute require five times more characters when generated string itself, that makes renderer code much bigger when original design.
JSF 2.0 offers “composite components” for code reuse, but native component developer still have to write dosens of startElement/writeAttribute/writeText/endElement calls.
RichFaces CDK closes a gap between component html design and Java code. It lets developer to create xhtml template, similar to the composite component and converts that template to Java code. That templates reuses JSF 2 composite component syntax where possible, what lets developers to prototype component as composite and convert it into native for production, with better performance and extended functionality/

Renderer Template

Base structure

Same as JSF composite component, Renderer template is well-formed XML file. The main difference that CDK template should have document element <root> from the cdk namespace “http://jboss.org/schema/richfaces/cdk/core&#8221;. To allow XML validation for non-standard html attributes, the default namespace should be “http://jboss.org/schema/richfaces/cdk/xhtml-el&#8221;, associated with CDK xml schema. The full list of template schemes described in the table below:

Namespace URI Schema location Description
http://jboss.org/schema/richfaces/cdk/xhtml-el&#8221; http://jboss.org/schema/richfaces/cdk/xhtml-el.xsd HTML 4.0.1 with CDK extensions.
http://jboss.org/schema/richfaces/cdk/core&#8221; http://jboss.org/schema/richfaces/cdk/cdk-template.xsd CDK template document
http://jboss.org/schema/richfaces/cdk/jstl/core&#8221; http://jboss.org/schema/richfaces/cdk/cdk-jstl-core.xsd CDK version of JSTL tags
http://jboss.org/schema/richfaces/cdk/jsf/composite&#8221; http://jboss.org/schema/richfaces/cdk/cdk-composite.xsd CDK version of JSF 2 composite component tags
http://jboss.org/schema/richfaces/cdk/ext&#8221; http://jboss.org/schema/richfaces/cdk/cdk-extensions.xsd Extensions for html attributes to process component pass-throuth attributes

Same as for JSF composite component, CDK contains two main sections: interface with meta information necessary to generate Renderer and implementation with HTML markup.

<composite:interface> Element

Interface section supports <composite:attribute> elements from the JSF composite component, with children <composite:clientBehavior>. The syntax is same as for composite component, while meaning is different: These elements define renderer-specific component attributes. If rendered-specific component generated by CDK, these attributes will be added to the component, and generated code will use getter and setter methods for them instead of attributes Map.
In addition, there are CDK-specific elements used by CDK only:

  • <cdk:class>, the content of that element should be full-qualified Java class name for generated renderer. By default, CDK infer name for generated class by naming conventions.
  • <cdk:superclass>, the content of that element should be full-qualified Java class name for generated Renderer superclass. That class should extend javax.faces.render.Renderer, and can be used to put decode logic and helper methods. By default, renderer extends javax.faces.render.Renderer class.
  • <cdk:component-family>, the content of that element should contain JSF component family ID, used to associate renderer with component. By default, that walue calculated by naming conventions or taken from UIComponent class annotation that contains renderer attribute referrenced to this template.
  • <cdk:renderer-type>, the content of that element contains JSF Renderer type assigned to the generated renderer. Same as for component family, its value can be inferred or taken from UIComponent.
  • <cdk:renderkit-id> defines JSF render kit for which generated rendered belongs to. By default, it’s JSF HTML_BASIC render kit.
  • <cdk:renders-children>, its content contains logical value ( true or false ) that should be returned from getRendersChildren method. By default, CDK doesn’t override that method from superclass.
  • <cdk:import> defines additional Java import directives for generated class. Attributes:
    • package – fully qualified Java package name
    • names – short names for imported classes, comma-separated list
    • static – tells CDK to generate “import static” directive
  • <cdk:import-attributes> allows CDK to import attributes definition from faces-config fragment, same as used by the @JsfComponent#attributes . The ‘src’ attributes should contain URL for that fragment.
  • <cdk:resource-dependency> defines JSF resource used by the component. Resource defined by that element added to @ResourceDependencies annotation for generated type. Attributes:
    • name – defines resource name.
    • library – optional, defines resource library name
    • target – optional, forces resource to be rendered in html head, body, or form element.

<composite:implementation>

While <interface> section defines meta-information, most of the Renderer code generated from the content of <implementation> element. Html content of that element converted to calls of startElement/writeAttribute/endElement ResponseWriter methods.

Encoding children components

JSF Renderer has three methods that participate in encoding process: encodeBegin, encodeChildern and encodeEnd. For components that do not contain children elements ( input field, for example ), it’s better to perform encoding in the single method, usually encodeEnd. If component children encoded in the natural order, developer can left default encodeChildren functionality and render component prolog in the encodeBegin() and finish it in the encodeEnd. For components that can change rendering sequence of its children, rendering of content usually performed in the encodeChildren mathod, with rendersChildren method returns true ( see <cdk:renders-children> element above ).
To define methods used for encoding, developer can put <cdk:body> element. Everything before that element going to the encodeBegin method, and rest of the <composite:implementation> content after <cdk:body> going to the encodeEnd. If this element is empty, no encodeChildren method generated unless ‘enforce’ attribute set to true, so encoding of children components performing by default in superclass. Otherwise, content of <cdk:body> generated inside encodeChildren method.

EL-expressions

CDK evaluates Expression Language statements into Java code. It supports Expression Language 2.2 syntax, and recognises their argument types where possible. Because expressions generates as the Java code, the type checking is more strict when it allowed in the dynamic interpreter. For example it impossible to access to unknown method or field if argument recognized as Object.
EL-expressions allowed in text, html attributes, and flow control directives. CDK does not recognise EL-expressions as HTML element names yet.
To call method that returns void, use <cdk:call> element, with call expression provided in element body or by the ‘expression’ attribute.

Flow control

CDK supports JSTL-like directives to control rendering:

  • <c:if> element used to generate Java if() statements. Content of the ‘test’ attribute used to generate condition expression, usually from EL-expression.
  • <c:choose> with <c:when> and <c:otherwise> children elements used to chain Java if() …else if() … else statements. ‘test’ attribute of each <c:when> element used to generate conditions, and content of the <c:otherwise> going to the final else {} block.
  • <c:forEach> used for iterations over collections. Its ‘items’ attribute should be evaluated to Java Collection or array ( Iterator/Enumeration not supported yet ), and variable defined by ‘var’ attribute can be used in EL-expressions inside iteration.

In addition, there is <cdk:switch> with <cdk:case> and <cdk:default> elements using to construct Java ‘switch’ directives. The ‘key’ attribute used to define switch() condition, and ‘values’ attribute from <cdk:case> used to generate case … : statement condition. Of course, these expression should be evaluated to types which valid for Java switch/case statement.

Variables

CDK can assign computation results to variables, which can be used in EL-expressions. Predefined variable names are:

  • component – the UIComponent used to call Renderer#encode…() method.
  • facesContext – the current FacesContext instance.
  • clientId – client id of component used to call Rendered method.
  • responseWriter – instance of JSF ResponceWriter used to write Renderer output.

Developer can define his own variables using <cdk:object> element. The variable name defined by the ‘name’ attribute, and value evaluated from the ‘value’ attribute or element body.
The scope of object is the current Java block, hence objects defined in the different parts sepatated by the <cdk:body> statement are not visible in another parts because they are going in different methods. Also, variables defined inside flow control elements are not visible outside of element.

Attributes

In the typical component, most HTML attributes generated from the component attributes. There are two cases for each attribute:

  1. Attribute value generated as the String.
  2. Pass throw attribute, which content comes from the component attribute, with optional behavior-generated event handlers.

For the first case, developer can provide attribute value as literal or EL-expression. CDK recognises HTML 4 schema ( no HTML5 schema implemented yet ) and properly render URL and boolean values.
In the second case, use attributes from the CDK extensions namespace. Each html attribute has its ‘extension’ version. For these attributes, cdk threat attribute value as the name of the component attribute from which attribute value comes. If component attribute was not set, no html attribute will be rendered. For attributes with associated ClientBehavior events component renders scripts from all behaviors for that event.
To reduce the number of code in component template, there are three attributes for bulk operations:

  • cdk:passThroughWithExclusions, that renders all attributes allowed for html element except ones defined in attribute value ( space separated list ). CDK expect that component attribute name the same as for html. That’s useful to render single-element components or for the root element.
  • cdk:passThrough renders all attributes defined in its value ( space-separated list ). If component and html attributes have the same name, it typed as is. Otherwise, developer can provide component attribute name separated by colon, for example: <cdk:passThrough=” style class:styleClass”, what means render component ‘style’ attribute as html style, and component#styleClass as HTML class.

 

4 Comments »

  1. Most of the RichFaces 4 components built using CDK, you can get source code from github: https://github.com/richfaces

    Comment by alexsmirnov — June 23, 2011 @ 2:58 pm

  2. Hi Alex,

    I’ve done the tutorial for RF 3.3.3 and learned how to make the components using the old style. Now I’m trying to use RF 4, but I’m coming up to the lack of documentation on implementing specific details for the API. Do you have a working set of code for a component (maybe something as simple as an input box, or something slightly more complex)? My end goal is to modify extendedDataTable to read even more metadata from an object, but I’m trying to get off the ground.

    Thanks!

    Comment by Larry Anderson — June 22, 2011 @ 6:58 am

    • Right now I’m at the point of writing the renderer XML file.

      Comment by Larry Anderson — June 22, 2011 @ 6:58 am

      • I compile my renderer XML file and the error I get says….

        [ERROR] error: XML error
        [DEBUG] Validate model
        [total 1019ms]
        [INFO] ————————————————————————
        [ERROR] BUILD ERROR
        [INFO] ————————————————————————
        [INFO] CDK build error

        Embedded error: Compilation error

        Which doesn’t really help me enough, it’d be nice to know more specifics…

        Comment by Larry Anderson — June 23, 2011 @ 12:24 pm


RSS feed for comments on this post. TrackBack URI

Leave a comment

Create a free website or blog at WordPress.com.