Did you know? Programmers convert coffee to code.

If you like my articles, sponsor me a coffee.

EHCache and Java EE 6

I think this is another interesting topic came from the mids of my wokring experience. The problem was: add EHCache to the Hibernate JPA 2.0 implementation as a second level cache and add some other caches to store properties or remote interface result objects. Naturally there are some errors which you encounter. I’ll share mine and their solution with you.

Project settings

First of all let’s clarify the project settings. This is needed because you have to make decisions based on these settings. In the case of the article I had to make my decisions based on the following settings of the project:

  • Java EE 6 architecture
  • Java 7 SDK
  • Hibernate as the JPA 2.0 provider
  • Hibernate version 4
  • JBoss AS 6.1.1 runtime environment

I think this is enough for the topic I’m going to cover in this article. If I run into anything I need to mention I’ll do it — but we can start with this list of configuration.

Configuring EHCache

The first thing I had to do was configuring EHCache — not just for Hibernate but for some other caches too which will be used along in the project. The version was given: we should use 2.8.3 — as the newest version at this point of time. Well enough for me. I headed to add the EHCache dependency to the pom.xml as it is told in the documentation.

Not to mention: this was not really a configuration of itself. The main part is to create the cache manager and the caches used later on in the application. As mentioned at the beginning of this article, we needed 3 caches: one for storing the entity objects (a 2nd Level Cache for Hibernate), one for remote interface objects and a third for storing the system configuration (yes, every change of configuration properties requires a re-start of the system).

This configuration is done via the ehcache.xml file. Here you define your cache manager and the caches. Eventually you can define a default cache and if some of the libraries (Hibernate in this exact case) needs a cache then it creates one with the default properties.

In this particular case I defined three caches and named them after their usage. There is no need for a default cache in this case — but this can lead to problems if no other configuration is set.

<?xml version="1.0" encoding="UTF-8"?>
<ehcache xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="http://ehcache.org/ehcache.xsd" updateCheck="false" name="MyCacheManager">
    <!-- | Please see http://ehcache.sourceforge.net/documentation/configuration.html for | detailed information on how to configurigure caches in this file + -->
    <!-- Location of persistent caches on disk -->
    <diskStore path="java.io.tmpdir" />

    <cache name="SecondLevel" maxBytesLocalHeap="250M" timeToIdleSeconds="300" timeToLiveSeconds="1800" eternal="false" overflowToDisk="false" diskPersistent="false" memoryStoreEvictionPolicy="LFU" />
    <cache name="Remote" maxBytesLocalHeap="150M" timeToIdleSeconds="300" timeToLiveSeconds="1800" eternal="false" overflowToDisk="false" diskPersistent="false" memoryStoreEvictionPolicy="LFU" />
    <cache name="Configuration" maxBytesLocalHeap="50M" timeToIdleSeconds="300" timeToLiveSeconds="0" eternal="false" overflowToDisk="false" diskPersistent="false" memoryStoreEvictionPolicy="LFU" />
</ehcache>

Above you see the three caches defined with all properties. This configuration would definitely not work with EHCache

Configuring Hibernate

For Hibernate 4 there is a separate module hibernate-ehcache to use for EHCache with Hibernate. This is what you need to add to your pom.xml. Yes, this makes the usage of ehcache in the pom unnecessary and you can remove it. Good thing if Hibernate provides its implementation for EHCache.

First you have to set the cache mode for your <persistence-unit>:

&lt;shared-cache-mode&gt;ENABLE_SELECTIVE&lt;/shared-cache-mode&gt;

If you look at the documentation this mode is declared as default but it needs to be set explicitly too. I think this is not so bad that you couldn’t do this.

Besides this you need to enable some configuration for hibernate in your persistence.xml under the <properties>:

&lt;property name=&quot;hibernate.cache.use_second_level_cache&quot; value=&quot;true&quot;/&gt;
&lt;property name=&quot;hibernate.cache.region.factory_class&quot; value=&quot;org.hibernate.cache.ehcache.SingletonEhCacheRegionFactory&quot;/&gt;

The first line enables the usage of the Second Level Cache, the second line tells Hibernate which Factory to use to create an EHCache manager if it is not existent (because it is singleton, the CacheManager returns the already existing instance or creates a new one).

By default storing entities to the 2nd Level Cache is selective: you have to tell Hibernate to store your entities. This is done with the @Cacheable annotation which has to be placed on the entity itself:

