A Custom JSF Tag Lib For Toggling Render of Child Elements

 

I’ve added a new sample project on GitHub that shows a custom Tag Library for JSF (Java Server Faces) that can be used to show/hide its children. There are several uses for this sort of custom component in your JSF web project but in this sample code I just read a property on the custom tag to determine whether to render all child elements or not. In a real application this logic could be swapped to implement application logic or perhaps call a Feature Toggle framework which decides whether to render elements within this tag or not.

Whilst the code is a complete same JSF project the main class is the CustomTag class.

This custom tag extends UIComponentBase to control the encodeChildren and getRendersChildren methods. In the getRendersChildren method we need to determine whether any child elements should be shown or not (again this can be any logic you find useful but for this example we are just reading a parameter on the XHTML). If its determined that we DO want to display children then we will follow normal processing and pass the call onto the base class’s getRendersChildren method. If its determined we DO NOT want to display child elements we instead return TRUE which tells the JSF framework that we want to render children ourselves using our custom encodeChildren method (which then ignores the request).

public class CustomTag extends UIComponentBase {

    @Override
    public String getFamily() {
         return "com.test.common.CustomTag";
    }

    @Override
    public void encodeChildren(FacesContext arg0) throws IOException {
         return;
    }

    @Override
    public boolean getRendersChildren() {
         boolean enabled = false;
         // Replace this logic with whatever you need to determine whether to display children or not
        String ruleName = (String) getAttributes().get("showChildren");
        enabled = (ruleName.equalsIgnoreCase("enabled"));

        if(enabled)
        {
             // we want the children rendered so we tell JSF that we wont be doing it in this custom tag.
             return super.getRendersChildren();
        }
        else {
             // we will tell JSF that we will render the children, but then we'll not.
             return true;
        }
    }
}

Next we define the new tag in the web.xml and custom.taglib.xml config files.

<!-- register custom tag -->
<context-param>
    <param-name>javax.faces.FACELETS_LIBRARIES</param-name>
    <param-value>/WEB-INF/custom.taglib.xml</param-value>
</context-param>

and

<?xml version="1.0"?>
<!DOCTYPE facelet-taglib PUBLIC
        "-//Sun Microsystems, Inc.//DTD Facelet Taglib 1.0//EN"
        "http://java.sun.com/dtd/facelet-taglib_1_0.dtd">
<facelet-taglib>
    <namespace>http://RichCustomTag.com</namespace>
    <tag>
        <tag-name>customTag</tag-name>
        <component>
            <component-type>com.test.common.CustomTag</component-type>
        </component>
    </tag>
</facelet-taglib>

We then use that new CustomTag within our XHTML page to wrap the elements that we want to toggle on/off depending on our logic.

Items below may or may not appear depending whether they are turned on or off:
<!-- to show children set showChildren to 'enabled' else 'disabled' -->
<rh:customTag showChildren="enabled">
   If you see this then child items are enabled
    <h:inputText value="#{helloBean.name2}"></h:inputText>
    end of dynamic content.
</rh:customTag>

That’s it.

Check out the code on GitHub via https://github.com/RichHewlett/JSFTag_ToggleChildRendering.

Advertisement

Speed up a slow JSF XHTML editing experience in Eclipse or IBM RAD/RSA.

If you find yourself doing some JSF (Java Server Faces) development within either Eclipse, IBM’s RAD (Rapid Application Developer) or IBM RSA (Rational Software Architect) IDEs you may find that the JSF editor can run slowly with some lag. This seems particularly a problem on RAM starved machines and/or older versions of the Eclipse/RAD IDEs. The problem (which can be intermittent) is very frustrating and can result in whole seconds going by after typing before your changes appear in the editor. It seems that the JSF code validator is taking too long to re-validate the edited JSF code file. At one point this got so bad for our team many would revert to making JSF changes in a text editor and then copy/paste the final code into the IDE.

java_small

Thankfully there is a workaround and in order that I don’t forget if I hit this problem again I’m posting it here. The workaround (although sadly not a fix) is to use a different “editor” within the same IDE. If you right click the JSF file you want to edit and use the pop-up menu to choose to open it with the XML Editor instead of the XHTML Editor then you will find a much faster experience. Whilst this does remove some of the JSF/XHTML specific validations it provides support for tags etc and will perform faster.

