-
Available since OmniFaces 1.1
The <o:cache>
component allows to cache a fragment of rendered markup. The first request for a page that has this component on it will cause this markup to be put into the cache. Then for subsequent requests the cached content is used directly and none of the components, backing beans and services that were used to generate this content in the first place will be consulted.
Caching can take place in application scope, or in session scope. For individual fragments a time can be specified for which the cached content is valid. After this time is elapsed, the very first request to the page containing the cache component in question will cause new content to be rendered and put into the cache. A default time can be set per scope in web.xml.
For each scope a maximum capacity can be set. If the capacity for that scope is exceeded, an element will be removed following a least recently used policy (LRU).
Via a cache provider mechanism an alternative cache implementation can be configured in web.xml. The default cache is based on LruCache
.
Setting a custom caching provider
A custom caching provider can be set by using the org.omnifaces.CACHE_PROVIDER
context parameter in web.xml to point to an implementation of org.omnifaces.component.output.cache.CacheProvider
. For example:
<context-param>
<param-name>org.omnifaces.CACHE_PROVIDER</param-name>
<param-value>com.example.MyProvider</param-value>
</context-param>
The default provider, org.omnifaces.component.output.cache.DefaultCacheProvider
can be used as an example.
Global settings
For the default provider, the maximum capacity and the default time to live can be specified for the supported scopes "session" and "application". If the maximum capacity is reached, an entry will be evicted following a least recently used policy. The default time to live specifies for how long entries are considered to be valid. A value for the time
attribute on this component will override this global default time to live. The following context parameters can be used in web.xml:
org.omnifaces.CACHE_SETTING_APPLICATION_MAX_CAPACITY |
Sets the maximum number of elements that will be stored per web module (application scope). Default: no limit |
org.omnifaces.CACHE_SETTING_SESSION_MAX_CAPACITY |
Sets the maximum number of elements that will be stored per session. Default: no limit. |
org.omnifaces.CACHE_SETTING_APPLICATION_TTL |
Sets the maximum amount of time in seconds that cached content is valid for the application scope. Can be overriden by individal cache components. Default: no limit. |
org.omnifaces.CACHE_SETTING_SESSION_TTL |
Sets the maximum amount of time in seconds that cached content is valid for the session scope. Can be overriden by individal cache components. Default: no limit. |
org.omnifaces.CACHE_INSTALL_BUFFER_FILTER |
Boolean that when true installs a Servlet Filter (Servlet 3.0+ only) that works in conjunction with the useBuffer attribute of the Cache component to enable an alternative way to grab the content that needs to be cached. This is a convenience setting that is a short-cut for installing the org.omnifaces.servlet.BufferedHttpServletResponse filter manually. If more finegrained control is needed regarding which place in the filter chain the filter appears and which resources it exactly filters, this setting should not be used and the mentioned filter should be manually configured. Default: false . |
Now: 2024-12-21T04:05:16.961566-06:00[America/Chicago]
Example 1 - Fixed cache
The following renders a couple of items in a default cache, which means the session scope is used without a timeout.
On the first page refresh, all items should have the same time as indicated by "Now
" above.
After a page refresh the time of the items should stay constant, indicating cached content is used.
A - Sat Dec 21 04:05:16 CST 2024 |
B - Sat Dec 21 04:05:16 CST 2024 |
C - Sat Dec 21 04:05:16 CST 2024 |
Example 2 - Timed cache
The following renders a time-stamp in the session scoped cache, for which a time to live has been set to 15 seconds.
On the first page refresh, it should be equal again to the time as indicated by "Now
" above.
For page refreshes done within 15 seconds after this first request it should be constant. After this time,
it should change into the "Now
" time again, meaning a timeout took place and new content was rendered.
Session scope content valid for 15 seconds generated at: 2024-12-21T04:05:16.961566-06:00[America/Chicago]
Example 3 - Treshold on number of cached items
The following renders a time-stamp in the session scoped cache again, this time using an explicit and dynamic key.
For this show case application, the number of items in the session cache has been set to 4
using the following setting in web.xml
:
<context-param> <param-name>org.omnifaces.CACHE_SETTING_SESSION_MAX_CAPACITY</param-name> <param-value>6</param-value> </context-param>
Since 4 items have been used already by the other examples, only 2 more fit it.
This can be demonstrated by generating cache items via the numbered buttons shown below. Clicking on any two of the same numbers below will switch between the cached content for those and will keep showing the time-stamp associated with them on their first click. Upon clicking a third number, and then clicking the number of the original 2 that was clicked the longest time ago (except 0, the default), a new time-stamp will be associated with that.
This means the threshold of 6 cached items had been exceeded and the last accessed item was evicted.
E.g. click 0, click 1, click 0 (notice it has the same time-stamp), click 1 (same timestamp), click 2, click 1 (gets new time-stamp)
Session scope content for key 0 generated at: 2024-12-21T04:05:16.961566-06:00[America/Chicago]
Example 4 - Explicitly resetting/expiring cache
Cached data may need to be reset at the point that the underlying data is known to have changed. Any cache entry can be programmatically removed based on the scope and the key of this entry. By default the cache component generates an internal key, but this can be overridden by using an explicit key. The default scope is "session".
Cached data can also be reset via the reset
attribute on the cache
component. Using this method
it's not necessary to know the scope and key of the cache. Instead, the attribute can be bound to a property of a backing bean
which can return true
(reset cache) or false
. If the attribute is bound to a view scoped backing bean,
care should be taken to reset the property back to false (e.g via a PreRenderView
event on the next request, or
CallbackPhaseListener
on the current request).
Programmatic reset
Pressing the following button will reset the cache that's used in example 1 at the start of this page via the
programmatic method. With this method the attribute
reset="#{cacheBean.reset}"
is NOT
used.
Reset via component attribute
Pressing the following button will reset the cache that's used in example 1 at the start of this page by setting
a bean property that's bound to the attribute
reset="#{cacheBean.reset}"
on the
component to true
.
Example 5 - Caching value expressions
Sometimes it might be convenient to cache an EL value expression instead or in addition of a fully rendered piece of markup. This is especially useful for a postback, since after a postback Faces (of course) won't evaluate the cached markup, but will evaluate value expressions again.
Without o:cacheValue
Clicking on any of the 'Postback' buttons below will cause a new date to be generated at each click, instead
of the actually selected date. This is because Faces doesn't send the actual row data along, but merely a row number.
Because the backing bean is request scoped and the expression #{cacheBean.items}
is evaluated
fresh after each postback, we'll end up selecting a new date each time.
With o:cacheValue
The following example makes use of o:cacheValue
to cache the value expression as well. Clicking
any of the 'Postback' buttons in the example below will cause the same date to be selected as the one in the row
where the button is clicked.
Example 6 - Disabling the cache
The OmniFaces cache can be disabled per request. If the cache is disabled the cache's children will be directly rendered without influencing the cached data. So if initially the value "1" was rendered and cached, and after disabling the cache the value "2" is rendered, then enabling the cache again (assuming no reset or timeout has taken place) will render the original "1" again and there will be no memory of there ever having been a "2".
<p>
<b>Now:</b> <span id="now">#{now}</span>
</p>
<hr/>
<h3>Example 1 - Fixed cache</h3>
<p>
The following renders a couple of items in a default cache, which means the session scope is used without a timeout.
On the first page refresh, all items should have the same time as indicated by "<code>Now</code>" above.
After a page refresh the time of the items should stay constant, indicating cached content is used.
</p>
<p>
<o:cache key="firstCache" reset="#{cacheBean.reset}" disabled="#{cacheBean.disabled}">
<h:dataTable id="example1" value="#{cacheBean.items}" var="item">
<h:column>
<i>#{item}</i> <br/>
</h:column>
</h:dataTable>
</o:cache>
</p>
<hr/>
<h3>Example 2 - Timed cache</h3>
<p>
The following renders a time-stamp in the session scoped cache, for which a time to live has been set to 15 seconds.
On the first page refresh, it should be equal again to the time as indicated by "<code>Now</code>" above.
For page refreshes done within 15 seconds after this first request it should be constant. After this time,
it should change into the "<code>Now</code>" time again, meaning a timeout took place and new content was rendered.
</p>
<p>
<o:cache time="15">
<i>Session scope content valid for 15 seconds generated at: #{now}</i>
</o:cache>
</p>
<hr/>
<h3>Example 3 - Treshold on number of cached items</h3>
<p>
The following renders a time-stamp in the session scoped cache again, this time using an explicit and dynamic key.
For this show case application, the number of items in the session cache has been set to <code>4</code>
using the following setting in <code>web.xml</code>:
</p>
<pre>
<context-param>
<param-name>org.omnifaces.CACHE_SETTING_SESSION_MAX_CAPACITY</param-name>
<param-value>6</param-value>
</context-param>
</pre>
<p>
Since 4 items have been used already by the other examples, only 2 more fit it.
</p>
<p>
This can be demonstrated by generating cache items via the numbered buttons shown below.
Clicking on any two of the same numbers below will switch between the cached content for those
and will keep showing the time-stamp associated with them on their first click.
Upon clicking a third number, and then clicking the number of the original 2 that was clicked the
longest time ago (except 0, the default), a new time-stamp will be associated with that.
</p>
<p>
This means the threshold of 6 cached items had been exceeded and the last accessed item was evicted.
</p>
<p>
E.g. click 0, click 1, click 0 (notice it has the same time-stamp), click 1 (same timestamp),
click 2, click 1 (gets new time-stamp)
</p>
<h:form>
Set Cache key to:
<h:commandButton action="#{cacheBean.setKey(0)}" value="0" />,
<h:commandButton action="#{cacheBean.setKey(1)}" value="1" />,
<h:commandButton action="#{cacheBean.setKey(2)}" value="2" />,
<h:commandButton action="#{cacheBean.setKey(3)}" value="3" />
</h:form>
<p>
<o:cache key="test-#{cacheBean.key}">
<i>Session scope content for key #{cacheBean.key} generated at: #{now}</i>
</o:cache>
</p>
<hr/>
<h3>Example 4 - Explicitly resetting/expiring cache</h3>
<p>
Cached data may need to be reset at the point that the underlying data is known to have changed. Any cache
entry can be programmatically removed based on the scope and the key of this entry. By default the cache
component generates an internal key, but this can be overridden by using an explicit key. The default scope is "session".
</p>
<p>
Cached data can also be reset via the <code>reset</code> attribute on the <code>cache</code> component. Using this method
it's not necessary to know the scope and key of the cache. Instead, the attribute can be bound to a property of a backing bean
which can return <code>true</code> (reset cache) or <code>false</code>. If the attribute is bound to a view scoped backing bean,
care should be taken to reset the property back to false (e.g via a <code>PreRenderView</code> event on the next request, or
<code>CallbackPhaseListener</code> on the current request).
</p>
<h4>Programmatic reset</h4>
<p>
Pressing the following button will reset the cache that's used in example 1 at the start of this page via the
programmatic method. With this method the attribute <span style="white-space: nowrap">
<code>reset="\#{cacheBean.reset}"</code></span> is <b>NOT</b>
used.
</p>
<h:form id="resetProgrammaticForm">
<h:commandButton id="button" action="#{cacheBean.resetProgrammatic}" value="Reset Example 1 cache programmatically" />
</h:form>
<h4>Reset via component attribute</h4>
<p>
Pressing the following button will reset the cache that's used in example 1 at the start of this page by setting
a bean property that's bound to the attribute <span style="white-space: nowrap">
<code>reset="\#{cacheBean.reset}"</code></span> on the
component to <code>true</code>.
</p>
<h:form id="resetAttributeForm">
<h:commandButton id="button" action="#{cacheBean.resetAttribute}" value="Reset Example 1 cache via attribute" />
</h:form>
<hr/>
<h3>Example 5 - Caching value expressions</h3>
<p>
Sometimes it might be convenient to cache an EL value expression instead or in addition of a fully rendered piece of markup.
This is especially useful for a postback, since after a postback Faces (of course) won't evaluate the cached markup, but will
evaluate value expressions again.
</p>
<h4>Without o:cacheValue</h4>
<p>
Clicking on any of the 'Postback' buttons below will cause a new date to be generated at each click, instead
of the actually selected date. This is because Faces doesn't send the actual row data along, but merely a row number.
Because the backing bean is request scoped and the expression <code>\#{cacheBean.items}</code> is evaluated
fresh after each postback, we'll end up selecting a new date each time.
</p>
<h:form id="example5aForm">
<p>
Item: <span id="example5aOutput">#{empty cacheBean.item? '(none)' : cacheBean.item}</span>
</p>
<o:cache>
<h:dataTable id="table" value="#{cacheBean.items}" var="item">
<h:column>
<i>#{item}</i>
</h:column>
<h:column>
<h:commandButton id="button" value="Postback" action="#{cacheBean.saveItem(item)}" >
<f:ajax execute="@form" render="@form" />
</h:commandButton>
</h:column>
</h:dataTable>
</o:cache>
</h:form>
<h4>With o:cacheValue</h4>
<p>
The following example makes use of <code>o:cacheValue</code> to cache the value expression as well. Clicking
any of the 'Postback' buttons in the example below will cause the same date to be selected as the one in the row
where the button is clicked.
</p>
<h:form id="example5bForm">
<p>
Item: <span id="example5bOutput">#{empty cacheBean.item? '(none)' : cacheBean.item}</span>
</p>
<o:cache>
<o:cacheValue name="items" value="#{cacheBean.items}"/>
<h:dataTable id="table" value="#{items}" var="item">
<h:column>
<i>#{item}</i>
</h:column>
<h:column>
<h:commandButton id="button" value="Postback" action="#{cacheBean.saveItem(item)}" >
<f:ajax execute="@form" render="@form" />
</h:commandButton>
</h:column>
</h:dataTable>
</o:cache>
</h:form>
<hr/>
<h3>Example 6 - Disabling the cache</h3>
<p>
The OmniFaces cache can be disabled per request. If the cache is disabled the cache's children will be
directly rendered <b>without influencing the cached data</b>. So if initially the value "1" was rendered
and cached, and after disabling the cache the value "2" is rendered, then enabling the cache again
(assuming no reset or timeout has taken place) will render the original "1" again and there will be no
memory of there ever having been a "2".
</p>
<h:form id="disableAttributeForm">
<h:commandButton id="button" action="#{cacheBean.disable}" value="Disable Example 1 cache via attribute (for one request)" />
</h:form>
package org.omnifaces.showcase.components;
import static org.omnifaces.util.Faces.getContext;
import static org.omnifaces.util.Messages.addGlobalInfo;
import java.io.Serializable;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import jakarta.annotation.PostConstruct;
import jakarta.enterprise.context.RequestScoped;
import jakarta.inject.Named;
import org.omnifaces.util.cache.CacheFactory;
@Named
@RequestScoped
public class CacheBean implements Serializable {
private static final long serialVersionUID = 1L;
private List<String> items;
private long key;
private String item;
private boolean reset;
private boolean disabled;
@PostConstruct
public void init() {
String date = new Date().toString();
items = new ArrayList<>();
items.add("A - " + date);
items.add("B - " + date);
items.add("C - " + date);
}
/**
* Demos reset via programmatic method.
*/
public void resetProgrammatic() {
CacheFactory.getCache(getContext(), "session").remove("firstCache");
}
/**
* Alternative way to reset via binding property to "reset" attribute of cache component.
*/
public void resetAttribute() {
// Note, no handler to revert back to false needed since bean
// is request scope.
reset = true;
}
public void disable() {
disabled = true;
}
public void saveItem(String item) {
this.item = item;
addGlobalInfo("Item {0} was posted back", item);
}
public List<String> getItems() {
return items;
}
public String getItem() {
return item;
}
public long getKey() {
return key;
}
public void setKey(long key) {
this.key = key;
}
public boolean isReset() {
return reset;
}
public boolean isDisabled() {
return disabled;
}
}
VDL documentation
API documentation
Java source code
org.omnifaces.util.cache.CacheFactory
org.omnifaces.component.output.OutputFamily
org.omnifaces.util.cache.CacheEntry
org.omnifaces.util.cache.DefaultCacheProvider
org.omnifaces.io.ResettableBufferedWriter
org.omnifaces.servlet.HttpServletResponseOutputWrapper
org.omnifaces.filter.OnDemandResponseBufferFilter
org.omnifaces.io.ResettableBufferedOutputStream
org.omnifaces.component.output.Cache
org.omnifaces.component.output.cache.el.CacheValue
org.omnifaces.util.cache.LruCache
org.omnifaces.servlet.BufferedHttpServletResponse
org.omnifaces.util.cache.Cache
org.omnifaces.io.ResettableBuffer
org.omnifaces.util.cache.CacheInstancePerScopeProvider
org.omnifaces.util.cache.CacheProvider
org.omnifaces.util.cache.DefaultCache
org.omnifaces.util.cache.TimeToLiveCache
org.omnifaces.util.cache.CacheInitializer
org.omnifaces.component.output.cache.el.CachingValueExpression