@Entity
@Cacheable
public class YourEntity {
...

The default concurrency value used with the @Cacheable JPA 2 annotation is: READ_WRITE. @Cacheable is since JPA 2.0 available and it makes caching more transparent: you can switch your JPA implementation beneath your application.

Problems

Unfortunately there is seldom a project where the initial configuration works as you expect. Here are the problems I encountered while setting up the project to work with EHCache as defined.

Versions

Because of the usage of JBoss our project uses all those versions of dependent libraries which JBoss provides. For Hibernate it is 4.0.2.SP1. This is not the latest version but is at least Hibernate 4.

Since Hibernate 4 there is a separate hibernate-ehcache module to use with Hibernate and EHCache. But there is a catch with this module: it contains the Version 2.4.3 of ehcache-core — and this version is old and has some features less than you’d need (for example configuring the heap memory usage of each cache). However there is a solution.

Note: always use the same hibernate-ehcache version as of your Hibernate.

Using latest ehcache-core

You can exclude the old ehcache-core from hibernate-ehcache with Maven and then add the dependency with the right version as follows:

&lt;dependency&gt;
    &lt;groupId&gt;org.hibernate&lt;/groupId&gt;
    &lt;artifactId&gt;hibernate-ehcache&lt;/artifactId&gt;
    &lt;version&gt;4.2.0.SP1&lt;/version&gt;
    &lt;exclusions&gt;
        &lt;exclusion&gt;
            &lt;groupId&gt;net.sf.ehcache&lt;/groupId&gt;
            &lt;artifactId&gt;ehcache-core&lt;/artifactId&gt;
        &lt;/exclusion&gt;
    &lt;/exclusions&gt;
&lt;/dependency&gt;
&lt;dependency&gt;
    &lt;groupId&gt;net.sf.ehcache&lt;/groupId&gt;
    &lt;artifactId&gt;ehcache&lt;/artifactId&gt;
    &lt;version&gt;2.8.3&lt;/version&gt;
&lt;/dependency&gt;

This allows you to use the latest version of EHCache along with Hibernate.

Note: replace the version fields with those version numbers you are using / want to use.

Regions

Regions are the “alias names” of caches. If you want your Entities to be stored in a special named cache and not the default by Hibernate at the 2nd Level, then you have to specify the region along with the @Cache annotation (see example below). In the application above this is the case: we have one cache to store the entities. Hibernate names the caches after the qualified name of the entities. So if you have the class YourEntity in the package biz.hahamo.dev.model then Hibernates creates a cache named biz.hahamo.dev.model.YourEntity when using with the @Cacheable annotation or with @Cache without providing a region.

Note: the @Cache annotation is Hibernate-specific. If you want to stick to JPA 2 then you have to use caches with their default names / regions.

@Entity
@Cache(usage = CacheConcurrencyStrategy.READ_WRITE, region = &quot;SecondLevel&quot;)
public class YourEntity {
...

usage is required. It is the same concurrency strategy defaulted with @Cacheable however with @Cache you can set another one defined by Hibernate:

  • NONE
  • READ_ONLY
  • NONSTRICT_READ_WRITE
  • READ_WRITE
  • TRANSACTIONAL

I will not go into detail about usages. There is a lot of information in the WWW to look-up.

Naming problems

We have the configuration, set the region for the caches and we start the application server and get the following error:

11:45:52,884 ERROR [org.jboss.msc.service.fail] (ServerService Thread Pool -- 48) MSC000001: Failed to start service jboss.persistenceunit.&quot;module.ear/submodule-0.1-SNAPSHOT.war#primary&quot;: org.jboss.msc.service.StartException in service jboss.persistenceunit.&quot;module.ear/submodule-0.1-SNAPSHOT.war#primary&quot;: javax.persistence.PersistenceException: [PersistenceUnit: primary] Unable to build EntityManagerFactory
    at org.jboss.as.jpa.service.PersistenceUnitServiceImpl$1.run(PersistenceUnitServiceImpl.java:103) [jboss-as-jpa-7.2.1.Final-redhat-10.jar:7.2.1.Final-redhat-10]
    at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1145) [rt.jar:1.7.0_55]
    at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:615) [rt.jar:1.7.0_55]
    at java.lang.Thread.run(Thread.java:745) [rt.jar:1.7.0_55]
    at org.jboss.threads.JBossThread.run(JBossThread.java:122) [jboss-threads-2.1.0.Final-redhat-1.jar:2.1.0.Final-redhat-1]
Caused by: javax.persistence.PersistenceException: [PersistenceUnit: primary] Unable to build EntityManagerFactory
    at org.hibernate.ejb.Ejb3Configuration.buildEntityManagerFactory(Ejb3Configuration.java:930)
    at org.hibernate.ejb.Ejb3Configuration.buildEntityManagerFactory(Ejb3Configuration.java:904)
    at org.hibernate.ejb.HibernatePersistence.createContainerEntityManagerFactory(HibernatePersistence.java:92)
    at org.jboss.as.jpa.service.PersistenceUnitServiceImpl.createContainerEntityManagerFactory(PersistenceUnitServiceImpl.java:200) [jboss-as-jpa-7.2.1.Final-redhat-10.jar:7.2.1.Final-redhat-10]
    at org.jboss.as.jpa.service.PersistenceUnitServiceImpl.access$600(PersistenceUnitServiceImpl.java:57) [jboss-as-jpa-7.2.1.Final-redhat-10.jar:7.2.1.Final-redhat-10]
    at org.jboss.as.jpa.service.PersistenceUnitServiceImpl$1.run(PersistenceUnitServiceImpl.java:99) [jboss-as-jpa-7.2.1.Final-redhat-10.jar:7.2.1.Final-redhat-10]
    ... 4 more
