How to cache component rendering in JSF example

29 October 2013
By Gonçalo Marques
In this tutorial we will see how to cache component rendering in JSF.

Introduction

Caching mechanisms are commonly used in web applications, especially when we have sections of a web page that are frequently accessed and the displayed content within those sections is not subject to constant changes. In this tutorial we will see how to easily cache components - or even sections - of a JSF view using the Omnifaces component library.

This tutorial considers the following environment:

  1. Ubuntu 12.04
  2. JDK 1.7.0.21
  3. JSF 2.2.4
  4. Omnifaces 1.6.1

Configuring Maven dependencies

Since we will be using Omnifaces we must declare the dependency in our Maven project:

Omnifaces Maven dependency

<dependencies>

  <dependency>
    <groupId>org.omnifaces</groupId>
    <artifactId>omnifaces</artifactId>
    <version>1.6.1</version>
  </dependency>

</dependencies>

The JSF managed bean

We will use a JSF managed bean to hold the information that we will present in the view:

TestBean.java

package com.byteslounge.jsf;

import java.util.ArrayList;
import java.util.List;

import javax.annotation.PostConstruct;
import javax.faces.bean.ManagedBean;
import javax.faces.bean.RequestScoped;

@ManagedBean
@RequestScoped
public class TestBean {

  private String title;
  private List<String> items;

  @PostConstruct
  private void init() {
    title = "JSF - cache component rendering";
    items = new ArrayList<>();
    items.add("Item 1");
    items.add("Item 2");
    items.add("Item 3");
    System.out.println("TestBean initialized");
  }

  public String getTitle() {
    return title;
  }

  public List<String> getItems() {
    return items;
  }

}

We are basically defining a title and a list of items that will be shown in the JSF view. Note that the bean is RequestScoped so under regular conditions it would be initialized in every request made against a view that referenced the bean.

We are writing a message to the console during bean initialization so we may later confirm that the bean will not be initialized in every request and the cache will work correctly.

The JSF view

Now we define the view:

test.xhtml

<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml"
  xmlns:h="http://java.sun.com/jsf/html"
  xmlns:ui="http://java.sun.com/jsf/facelets"
  xmlns:o="http://omnifaces.org/ui">

<h:head>
  <title>JSF - cache component rendering</title>
</h:head>
<h:body>
  <o:cache>
    <div>
      <h:outputText value="#{testBean.title}" />
    </div>
    <ui:repeat var="item" value="#{testBean.items}">
      <div>
        <h:outputText value="#{item}" />
      </div>
    </ui:repeat>
  </o:cache>
</h:body>
</html>

The view is writing the title we defined in the managed bean to the screen and also iterating over the items list - defined in the managed bean as well - and showing them to the user.

Note the o:cache element. This component is provided by Omnifaces and it will cache the HTML that is generated by the other components that are declared inside it.

By default the o:cache component will cache its contents using session scope. This means that for every distinct user session it will only generate the rendered HTML once, and consequently it will only initialize the managed bean and fetch its properties once. The scope may be changed but we will see that later in this tutorial.

Testing

When we access the following URL:

http://localhost:8080/myapp/pages/test.xhtml

The expected output will be generated:

Generated output
JSF cache - generated output

Now when we refresh the page we will see that the managed bean will not be initialized again even if the bean is RequestScoped. The HTML will also not be rendered again: it is cached in memory.

Remember that by default the cache is session scoped so as soon as the page is accessed by a different session the component will be rendered again. We will see other scopes in the next article section.

The following message will be written to the standard output only once per session:

TestBean initialized

Scope attribute

By default the Omnifaces cache component will have its scope defined as session. This means that the component rendering will be cached per session. Other possible value for scope attribute is application scope:

Scope attribute

<o:cache scope="application">
  ...
</o:cache>

By setting the scope to application the component will be rendered once, cached and reused across the entire application.

Key attribute

The key attribute is the key used to store the component rendering result in the cache (like a key-value pair). It may be set dynamically through an EL expression so we may use it to cache components rendering more flexibly, ie. multiple (or distinct) renderings of the same component.

Key attribute

<o:cache key="pizzaMenu#{pizzaBean.pizzaType}">
  ...
</o:cache>

Note that if you use an EL expression associated with a managed bean in the key attribute value - as we just did - you must keep in mind that the expression will be evaluated every time the o:cache component is being rendered. This is because Omnifaces must know what value the key attribute will resolve in order to check if it is already in cache. So make sure that the EL expression doesn't do any expensive operation.

Time attribute

As the name states, the time attribute specifies the time to live (TTL) in seconds of a cached element:

Time attribute

<o:cache time="120">
  ...
</o:cache>

After the time to live expires the content will be rendered again.

Reset attribute

The reset attribute is used to instruct Omnifaces that the component should be rendered again:

Reset attribute

<o:cache reset="#{someBean.resetCache}">
  ...
</o:cache>

This attribute may be an EL expression. When the result of the EL expression evaluates to true the content is rendered again.

Programmatically resetting the cache

It is possible to programmatically reset the Omnifaces component cache:

Resetting programmatically the cache

CacheFactory.getCache(
  FacesContext.getCurrentInstance(),
  "session").remove("someKey");

Where "session" is the scope of the cached item to remove and "someKey" is the item key.

Downloadable sample

You may find a downloadable sample at the end of this page. Please keep in mind that the sample is a Maven project ready to be deployed in Tomcat 7.

References

Omnifaces may be found here.

Download source code from this article

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: