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.

 

Advertisement

April 6, 2011

RichFaces CDK – how to create JSF component

Filed under: Java, Java server faces — alexsmirnov @ 3:48 pm
JSF component if pretty complicated beast. In the worst case, you have to create UIComponent class, with a lot of attributes with special getter’s and setters that interacts with StateHelper,  renderer-specific class that contains similar attributes for html-related parameters ( even worse, they require special code if you wish to use attributes access optimization in Renderer ) and defines JSF Behavior events for them, create Renderer class that generates html code using spaghetti of startElement/writeAttribute/writeText/endElement calls, describe these classes in the faces-config.xml, create Facelets taglib.xml to define component as VDL tag, write TagHandler class. If your component fires FacesEvents for some listeners, you also need Listener interface and listener TagHandler with default ListenerWrapper.
Similar work required for the ClientBehavior, except renderer-specific implementation.
Faces Converters and Validators a little bit simple because they don’t require separate renderers and cannot broadcast events.
RichFaces uses special Component Development Kit ( CDK ) that takes rid for most of these tasks and lets developers to concentrate on component functionality only.
In the best case, developer has to only create abstract component class, with functional code only, and Renderer template that describes generated Html with Facelets-like syntax. Everything else generated by the tool.

Define Java Package as Components Library

By default, all components in the same projects included to the same library. Developer can provide package-level annotation to define library for all components which belong to that package
package-info.java:
@TagLibrary(uri=”http://richfaces.org/test&#8221;,shortName=”testLib”)
package org.richfaces.cdk.test.component;
import org.richfaces.cdk.annotations.TagLibrary;

Abstract Component Class

Most JSF components contains only a few lines of functional code. With cdk, developer can only create java class with such functionality and lets boilerplate to be generated.

Base Class

The base class can be abstract if it need references to generated methods. That class should be annotated with @JsfComponent annotation that describes generation details:
@JsfComponent(type = “foo.Bar”,
family=”foo.Bar”,
description=@Description(displayName=”Bar Component”,
largeIcon=”large.gif”,
smallIcon=”spall.png”),
generate=”foo.component.UIBar”,
facets=@Facet(name=”caption”,
generate=true,
description=@Description(“Caption Facet”)),
fires={@Event(FooEvent.class),
@Event(value=BarEvent.class,listener=BarListener.class)},
interfaces=Ext.class,         tag=@Tag(name=”abbr”,generate=true,handler=”foo.facelets.barHandler”),
attributes={“core-props.xml”,
“events-props.xml”,
“i18n-props.xml”},
renderer=@JsfRenderer(type=”foo.HtmlBarRenderer”)),
)
public abstract class AbstractBarComponent extends UIComponentBase

For type-safe definition, optional annotations defined as @JsfComponent attributes, so Java compoler can check their usage and code competition available in modern editors. All annotation attributes are optional and can be inferred by CDK:

  • type() defines JSF component type, used as key when framework creates component instance. Its value can be also defined by public constant COMPONENT_TYPE or inferred from the class name by Naming Conventions#.
  • family() defines component family, common for the group of similar components ( for example, UICommand, HtmlCommandButton and HtmlCommandLink all share “javax.faces.Command” family ).
  • description() defines optional description of component, used by JSF tools and documentation generator. Full description comes from the class JavaDoc comment or can be defined by value() attribute.
  • generate() defines the fully qualified name for concrete component class. There are two options for default value of that attribute. If @JsfAnnotation applied to the abstract class, the name of generated class will be inferred from Naming Conventions. Otherwise, if annotated class is concrete, CDK will not generate concrete component class and use annotated class as component implementation.
  • facets()  defines component facets. It’s array of @Facet annotations. Facet#generate() attribute tells CDK to generate getter and setter for facet.
  • fires() is array of @Event annotations which define JSF events fired by components. It defines FacesEvent class for event, listener and source interface. For each event, CDK generates add/remove/get<Event>Listener methods defined by the source interface, creates eventListener tag handler and creates listener instance that can be binded to EL-expression.
  • tag() is array of @Tag annotations. Using multiply tags for single component is necessary to define tags for different VDL ( View Description Language ), or make aliases. Tag links JSF component and its renderer. If no tag defined for component, but there is Renderer associated with component, Facelets tag will be generated. Tag name, handler class and library will be inferred.
  • attributes() contains array of strings, each contains the name of faces-config.xml fragment with attributes definitions, that lets CDK to reuse attributes definition in different components. CDK looks for these files in project classpath META-INF/cdk/attributes folder, and provides set of such files for the most html elements and standard components.
  • renderer() associates component with Renderer implementation. There are two options to link component with renderer#: by the renderer type or by the template name. For type, CDK doesn’t check existence of the target renderer, because it would be defined in another module. For template name, CDK enforces both renderer and component to share the same renderer type and family.
  • interfaces() attribute contains array of Java interface classes that should be implemented by generated component, that provides another way to reuse attributes definitions in different components, similar to ‘attributes()’ option. That’s preferred method for user attributes, because it allows type-safe check. The result is the same as including these interfaces in ‘implements’ keyword for component class, but it does not enforce component class to be abstract, and can be used to define interfaces implemented by the renderer-specific components ( see late ).