Caused by: org.hibernate.cache.CacheException: net.sf.ehcache.CacheException: Caches cannot be added by name when default cache config is not specified in the config. Please add a default cache config in the configuration.
    at org.hibernate.cache.ehcache.AbstractEhcacheRegionFactory.getCache(AbstractEhcacheRegionFactory.java:189)
    at org.hibernate.cache.ehcache.AbstractEhcacheRegionFactory.buildEntityRegion(AbstractEhcacheRegionFactory.java:132)
    at org.hibernate.cache.ehcache.SingletonEhCacheRegionFactory.buildEntityRegion(SingletonEhCacheRegionFactory.java:47)
    at org.hibernate.internal.SessionFactoryImpl.&lt;init&gt;(SessionFactoryImpl.java:348)
    at org.hibernate.cfg.Configuration.buildSessionFactory(Configuration.java:1762)
    at org.hibernate.ejb.EntityManagerFactoryImpl.&lt;init&gt;(EntityManagerFactoryImpl.java:94)
    at org.hibernate.ejb.Ejb3Configuration.buildEntityManagerFactory(Ejb3Configuration.java:920)
    ... 9 more
Caused by: net.sf.ehcache.CacheException: Caches cannot be added by name when default cache config is not specified in the config. Please add a default cache config in the configuration.
    at net.sf.ehcache.CacheManager.addCache(CacheManager.java:938)
    at org.hibernate.cache.ehcache.AbstractEhcacheRegionFactory.getCache(AbstractEhcacheRegionFactory.java:181)
    ... 15 more

Well, this sounds not good. If we read through the StackTrace then we see: we have to add a default cache too if we want to assign entities by name. Let’s extend the ehcache.xml file with the default cache:

&lt;defaultCache eternal=&quot;false&quot; maxBytesLocalHeap=&quot;42M&quot; overflowToDisk=&quot;false&quot; diskPersistent=&quot;false&quot; timeToIdleSeconds=&quot;0&quot; timeToLiveSeconds=&quot;600&quot; memoryStoreEvictionPolicy=&quot;LRU&quot; /&gt;

This default cache removes the cause of the error but you get a warning if you look carefully in your log during the start-up. The warning has the code: HHH020003.

HHH020003


WARN  [org.hibernate.cache.ehcache.AbstractEhcacheRegionFactory] (ServerService Thread Pool -- 48) HHH020003: Could not find a specific ehcache configuration for cache named [YOUR_WAR_FILE.war#primary.SecondLevel]; using defaults.

This comes because Hibernate has a region prefix which will be used to access the specified regions (with the @Cache annotation). And this warning tells us, that our region SecondLevel is not found by Hibernate because it is looking for primary.SecondLevel. To avoid this warning, we can define a property among the other <properties> in persistence.xml:

&lt;property name=&quot;hibernate.cache.region_prefix&quot; value=&quot;&quot;/&gt;

This sets the default prefix for Hibernate-regions to nothing (empty string). This removes the warning and you can remove the default cache because the error message is removed too.

Mutable entities to read

If you use @Cache and the usage of READ_ONLY you may get the following warning when starting the server:

[org.hibernate.cache.ehcache.internal.strategy.EhcacheAccessStrategyFactoryImpl] (ServerService Thread Pool -- 48) HHH020007: read-only cache configured for mutable entity [SecondLevel]

This tells you, that one of your annotated objects can be edited (it has setter methods for example). In this case you should consider changing the usage to READ_WRITE.

Conclusion and code

Introducing EHCache into a JEE 6 application is not a big deal if you get along with the default configuration and the provided dependencies. But if you need some more you have to look through the WWW or find your own solution. I tied a bunch of problems together where I had to look and found answers on the net or not and had to figure out myself. I hope I can be of help.

If you have any questions, do not hesitate to ask. I’ll do my best to reply to you with an answer ASAP.

And for this article there is no source code. I do not have any project I could show you but if I make one I’ll add the reference to the code to this article. And I guess this description is really straightforward to use. If not, tell me.

 

GHajba
 

Senior developer, consultant, author, mentor, apprentice.

I love to share my knowledge and insights what I achieve through my daily work which is not trivial — at least not for me.

Click Here to Leave a Comment Below 0 comments
%d bloggers like this: