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 martie 2015

JSF 2.2 - Write Custom TagHandler Skeleton

What is a tag handler ?
·         Let's say that you have created a custom tag, and you have placed it somewhere in your XHTML page (e.g. <mt:dummy>). When JSF builds the component tree, it will traverse the page tags, and, at some moment in time, it will "meet" your tag. This is the time when a tag handler is executed (if there is a tag handler associated to this tag!). So, a tag handler is just an optional snippet of code executed when JSF "meets" a tag (built-in or custom) in the XHTML page.

What is the main goal of a tag handler ?
·         Basically, a tag handler is capable to access and modify the JSF component tree that is currently built (e.g. modify its parent). You have to keep in mind that when a tag handler is executed, the component tree is partially built/restored, which means that some components exist, while others doesn't exist yet. The tag handler can manipulate the JSF component tree safely, but you have to pay attention on how you manipulate it.

When you commonly need a custom tag handler ?
·         Is useful when you need to "pinch" some components from component tree. You can even use it to add/remove components, or to write your own JSTL-like tags/functions. Moreover, tag handlers can be used to implement validation stuff (e.g. see OmniFaces, <o:validateBean>).

What should I know before start writing a custom tag handler ?
·         A tag handler extends the TagHandler class
·         Do not confuse a tag handler with a component handler! A custom tag handler for a component, converter, validator, or behavior will extend ComponentHandler, not TagHandler. Tag handlers are useful only when the component tree is build and they don't correspond to a component.
·         The tag handler is passed the configuration of the tag (TagConfig) - this take place in the tag handler constructor. Among other things, this configuration contains the Tag object generated by the TagDecorator. So, the tag handler contains a reference to the Tag instance corresponding to this TagHandler instance. Moreover, it provides a shortcut for TagConfig.getTagId(), as tagId.
·         The Tag attributes are available via getAttribute() and getRequiredAttribute() methods. The later is for required attributes, and, basically, it invokes getAttribute() and check if the returned result is null or not. If it is null, then it simply throw a TagException. Otherwise, it returns the attribute, which is an instance of TagAttribute - representation of an XML attribute name=value pair on an XML element in a Facelet file.
·         JSF signal the fact that it has identified your tag by calling the tag handler apply() method. This is the "playground" of a tag handler. Here, you will have access to the FaceletContext and to the parent component of this tag, so, to the available component tree.

How do I usually write a tag handler skeleton ?
·         There are several simple steps to follow, and the first one consist in writing a class that extends the TagHandler.
·         Secondly, you need a constructor with a TagConfig argument and use this argument to call the super.
·         Third, you need to override the apply() method - here, you place the code for "pinching" the component tree.
·         Finally, attach the tag handler to the tag name in a *.taglib.xml file, and register the *.taglib.xml file in web.xml via javax.faces.FACELETS_LIBRARIES context parameter.

DummyTagHandler
public class DummyTagHandler extends TagHandler {
   
public DummyTagHandler(TagConfig config) {
  super(config);
 }

 @Override
 public void apply(FaceletContext ctx, UIComponent parent) throws IOException {
  // your job here      
 }
}

dummy.taglib.xml
...
<namespace>http://jsf.taghandlers.skeleton/dummy</namespace>   
<tag>
 <tag-name>dummy</tag-name>
 <handler-class>jsf.taghandlers.DummyTagHandler</handler-class>
 <attribute>
  <description>
   <![CDATA[
      The text that will be repeated
   ]]>
  </description>
  <name>text</name>
  <required>true</required>
  <type>java.lang.String</type>
 </attribute>
   
 <attribute>
  <description>
   <![CDATA[
      The number of times to repeat the text
   ]]>
  </description>
  <name>repeat</name>
  <required>true</required>
  <type>java.lang.String</type>
 </attribute>
   
 <attribute>
  <description>
   <![CDATA[
      The number of times to repeat the text (accepted value: yes)
   ]]>
  </description>
  <name>uppercase</name>
  <required>false</required>       
  <type>java.lang.String</type>
 </attribute>
</tag>
...

web.xml
...
<context-param>
 <param-name>javax.faces.FACELETS_LIBRARIES</param-name>
 <param-value>/WEB-INF/dummy.taglib.xml</param-value>
</context-param>
...
Complete code on GitHub.

Now, let's see several examples of custom tag handlers:

Text Repeat
For example, let's suppose that we need the following functionality: we provide a piece of text, the number of times it should be displayed, and the possibility to be displayed in uppercase. We may think of a tag as follows:

<mt:textrepeat text="Vamos Rafa!" repeat="10" uppercase="yes"/>

We don't need a custom component for this, because we can simply fix it via a tag handler, as below:

TextRepeatTagHandler
public class TextRepeatTagHandler extends TagHandler {

 protected final TagAttribute text;
 protected final TagAttribute repeat;
 protected final TagAttribute uppercase;

 public TextRepeatTagHandler(TagConfig config) {
  super(config);
  this.text = this.getRequiredAttribute("text");
  this.repeat = this.getRequiredAttribute("repeat");
  this.uppercase = this.getAttribute("uppercase");
 }

 @Override
 public void apply(FaceletContext ctx, UIComponent parent) throws IOException {
  String s = "";
  UIOutput child = new HtmlOutputText();
  for (int i = 0; i < Integer.valueOf(repeat.getValue()); i++) {
       s = s + text.getValue() + " ";
  }

  if (uppercase != null) {
      if (uppercase.getValue().equals("yes")) {
          s = s.toUpperCase();
      } else {
          s = s.toLowerCase();
      }
  }

  child.setValue(s);
  parent.getChildren().add(child);
  }
}

Complete code on GitHub.

Style Input Text
The below TagHandler set the styleClass attribute for the parent component, only when the parent component is an instance of HtmlInputText:

StyleInputTextTagHandler
public class StyleInputTextTagHandler extends TagHandler {

 public StyleInputTextTagHandler(TagConfig config) {
  super(config);
 }

 @Override
 public void apply(FaceletContext ctx, UIComponent parent) throws IOException {
  if (parent instanceof HtmlInputText) {
      HtmlInputText inputText = (HtmlInputText) parent;
      String styleClass = inputText.getStyleClass();
      if (styleClass == null) {
          styleClass = "";
      }
      if (!styleClass.contains("inputstyle")) {
          inputText.setStyleClass(styleClass + " inputstyle");
      }
  }
 }
}

Complete code on GitHub

Add Converter/Validator
The below TagHandler set a converter and a validator for the parent component, only when the parent component is an instance of HtmlInputText:

ConverterValidatorTagHandler
public class ConverterValidatorTagHandler extends TagHandler {

 public ConverterValidatorTagHandler(TagConfig config) {
  super(config);
 }

 @Override
 public void apply(FaceletContext ctx, UIComponent parent) throws IOException {
  if (parent instanceof HtmlInputText) {
      HtmlInputText inputText = (HtmlInputText) parent;

      inputText.addValidator(new MyValidator());
      inputText.setConverter(new MyConverter());           
  }
 }
}

Complete code on GitHub.
OmniFaces defines a set of very useful tag handlers. Check the taghandlers section in Showcase!

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