Should you wish to always use the XML Editor to edit XHTML files you can make this global change via the preferences. Go to General > Editors > File Associations > File Types list > select XHTML extension > click Add > Add XML Editor. Then in the associated editors list select the XML Editor and click the ‘Default’ button – thus making XML Editor the default for all XHTML files. Of course once this is done you can still click on individual XHTML files and right click to open in the original XHTML editor should you want to temporarily switch back for an individual file.

Hopefully this will prevent you pulling your hair out in frustration when editing XHTML files.

Setting HTTP Headers in Java Server Faces (JSF)

In my last post  I discussed using HTTP headers to control browser caching of sensitive data. The post can be found here. The examples provided in that post were all ASP.Net and so I thought I’d cover how to explicitly set your HTTP Response headers when you are using the Java JSF framework.

Adding Headers via Code

You can set HTTP response headers directly in your code via the HTTPServletResponse object, as below:

import javax.servlet.http.HttpServletResponse;

ExternalContext context = FacesContext.getCurrentInstance().getExternalContext();
HttpServletResponse response =  (HttpServletResponse)context.getResponse();
response.setHeader("TestHeader", "hello");

This results in the addition of this header in the HTTP Response: TestHeader: hello.

Adding Headers in your XHTML Markup

Alternatively you can set it directly on each XHTML page via an event tag, as shown in the example below:

<f:event type="preRenderView" listener="#{facesContext.externalContext.response.setHeader('TestHeader', 'hello')}" />
  <h:form>
    <h:panelGrid columns="2">
      <h:outputText value="Name"></h:outputText>
      <h:inputText value="#{LoginBean.name}"></h:inputText>
      <h:outputText value="Password"></h:outputText>
      <h:inputSecret value="#{LoginBean.password}"></h:inputSecret>
    </h:panelGrid>
    <h:commandButton action="welcome" value="Submit" />
</h:form>

This again results in the addition of this header in the HTTP Response: TestHeader: hello.

Adding Headers via a custom Web Filter

In order to implement a solution across your whole web application and for the ability to set headers for different resource types (not just facelets), a web filter may be what you need. Filters intercept your requests and responses to dynamically transform them or use the information contained in them. A good guide to Filters is this official Oracle one – The Essentials of Filters, or check this one out – Servlet Filter to Set Response Headers .

Here is the source code for a simple filter that sets a custom header and can be used to explicitly set HTTP response headers as required:

package Filters; 
import java.io.IOException; 
import javax.servlet.Filter; 
import javax.servlet.FilterChain; 
import javax.servlet.FilterConfig; 
import javax.servlet.ServletException; 
import javax.servlet.ServletRequest; 
import javax.servlet.ServletResponse; 
import javax.servlet.http.HttpServletResponse;

public class HeaderFilter implements Filter 
{ 
    public void init(FilterConfig fc) throws ServletException {} 

    public void doFilter(ServletRequest req, ServletResponse res, 
            FilterChain fc) throws IOException, ServletException 
    { 
        HttpServletResponse response = (HttpServletResponse) res; 
        response.setHeader("TestHeader", "hello"); 
        fc.doFilter(req, res); 
    } 

    public void destroy() {} 
}

Once you’ve coded your filter you need to update your Web.xml file to tell the framework that you want to use this filter. Do this by adding a filter element containing the name and class details. You also need to set a filter-mapping element to map the filter with the request for resources. In the below example which configures the Filter above I have mapped “/*”  meaning all requests will go through the filter but you can configure this to only impact certain resources or file types.

<filter>
  <filter-name>MapThisCustomHeaderFilter</filter-name>
  <filter-class>Filters.HeaderFilter</filter-class>
  <init-param>
    <param-name>value</param-name>
    <param-value>test</param-value>
  </init-param>
</filter>
<filter-mapping>
  <filter-name>MapThisCustomHeaderFilter</filter-name>
   <url-pattern>/*</url-pattern>
</filter-mapping>

Once configured via the web.xml file the custom header sets this header on all respones: TestHeader : hello.