A Custom JSF Tag Lib For Toggling Render of Child Elements

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.

Advertisements

Setting HTTP Headers in Java Server Faces (JSF)

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.

‘Java Update Secret Warning’ or ‘You WILL Auto-Update’

The Java Runtime on my Dev machine prompted me to Update with a new Version. It didn’t prompt nicely via a little notification popup in the System Tray but instead blows straight into a full UAC prompt. Anyway in a moment of revenge I decided to turn off the ‘Auto Update’ feature. I opened the Java Control Panel and found the Update tab shown below:

image

I unchecked the “Check for Updates Automatically” option and then got this rather amusing ‘Warning’:

image

After guessing which button did what I closed the dialog to see this:

image

No matter how many times I try the same thing happens. I’m guessing that this is either:

  1. A very secret warning message that not just any mere mortal can read.
  2. A very obscure tactic to convince users not to turn off auto updates.
  3. A bug.

You decide.