Preamble
I you are planing to use ehCache as a session management implementation first check, if you cannot by any chance use a already provided, and probably better suited session implementation. If you are using a web container or a full fleshed jee server you really should try this first
Why
Okay. You are quite sure to not do it the right easy way. Here are some hints, why you might want to use ehCache for sessions
- Your service is not part of a jee server/web container.
- Your service is stateless but from time to time, you need states (framework code).
- You cannot distinguish calls because of a proxy between you and the distinguishable client, e.g you are some kind of middleware for a service/service which does not provided distinguishable data as default, but uses parameters like userId or sessionId conditionally but not constitutively.
- You just did not RTFM and want to do it your way.
For 1 please check, if a web container like jetty is an option. You certainly use web access of the whole session thingy would not pop up for you.
For 2 please check, if Apache Shiro won't do what you want. If not, ehCache could be your friend.
For 3... welcome to the club.
For 4... well I guess if you did not read the manual, you won't read this either.
How to
If you want to implement a session management using ehCache please assure that your data is serializable. This will reduce problems and let you use the sensitive features of ehCache. namely persistence to disk, caching nodes, recover from this, and so on.
Do not use a cache for every session, but one cache for all sessions. The sessionId
is the key on your cache, and a values are going to a Map
. Do not forget about concurrency (think of ajax calls). It might be best to use the ConcurrentHashMap
from java.util.concurrent
. But maybe you are Dr Heinz M. Kabutz and find a even cooler way to do it.
I found it very helpfull to rather use size than amount of elements to keep in storage. You might not know, what data/objets are stored later on. Do not forget to set a persistence strategy. I used storing to temp folder here.
<?xml version="1.0" encoding="UTF-8"?>
<ehcache
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:noNamespaceSchemaLocation="ehcache.xsd"
updateCheck="true"
monitoring="autodetect"
dynamicConfig="true">
<diskStore path="java.io.tmpdir"/>
<cache name="vocCache"
eternal="false"
maxElementsInMemory="100MB"
maxElementsOnDisk="1GB"
timeToIdleSeconds="3600"
timeToLiveSeconds="0"
memoryStoreEvictionPolicy="LRU"
diskExpiryThreadIntervalSeconds="60">
<persistence strategy="localTempSwap" />
</cache>
Because we want to implement a session manager, we do not bother about timeToLiveSeconds
. Sessions time out after a certain idle time. So we do not constrain the element to a maximal ttl, but use the timeToIdleSeconds
to let an element time out.
Do not bother with the timeToIdleSeconds
and timeToLiveSeconds
because you can set specific values to the elements to add later on.
Eviction
One note on the expiry time. An element in memory will never be evicted because of a configured time. The memory will build up until the defined memory constraint is hit. So if you define 100 elements, if the 101 element is added, the memoryStoreEvictionPolicy
will bet triggered and one element will be - in this configuration - flushed to disk (ehCache 2.2). For the disk storage, there will be a thread checking for expiry time (diskExpiryThreadIntervalSeconds
). See the documentation.
So you have to check the retrieved element from the cache using isExpired()
to be sure it has not expired.
So in the end, you will end up with something like this:
GET
Cache cache = CacheManager.getInstance().getCache(CACHE_NAME);
Element elem = cache.get(identifier);
if (elem == null)
{
throw new SessionNotFoundException(identifier);
}
if (elem.isExpired())
{
throw new SessionExpiredException(identifier);
}
return elem.getObjectValue();
PUT
Cache cache = CacheManager.getInstance().getCache(CACHE_NAME);
// We use ttl = 0 and tti=<ttlInMinutes>, because session timeout is based on session idle timout.
element = new Element(identifier, new SessionElement(), Boolean.FALSE, (int) (timeToLive / VALUE_MS), 0);
cache.put(element);