Wednesday, October 20, 2010

JSF 2.0 - New features (part 2 of 3)

Note: below description uses Eclipse Indigo, Tomcat 7.0.28 and MyFaces 2.1.7. 

Requirements:
You will learn:
  • resource loading
This is the second post about new features that could be found in JSF 2.0 comparing to JSF 1.x. In the previous post (part 1), I described templating mechanism and simplified navigation model. In this post I would like to focus on the improved resource loading and its capabilities in JSF 2.0.

Resource loading.
What are resources in terms of a web application? It can be images files, JavaScript script files or CSS files used on web pages in the application - so some external files accessible by special tags in the page source. In the JSF application we also name as resources message bundle files.
Just as a short reminder for message bundles:
1. We create message bundle files for each language we would like to support. Then we add some lines into the configuration in faces-config.xml where we define what language will be supported (<locale-config> section) and we define EL access object (<var>msg</var>) for the created message bundle files:


2.  We use message from the bundle files by calling defined EL accessor in the page source, for example:
<h:outputText value="#{msg['top.name']}" />
This approach gives us the most important benefit: localization of the application. Based on the browser's language, suitable message bundle file is used (EN or PL in above example).

So far so good - nothing new is here when comparing to JSF 1.x. But what about other resources like JS, CSS or image files? JSF 2.0 can handle those resources in a more intelligent way than before - a special ResourceHandler is used for load resources from some predefined locations. According to the documentation resources are expected to be placed in:

WebRoot/resources/<resourceIdentifier> 

WebRoot is a root of web application - in the Eclipse generated web projects it is the directory named "WebContent". Part resourceIdentifier have this structure:

[localePrefix/][libraryName/][libraryVersion/]resourceName[/resourceVersion] 

resourceIdentifier defines the subdirectory structure inside WebRoot/resources/directory. And the most important part: localePrefix means that resources can be localized based on the browser's language, like message bundles. Part libraryName can be use to group resources by their type in different directories, for example "css", "images", "scripts".

Let' see how it work in a sample application. As I wrote in previous post, we used shopTemplate.xhtml file as a template page for all pages in application. The second purpose of this file (next to defining reusable parts) is to separate the structure from the presentation - template page will include all CSS files and common images files. We will use new ResourceHandler in order to load some CSS and images suitable for current browser language:
  • images: we have two pictures (bike_logo.jpg and flag.gif) in sample application visible in the header - they will change depending on current browser language
  • CSS: depending on current browser language, different CSS will be loaded. The only difference between loaded CSS's is footer color (just to show that CSS is really changed)
According to the documentation we have to create directory structure for mentioned resources and put different resource there:



How to load such resources on the page? First we have to perform additional configuration to enable loading resources using proper localePrefix ("pl" and "en" on the screenshot above). We have to create a special localized entry named javax.faces.resource.localePrefix in a resource-bundle file. This file must be configured as message-bundle in faces-config.xml - we can not use resource bundles (used for localized messages as shown above) to put entry there:


Now we can use the resources on the shopTemplate.xhtml page:


Please note that we use here a new JSF 2.0 tag:
<h:outputStylesheet library="css" name="layout.css" />
Attributes library and name correspond to the libraryName and resourceName from <resourceIdentifier> respectively.

If we want to load  JS scripts we have to use additional JSF 2.0 tag: <h:outputScript ... /> wich has additional attribute named target - specifying where to render script link.

Loading images with standard tag <h:graphicImage ... /> is possible in two ways:
  • using attributes library and name correspond to the libraryName and resourceName from <resourceIdentifier> respectively (like for CSS)
  • using special EL expression "#{resource['images:bike_logo.jpg']}" (wartch out for letters: EL has resource word but in the WebContent there is a resources directory!)

Note about testing: in order to test if images and CSS (footer color) changes when browser language is changed, I recommend clean the browser cache and restart it completely before testing (sometimes image cache prevents from changing the image). The test result should be:

PL version:


EN version:


-------------------------------------------
Download source files:
The complete working example of mentioned application which will contain all described features, will be available in the last (third) article of this serie.

1 comment:

Mikael Falkvidd said...

Great post, thanks a lot.

Is there a way to have jsf "fallback" to the default locale (or no locale) if no image exists in the current locale?

A lot of images are the same for all locales, and I would prefer not to copy them to all locales. Is this possible?