Annoying JSF! (Part 1: Resource Handling)

21 11 2011

The last weeks, I dealt with JSF in a more intensive way. Whenever I read posts about JSF2, I found tutorials about the new features or listings about the advantages of JSF. But when looking for a deeper level of knowledge, there are some stumbling blocks that I’ll write about within a series of posts. The first one deals with the Resource Handling mechanism that was introduced with JSF2.

Resource Handling with JSF

The principle of resource handling with JSF is that you can place your web resources (CSS, JS or whatever) within special folders and send a request to the FacesServlet to get the resources to the browser. There are some JSF Facelet Tags to refer to these resources in a transparent way.
You do not have to use this, you can also refer to static resources of the web application (bypassing the Faces Servlet). But JSF resource handling has some advantages:

  • Caching: The resources are loaded once and cached by the FacesServlet to provide faster request handling for the next invocations.
  • Pluggability: You can address resources within a JAR file using the classloader, so you can provide corporate designs as external reusable libraries.
  • Component Architecture: Write custom UI components that introduce some CSS or JS. Those resources are loaded by JSF’s resource handling.

And you can implement your own ResourceHandler to customize it.

The pitfall

CSS is created and tested by web designers in a static way. You can use it within your web pages in a static way. Unfortunately, you cannot use it with JSF resource handling, because links in CSS files (e.g. background images, CSS imports) do not work. See the example below:

body {
  background-image: url("logo.gif");
}

If this is loaded by JSF with a URL of /javax.faces.resources/theme/layout.css.jsf?ln=css, the image is searched under /javax.faces.resources/theme/logo.gif cannot be found, because the Faces Servlet is not mapped to this url (only *.jsf) and the library name (css) is passed as a request parameter that is lost.

To the JSF team:
Suggestion #1: Encode the library name within the request path.

So how to solve the problem? There are some possibilities:

  • Use #{resource[‘css:theme/logo.gif’]} in the CSS file.
    This is recommended by the JSF community to get a valid link rendered within the CSS file. IMHO, this is not a good strategy because you cannot develop and test the CSS in the static way anymore. How should the web designer know about JSF expressions? What about CSS that is used in both JSF and non-JSF applications?
  • Write a custom ResourceHandler that replaces URLs in CSS to match the FacesServlet in a valid way.
    I have done so, but such string replacing algorithms can contain bugs. (Download the archive and put it into your WEB-INF/lib folder of the web application. It contains the source code.)
  • Write a custom ResourceHandler that defines an URL where the library name is encoded within the request path.Ideally, the javax.faces.resources should be removed from the URL. The FacesServlet must then be mapped to the new URL using a prefix (e.g. /resources/*) instead of a suffix.

To the JSF team:
Suggestion #2: Think about URL mappings and folders defined by the specs.
Resources have to be placed under the /resources folder of the web application. There they can be addressed directly via URL bypassing the FacesServlet. IMHO this is not the best solution. So why not place them under /META-INF/resources like it is declared for external JARs?

Further suggestion

Those suggestions came up during implementation of my customized ResourceHandler.

Suggestion #3: Refactor the URL handling for resources
The URL to a resource is given by an object of javax.faces.application.Resource, while the decision of a request to address a resource is made by the ResourceHandler. This should be encapsulated and made configurable (e.g. by an init param of the web app).

Suggestion #4: Limit the responsibilities of the ResourceHandler
“ResourceHandler” means the instance for loading resources. But I found out that it also loads Composite Components that maybe can be declared as resources too – but if the custom ResourceHandler contains bugs, you affect the whole page rendering, not only CSS, JS or images.

Suggestion #5: Generalize the exception for the ResourceHandler that is made within the FacesServlet
Within the FacesServlet, the request is analyzed to be a resource request or not. If so, the request is handled by the ResourceHandler, otherwise the phases of the request lifecycle are passed through. Might there be further exceptions in the future or done by external frameworks? Would it be better to provide a more generic mechanism to plug such exceptions to the FacesServlet? The ResourceHandler would then be one of these exceptions.