jsfprimefacesresourcessystemeventlistener

Exclude resources in JSF


I'm using Primefaces. For some pages I want to exclude the resources which are included by primefacs, especially the theme resource.

<link type="text/css" rel="stylesheet" href="/context/javax.faces.resource/theme.css?ln=primefaces-owntheme" />    

I try that with a SystemEventListener as following:

public class PrimeFacesResourceRemover implements javax.faces.event.SystemEventListener {


  @Override
  public void processEvent(SystemEvent event) throws AbortProcessingException {
    FacesContext context = FacesContext.getCurrentInstance();

    UIViewRoot viewRoot = context.getViewRoot();
    for (UIComponent resource : viewRoot.getComponentResources(context, "head")) {

        Map<String, Object> attrs = resource.getAttributes();
        String resourceLibrary = (String) attrs.get("library");
        String resourceName = (String) attrs.get("name");

        if ("primefaces-owntheme".equals(resourceLibrary) && "theme.css".equals(resourceName)) {

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

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

and in the faces-config.xml

    <application>
      <system-event-listener>
        <system-event-listener-class>
          com.mycompany.mavenproject1.PrimeFacesResourceRemover
        </system-event-listener-class>
        <system-event-class>
          javax.faces.event.PostAddToViewEvent
        </system-event-class>
      </system-event-listener>
    </application>

This works well, when I include a resouce on a page manually, but those not work with the resouces which are included by Primefaces. How can I remove those resouces?


Solution

  • The theme.css is not been added as a dynamic component resource, but it's been hardcoded in PrimeFaces' HeadRenderer. The OmniFaces CombinedResourceHandler was also struggling with this.

    The solution is rather simple: override it with a custom HeadRenderer (without any @ResourceDependency on theme.css, of course!):

    public class HeadRenderer extends Renderer {
    
        @Override
        public void encodeBegin(FacesContext context, UIComponent component) throws IOException {
            context.getResponseWriter().startElement("head", component);
        }
    
        @Override
        public void encodeChildren(FacesContext context, UIComponent component) throws IOException {
            // NOOP.
        }
    
        @Override
        public void encodeEnd(FacesContext context, UIComponent component) throws IOException {
            for (UIComponent resource : context.getViewRoot().getComponentResources(context, "head")) {
                resource.encodeAll(context);
            }
    
            context.getResponseWriter().endElement("head");
        }
    
    }
    

    Register it as follows in webapp's faces-config.xml:

    <render-kit>
        <renderer>
            <component-family>javax.faces.Output</component-family>
            <renderer-type>javax.faces.Head</renderer-type>
            <renderer-class>com.example.HeadRenderer</renderer-class>
        </renderer>
    </render-kit>