Renderer Specific Components

In JSF, the single component can have more then one renderer, to allow different client-side representations of the same functionality. For example, base command UICommand component can be rendered as html button ( <input> element ) or link ( <a> element ). Because these representations can have different attributes and ClientBehavior events, JSR best practices recomment to have renderer-specific component that contains bean attributes for specific implementation. CDK follows that structure and lets developer to define renderer-specific components in the base class using @JsfComponent#components() attribute.
This attribute contains array of @RendererSpecificComponents annotations which have the same set of attributes as @JsfComponent, except the family() that should be shared by all components. These annotations lets to define third level of generated classes, specific to the particular renderer.

Define Attributes

JSF component attributes not are plain bean getters and setters, they can contains code to evaluate EL-expressions, and to persist value in the View state. Also, some attributes can be associated with ClientBehavior events. CDK generates all code to make attributes compatible with JSF spec.
To define component attribute, developer can annotate class field or getter method with @Attribute annotation. The method can be abstract, that allows to use that annotation in the interfaces or abstract classes:
@Attribute(
aliases={@Alias(“getAction”)},
defaultValue=”null”,
description=@Description(),
events={@EventName(value=”click”,defaultEvent=true)},
hidden=false,
literal=false,
passThrough=false,
readOnly=true,
required=false,
generate=true,
suggestedValue=”#{foo}”,
signature = @Signature(parameters = {String.class},
returnType = Boolean.class))
public abstract MethodExpression getMethodExpression();
Same as for the @JsfComponent, all annotation attributes are optional.

  • aliases() lets to define different names for the single attribute. In the example above, CDK will generate public MethodExpression getAction(){ return getMethodExpression();}
  • defaultValue() should contain valid Java expression evaluated to the default attribute value.
  • description() contains attribute description for IDE and documentation, the same annotation used elsewhere in CDK. By default, CDK uses method JavaDoc comment to generate description.
  • events() contains array of ClientBehavior events definition. The value of EventName annotation is name itself, and defaultEvent defines marks event as component default#.
  • hidden() attribute tells CDK to remove attribute from tag.
  • literal() disables EL- expressions for attribute.
  • passThrough() defines attribute to be rendered as html attribute without conversion. Attributes with ClientBehavior events always threated as passed through.
  • readOnly disables generation for the setter method.
  • requires() enforces tag handler to check what developer provided explicit value for that attribute.
  • geterate() enforces CDK to generate getter and setter methods for attribute, even if concrete method already exist. If omitted, CDK checks ‘abstract’ modifier for getter and setter methods and generate implementation for abstract methods only.
  • suggestedValue can be used in tools for code competition.
  • signature() only used for attributes with MethodExpression type to define signature of the target method.

Define Facets

Component facets can be defined in the two ways: in the facets() attribute of component annotations ( described above ) or by the getter method @Facet annotation:
@Facet(generate=true,
description=@Description())
public abstract UIComponent getHeader();
The ‘name()’ attribute is optional in this case, CDK uses bean attribute name instead. Same as for the attribute, it uses JavaDoc comment to generate description and generate implementation for abstract methods.

Blog at WordPress.com.