Using tag handler, UI component and renderer with a JSF facelet taglib 

Joined:
08/13/2009
Posts:
164

November 22, 2011 10:40:16    Last update: November 22, 2011 10:40:16
This is an example that uses tag handler, UI component and renderer together to support a custom taglib. The main purpose is to show how these components play together.

The tag renders
<ui:param name="extra" value="el interpreted"/>
<h3>my:foreach</h3>
<my:foreach var="person" value="John Joe Jane" tag="ul" class="css class" extra="#{extra}">
    <li>#{person}</li>
</my:foreach>

as
<h3>my:foreach</h3>
<ul class="css class" extra="el interpreted">
	    <li>John</li>
	    <li>Joe</li>
	    <li>Jane</li>
</ul>


These are the files:
  1. The tag handler (src/main/java/com/example/ForeachTagHandler.java):
    package com.example;
    
    import java.util.Map;
    import javax.faces.component.UIComponent;
    import javax.faces.view.facelets.*;
    
    public class ForeachTagHandler extends ComponentHandler {
        public ForeachTagHandler(ComponentConfig config) {
    	super(config);
        }
    
        @Override
        protected MetaRuleset createMetaRuleset(Class cls) {
    	MetaRuleset meta = super.createMetaRuleset(cls);
    	meta.alias("class", "styleClass");
    	return meta;
        }
    
        @Override
        public void onComponentCreated(FaceletContext ctx,
    				   UIComponent c,
    				   UIComponent parent) {
    	TagAttribute[] allAttrs = this.tag.getAttributes().getAll();
    
    	// we are passing thru all attributes except tag, var and value.
    	String[] attrs = new String[allAttrs.length - 3];
    	int j = 0;
    	for (int i = 0; i < allAttrs.length; i++) {
    	    String localName = allAttrs[i].getLocalName();
    	    if ("tag".equals(localName) ||
    		"var".equals(localName) ||
    		"value".equals(localName)) {
    		continue;
    	    }
    
    	    if ("class".equals(localName)) {
    		attrs[j++] = "styleClass";
    	    }
    	    else {
    		attrs[j++] = localName;
    	    }
    	}
    
    	Map<String,Object> compAttrs = c.getAttributes();
    	compAttrs.put("alias.attributes", attrs);
        }
    }
    

  2. The UI component (src/main/java/com/example/UIForeach.java):
    package com.example;
    
    import java.io.IOException;
    
    import javax.el.ValueExpression;
    import javax.faces.component.UIComponent;
    import javax.faces.component.UIComponentBase;
    
    public class UIForeach extends UIComponentBase {
        public static final String COMPONENT_TYPE = "com.example.Foreach";
        public static final String COMPONENT_FAMILY = "com.example";
    
        // data object
        private Object value;
    
        // variable name
        private String var;
        private String tag;
    
        public UIForeach() {
        }
    
        public String getFamily() {
    	return COMPONENT_FAMILY;
        }
    
        public String getVar() {
    	return this.var;
        }
    
        public void setVar(String var) {
    	this.var = var;
        }
    
        public String getTag() {
    	return this.tag;
        }
    
        public void setTag(String tag) {
    	this.tag = tag;
        }
    
        // value is set only when the value attribute does not contain EL.
        // otherwise, setValueExpression is called with the EL value.
        public Object getValue() {
    	if (this.value == null) {
    	    ValueExpression vex = this.getValueExpression("value");
    	    if (vex != null) {
    		return vex.getValue(getFacesContext().getELContext());
    	    }
    	}
    	return this.value;
        }
    
        public void setValue(Object value) {
    	this.value = value;
        }
    
        public boolean getRendersChildren() {
    	return true;
        }
    }
    

  3. The renderer (src/main/java/com/example/ForeachRenderer.java):
    package com.example;
    
    import java.io.IOException;
    import java.util.Map;
    import java.util.Iterator;
    
    import javax.faces.render.Renderer;
    import javax.faces.component.UIComponent;
    import javax.faces.context.FacesContext;
    import javax.faces.context.ResponseWriter;
    
    public class ForeachRenderer extends Renderer {
        @Override
        public void encodeBegin(FacesContext ctx, UIComponent uic) throws IOException {
    	UIForeach c = (UIForeach) uic;
        	ResponseWriter w = ctx.getResponseWriter();
    	w.startElement(c.getTag(), c);
    	Map<String, Object> a = c.getAttributes();
    	String[] attrs = (String[]) a.get("alias.attributes");
    	for (int i = 0; i < attrs.length; i++) {
    	    String attr = attrs[i];
    	    if ("styleClass".equals(attr)) {
    		w.writeAttribute("class", a.get(attr), null);
    	    }
    	    else {
    		w.writeAttribute(attr, a.get(attr), null);
    	    }
    	}
        }
    
        @Override
        public void encodeEnd(FacesContext ctx, UIComponent uic) throws IOException {
    	UIForeach c = (UIForeach) uic;
        	ResponseWriter w = ctx.getResponseWriter();
    	w.endElement(c.getTag());
        }
    
        @Override
        public void encodeChildren(FacesContext ctx, UIComponent uic) throws IOException {
    	UIForeach c = (UIForeach) uic;
    	String[] values = ((String) c.getValue()).split("\\s+");
    	for (int i = 0; i < values.length; i++) {
    	    Map<String, Object> attrs = ctx.getExternalContext().getRequestMap();
    	    attrs.put(c.getVar(), values[i]);
    
    	    Iterator<UIComponent> it = c.getChildren().iterator();
    	    while (it.hasNext()) {
    		UIComponent ch = it.next();
    		ch.encodeAll(ctx);
    	    }
    	}
        }
    }
    

  4. Faces config (src/main/resources/META-INF/faces-config.xml):
    <?xml version="1.0" encoding="UTF-8"?>
    <faces-config xmlns="http://java.sun.com/xml/ns/javaee"
        xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
        xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-facesconfig_2_1.xsd"
        version="2.1">
        <component>
    	<component-type>com.example.Foreach</component-type>
    	<component-class>com.example.UIForeach</component-class>
        </component>
    
        <render-kit>
            <render-kit-id>HTML_BASIC</render-kit-id>
            <renderer>
                <component-family>com.example</component-family>
                <renderer-type>com.example.ForeachRenderer</renderer-type>
                <renderer-class>com.example.ForeachRenderer</renderer-class>
            </renderer>
        </render-kit>
    </faces-config>
    

  5. Taglib config (src/main/resources/META-INF/foreach.taglib.xml):
    <?xml version="1.0" encoding="UTF-8"?>
    <facelet-taglib
        xmlns="http://java.sun.com/xml/ns/javaee"
        version="2.0">
        <namespace>http://www.example.com/ns/facelettags</namespace>
        <tag>
    	<tag-name>foreach</tag-name>
    	<component>
    	    <component-type>com.example.Foreach</component-type>
    	    <renderer-type>com.example.ForeachRenderer</renderer-type>
    	    <handler-class>com.example.ForeachTagHandler</handler-class>
    	</component>
        </tag>
    </facelet-taglib>
    

Share |
| Comment  | Tags