How to remove included resources in JSF example

23 October 2013
By Gonçalo Marques
In this tutorial we will see how to remove included resources (like JavaScript and CSS style sheets) in JSF.

Introduction

Sometimes one may need to remove resources included by JSF like JavaScript files or CSS style sheets. The resources may be the ones included by JSF itself or by some other external library like Primefaces or Richfaces. In this tutorial we will see how to accomplish this using a SystemEventListener.

Configuring a SystemEventListener

First thing we need is to configure a SystemEventListener that will listen for pre-render view events. We declare it in faces-config.xml:

faces-config.xml

<?xml version="1.0" encoding="UTF-8"?>
<faces-config version="2.0" 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_0.xsd">

  <application>
    <system-event-listener>
      <system-event-listener-class>
        com.byteslounge.jsf.RemoveResourcesListener
      </system-event-listener-class>
      <system-event-class>
        javax.faces.event.PreRenderViewEvent
      </system-event-class>
    </system-event-listener>
  </application>

</faces-config>

Defining the Listener

Now we define the listener:

RemoveResourcesListener.java

package com.byteslounge.jsf;

import javax.faces.component.UIComponent;
import javax.faces.component.UIViewRoot;
import javax.faces.context.FacesContext;
import javax.faces.event.AbortProcessingException;
import javax.faces.event.SystemEvent;
import javax.faces.event.SystemEventListener;

public class RemoveResourcesListener 
  implements SystemEventListener {

  private static final String HEAD = "head";

  @Override
  public void processEvent(SystemEvent event) 
    throws AbortProcessingException {

    FacesContext context = FacesContext.getCurrentInstance();

    // Fetch included resources list size
    int i = context.getViewRoot().getComponentResources(context, HEAD)
        .size() - 1;

    while (i >= 0) {

      // Fetch current resource from included resources list
      UIComponent resource = context.getViewRoot()
          .getComponentResources(context, HEAD).get(i);

      // Remove resource from view
      context.getViewRoot().removeComponentResource(context, resource,
          HEAD);

      i--;
    }
  }

  @Override
  public boolean isListenerForSource(Object source) {
    return (source instanceof UIViewRoot);
  }

}

The listener code is almost self-explanatory. Our listener will only be executed if the event source is a UIViewRoot instance (method isListenerForSource enforces this condition). We use the JSF API to fetch the resources that were appended to the view head and remove them one by one.

This will remove all JSF included resources. We will see next how to remove specific included resources.

Removing only specific resources

If we need to remove only a subset of the included resources we may change processEvent method in the following way:

Removing only specific resources

@Override
public void processEvent(SystemEvent event) 
  throws AbortProcessingException {

  FacesContext context = FacesContext.getCurrentInstance();

  // Fetch included resources list size
  int i = context.getViewRoot().getComponentResources(context, HEAD)
        .size() - 1;

  while (i >= 0) {

    // Fetch current resource from included resources list
    UIComponent resource = context.getViewRoot()
          .getComponentResources(context, HEAD).get(i);

    // Fetch resource library and resource name
    String resourceLibrary = (String) resource.getAttributes().get(
        "library");
    String resourceName = (String) resource.getAttributes().get("name");

    // Check if we should remove the current resource.
    // Here we may check for any library and name combination.
    // (JSF, Primefaces, Richfaces, etc)
    if ("javax.faces".equals(resourceLibrary)
      && "jsf.js".equals(resourceName)) {

      // Remove resource from view
      context.getViewRoot().removeComponentResource(context,
          resource, HEAD);
    }

    i--;

  }

}

We have changed processEvent method and now we only remove the resource if it belongs to the javax.faces library and if the resource name is jsf.js (the JavaScript library included by JSF). This technique may be used to remove only specific resources from included libraries like Primefaces or Richfaces or even from JSF itself.

Related Articles

Comments

About the author
Gonçalo Marques is a Software Engineer with several years of experience in software development and architecture definition. During this period his main focus was delivering software solutions in banking, telecommunications and governmental areas. He created the Bytes Lounge website with one ultimate goal: share his knowledge with the software development community. His main area of expertise is Java and open source.

GitHub profile: https://github.com/gonmarques

He is also the author of the WiFi File Browser Android application: