How to remove included resources in JSF example
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:
<?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:
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:
@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.