Portlet Cache – Expired cache and EhCache

A little guide to illustrate how to use two common content Cache system. The first comes from the portlet system while the last, ehcache, is used in many different system.

We’ll see the used of them in a Liferay Portlet.

Why should one web application spend time for processing the same page for any users when the result of it is the same for all them? It would be a waste of the time and consumes of resources for getting a page already generated for everyone.

I guess you already know the keyword to avoid it. The cache helps us to solve this problem in a easy way by choosing the portlet/resource we need to store for next request.

I’d like to speak of two options for caching the data in a Portlet. You can use a native systema commonly named “Expiration-based content caching” and/or (you can use it even together) a Spring support for ehCache.

Let’s start with the first, the expiration-based content caching.

The core of that system is located on portlet.xml at looks like as the follow xml

<portlet>
<portlet-name>orderPortlet</portlet-name>
<portlet-class>it.techannotation.warehouse.portlet.OrderPortlet</portlet-class>
<expiration-cache>300</expiration-cache>
<cache-scope>public</cache-scope>
...
</portlet>

The expiration-cache is expressed in second. So, in the above code, the cache expires after 5 minutes.

The cache-scope accepts two value: “Public” whether the content cache is shared across all portal users and “Private” whether the content cache is one by user.

So, in the previous example, all the user share the same content for 5 minutes.

Now, it’s time to test it. I used Liferay 6.1.1 CE and I browsed the portlet (after having added it to the page) as not logged user. The result? It doesn’t work…

Why?

Starting from this point:

http://issues.liferay.com/browse/LEP-5732?focusedCommentId=40135&page=com.atlassian.jira.plugin.system.issuetabpanels:comment-tabpanel

I checked that at the class com.liferay.portlet.InvokerPortletImpl. You can find it in the portal-impl.jar file under ROOT\WEB-INF\lib folder.
Check out these lines:

String remoteUser = renderRequest.getRemoteUser();

if ((remoteUser == null) || (_expCache == null) || (_expCache.intValue() == 0)) {
    invokeRender(renderRequest, renderResponse);
}

What happens is the code check if the user is authenticated and it returns not cached content. I updated the code in this way:

//String remoteUser = renderRequest.getRemoteUser();

if ((_expCache == null) || (_expCache.intValue() == 0)) {
 invokeRender(renderRequest, renderResponse);
}

It works for my aim. A little disclaimer: I’m not telling you that’s the right way to do it, simply I use it to solve my problem and I’m sharing that with you. If you find out a better solution please, let me know!!

Let’s go on illustrating ehcache system with Spring.  I’ve already written something about it in one of my previous post. So, probably I’m repeating something already known because the behaviour is the same for not-portlet application.

Anyway, I used this dependecy of ehcache

<dependency>
 <groupId>net.sf.ehcache</groupId>
 <artifactId>ehcache</artifactId>
 <version>2.3.2</version>
 <type>pom</type>
</dependency>

Then put your ehcache.xml under the classpath directory. It contains the cache configuration.

<?xml version="1.0" encoding="UTF-8"?>
<ehcache>
	<defaultCache maxElementsInMemory="50" eternal="false"
		overflowToDisk="false" memoryStoreEvictionPolicy="LFU" />

	<cache name="warehouseCache" eternal="false" maxElementsInMemory="100"
		overflowToDisk="false" diskPersistent="false" timeToIdleSeconds="0"
		timeToLiveSeconds="60" memoryStoreEvictionPolicy="LRU" />
</ehcache>

I used to cache the data from a database source. Why? Obviously because in a three tiers application the data layer is the most stressed part both for resource access and time computing.

@Cacheable(value="warehouseCache")
public List<Order> getOrders() {

 Query query = em.createNamedQuery("findAllWareHouse", Order.class);
 query.setHint("javax.persistence.cache.storeMode", "REFRESH");

 List<Order> orders = query.getResultList();

 return orders;
}

It works even for any type of object and with parameter key to store it.  Take a look at the highlighted row; I wanted to exclude the Jpa Cache get by EclipseLink because I manage the cache in different way. If you’re interested I guess you can find out more info at http://wiki.eclipse.org/EclipseLink/Examples/JPA/Caching 

In this scenario the content expires after 1 minute or whether the elements in cache are more of 100 elements. You might evict the cache element using @CacheEvict attribute so, you can have the whole cache control by code.

To be honest, now I have to bring up another type of cache used by Etag element. Unfortunately this method doesn’t work in Liferay 6.x because it doesn’t supported in that platoform.
You can check it looking at the Cache-Control object’s getETag method. It always returns null.

 

Advertisements

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s