

This is a book about Ehcache, a widely used open source Java cache. Ehcache has grown in size and scope since it was introduced in October 2003. As people used it they often noticed it was missing a feature they wanted. Over time, the features that were repeatedly asked for, and make sense for a Cache, have been added.
Ehcache is now used for Hibernate caching, data access object caching, security credential caching, web caching, SOAP and RESTful server caching, application persistence and distributed caching.
In August 2009, Ehcache was acquired by Terracotta, Inc.
This book is for Ehcache version 1.7.1.
The intended audience for this book is developers who use ehcache. It should be able to be used to start from scratch, get up and running quickly, and also be useful for the more complex options.
Ehcache is about performance and load reduction of underlying resources. Another natural audience is performance specialists.
It is also intended for application and enterprise architects. Some of the features of ehcache, such as distributed caching and Java EE caching, are alternatives to be considered along with other ways of solving those problems. This book discusses the trade-offs in Ehcache's approach to help make a decision about appropriateness of use.
Ehcache has had many contributions in the form of forum discussions, feature requests, bug reports, patches and code commits.
Rather than try and list the many hundreds of people who have contributed to Ehcache in some way it is better to link to the web site where contributions are acknowledged in the following ways:
Thanks to Denis Orlov for suggesting the need for a book in the first place.

Adam Murdoch (an all round top Java coder) came up with the name in a moment of inspiration while we were stuck on the SourceForge project create page. Ehcache is a palindrome. He thought the name was wicked cool and we agreed.
The logo is similarly symmetrical, and is evocative of the diagram symbol for a doubly-linked list. That structure lies at the heart of ehcache.
--- Introduction ---
Ehcache is a cache library. Before getting into ehcache, it is worth stepping back and thinking about caching generally.
Wiktionary defines a cache as A store of things that will be required in future, and can be retrieved rapidly. That is the nub of it.
In computer science terms, a cache is a collection of temporary data which either duplicates data located elsewhere or is the result of a computation. Once in the cache, the data can be repeatedly accessed inexpensively.
While Ehcache concerns itself with Java objects, caching is used throughout computing, from CPU caches to the DNS system. Why? Because many computer systems exhibit locality of reference. Data that is near other data or has just been used is more likely to be used again.
Chris Anderson, of Wired Magazine, coined the term The Long Tail to refer to Ecommerce systems. The idea that a small number of items may make up the bulk of sales, a small number of blogs might get the most hits and so on. While there is a small list of popular items, there is a long tail of less popular ones.

The Long Tail
The Long Tail is itself a vernacular term for a Power Law probability distribution. They don't just appear in ecommerce, but throughout nature. One form of a Power Law distribution is the Pareto distribution, commonly know as the 80:20 rule.
This phenomenon is useful for caching. If 20% of objects are used 80% of the time and a way can be found to reduce the cost of obtaining that 20%, then the system performance will improve.
The short answer is that it often does, due to the effects noted above.
The medium answer is that it often depends on whether it is CPU bound or I/O bound. If an application is I/O bound then then the time taken to complete a computation depends principally on the rate at which data can be obtained. If it is CPU bound, then the time taken principally depends on the speed of the CPU and main memory.
While the focus for caching is on improving performance, it it also worth realizing that it reduces load. The time it takes something to complete is usually related to the expense of it. So, caching often reduces load on scarce resources.
CPU bound applications are often sped up by:
The role of caching, if there is one, is to temporarily store computations that may be reused again.
An example from Ehcache would be large web pages that have a high rendering cost. Another caching of authentication status, where authentication requires cryptographic transforms.
Many applications are I/O bound, either by disk or network operations. In the case of databases they can be limited by both.
There is no Moore's law for hard disks. A 10,000 RPM disk was fast 10 years ago and is still fast. Hard disks are speeding up by using their own caching of blocks into memory.
Network operations can be bound by a number of factors:
The caching of data can often help a lot with I/O bound applications. Some examples of Ehcache uses are:
The flip side of increased performance is increased scalability. Say you have a database which can do 100 expensive queries per second. After that it backs up and if connections are added to it it slowly dies.
In this case, caching may be able to reduce the workload required. If caching can cause 90 of that 100 to be cache hits and not even get to the database, then the database can scale 10 times higher than otherwise.
The short answer is that it depends on a multitude of factors being:
In applications that are I/O bound, which is most business applications, most of the response time is getting data from a database. Therefore the speed up mostly depends on how much reuse a piece of data gets.
In a system where each piece of data is used just once, it is zero. In a system where data is reused a lot, the speed up is large.
The long answer, unfortunately, is complicated and mathematical. It is considered next.
Amdahl's law, after Gene Amdahl, is used to find the system speed up from a speed up in part of the system.
1 / ((1 - Proportion Sped Up) + Proportion Sped Up / Speed up)
The following examples show how to apply Amdahl's law to common situations. In the interests of simplicity, we assume:
A Hibernate Session.load() for a single object is about 1000 times faster from cache than from a database.
A typical Hibernate query will return a list of IDs from the database, and then attempt to load each. If Session.iterate() is used Hibernate goes back to the database to load each object.
Imagine a scenario where we execute a query against the database which returns a hundred IDs and then load each one.
The query takes 20% of the time and the roundtrip loading takes the rest (80%). The database query itself is 75% of the time that the operation takes. The proportion being sped up is thus 60% (75% * 80%).
The expected system speedup is thus:
1 / ((1 - .6) + .6 / 1000)
= 1 / (.4 + .006)
= 2.5 times system speedupAn observed speed up from caching a web page is 1000 times. Ehcache can retrieve a page from its SimplePageCachingFilter in a few ms.
Because the web page is the end result of a computation, it has a proportion of 100%.
The expected system speedup is thus:
1 / ((1 - 1) + 1 / 1000)
= 1 / (0 + .001)
= 1000 times system speedupCaching the entire page is a big win. Sometimes the liveness requirements vary in different parts of the page. Here the SimplePageFragmentCachingFilter can be used.
Let's say we have a 1000 fold improvement on a page fragment that taking 40% of the page render time.
The expected system speedup is thus:
1 / ((1 - .4) + .4 / 1000)
= 1 / (6 + .004)
= 1.6 times system speedupIn real life cache entrie do not live forever. Some examples that come close are "static" web pages or fragments of same, like page footers, and in the database realm, reference data, such as the currencies in the world.
Factors which affect the efficiency of a cache are:
Ehcache keeps these statistics for each Cache and each element, so they can be measured directly rather than estimated.
Also in real life, we generally do not find a single server?
Assume a round robin load balancer where each hit goes to the next server.
The cache has one entry which has a variable lifespan of requests, say caused by a time to live. The following table shows how that lifespan can affect hits and misses.
Server 1 Server 2 Server 3 Server 4 M M M M H H H H H H H H H H H H H H H H ... ... ... ...
The cache hit ratios for the system as a whole are as follows:
Entry Lifespan Hit Ratio Hit Ratio Hit Ratio Hit Ratio in Hits 1 Server 2 Servers 3 Servers 4 Servers 2 1/2 0/2 0/2 0/2 4 3/4 2/4 1/4 0/4 10 9/10 8/10 7/10 6/10 20 19/20 18/20 17/20 16/10 50 49/50 48/50 47/20 46/50
The efficiency of a cluster of standalone caches is generally:
(Lifespan in requests - Number of Standalone Caches) / Lifespan in requests
Where the lifespan is large relative to the number of standalone caches, cache efficiency is not much affected.
However when the lifespan is short, cache efficiency is dramatically affected.
(To solve this problem, Ehcache supports distributed caching, where an entry put in a local cache is also propagated to other servers in the cluster.)
From the above we now have:
1 / ((1 - Proportion Sped Up * effective cache efficiency) + (Proportion Sped Up * effective cache efficiency)/ Speed up)
effective cache efficiency = cache efficiency * cluster efficiency
Applying this to the earlier web page cache example where we have cache efficiency of 35% and average request lifespan of 10 requests and two servers:
cache efficiency = .35
cluster efficiency = .(10 - 1) / 10
= .9
effective cache efficiency = .35 * .9
= .315
1 / ((1 - 1 * .315) + 1 * .315 / 1000)
= 1 / (.685 + .000315)
= 1.45 times system speedupWhat if, instead the cache efficiency is 70%; a doubling of efficiency. We keep to two servers.
cache efficiency = .70
cluster efficiency = .(10 - 1) / 10
= .9
effective cache efficiency = .70 * .9
= .63
1 / ((1 - 1 * .63) + 1 * .63 / 1000)
= 1 / (.37 + .00063)
= 2.69 times system speedupWhat if, instead the cache efficiency is 90%; a doubling of efficiency. We keep to two servers.
cache efficiency = .90
cluster efficiency = .(10 - 1) / 10
= .9
effective cache efficiency = .9 * .9
= .81
1 / ((1 - 1 * .81) + 1 * .81 / 1000)
= 1 / (.19 + .00081)
= 5.24 times system speedupWhy is the reduction so dramatic? Because Amdahl's law is most sensitive to the proportion of the system that is sped up.
--- Getting Started ---
Firstly, if you have not downloaded Ehcache, you can download it here.
Ehcache can be used directly. It can also be used with the popular Hibernate Object/Relational tool. Finally, it can be used for Java EE Servlet Caching.
This quick guide gets you started on each of these. The rest of the documentation can be explored for a deeper understanding.
See the Code Samples chapter for more information on direct interaction with ehcache.
See the Hibernate Caching chapter for more information.
See the Web Caching chapter for more information.
By default it will listen on port 8080, will have both RESTful and SOAP web services enabled, and will use a sample Ehcache configuration from the WAR module.
See the Cache Server chapter for more information.
Ehcache contains an early draft implementation of JCache contained in the net.sf.ehcache.jcache package.
See the JSR107 chapter for usage.
Usually, with these, you are using Ehcache without even realising it. The first steps in getting more control over what is happening are:
---- Features ----
Over the years, various performance tests have shown Ehcache to be one of the fastest Java caches. Ehcache's threading is designed for large, high concurrency systems.
Extensive performance tests in the test suite keep ehcache's performance consistent between releases.
As an example, some guys have created a java cache test tool called cache4j_perfomance_tester.
The results for ehcache-1.1 and ehcache-1.2 follow.
ehcache-1.1 [java] --------------------------------------------------------------- [java] java.version=1.4.2_09 [java] java.vm.name=Java HotSpot(TM) Client VM [java] java.vm.version=1.4.2-54 [java] java.vm.info=mixed mode [java] java.vm.vendor="Apple Computer, Inc." [java] os.name=Mac OS X [java] os.version=10.4.5 [java] os.arch=ppc [java] --------------------------------------------------------------- [java] This test can take about 5-10 minutes. Please wait ... [java] --------------------------------------------------------------- [java] |GetPutRemoveT |GetPutRemove |Get | [java] --------------------------------------------------------------- [java] cache4j 0.4 |9240 |9116 |5556 | [java] oscache 2.2 |33577 |30803 |8350 | [java] Ehcache 1.1 |7697 |6145 |3395 | [java] jcs 1.2.7.0 |8966 |9455 |4072 | [java] --------------------------------------------------------------- ehcache-1.2 [java] --------------------------------------------------------------- [java] java.version=1.4.2_09 [java] java.vm.name=Java HotSpot(TM) Client VM [java] java.vm.version=1.4.2-54 [java] java.vm.info=mixed mode [java] java.vm.vendor="Apple Computer, Inc." [java] os.name=Mac OS X [java] os.version=10.4.5 [java] os.arch=ppc [java] --------------------------------------------------------------- [java] This test can take about 5-10 minutes. Please wait ... [java] --------------------------------------------------------------- [java] |GetPutRemoveT |GetPutRemove |Get | [java] --------------------------------------------------------------- [java] cache4j 0.4 |9410 |9053 |5865 | [java] oscache 2.2 |28076 |30833 |8031 | [java] Ehcache 1.2 |8753 |7072 |3479 | [java] jcs 1.2.7.0 |8806 |9522 |4097 | [java] ---------------------------------------------------------------
Many users of Ehcache hardly know they are using it. Sensible defaults require no initial configuration.
The API is very simple and easy to use, making it possible to get up and running in minutes. See the Code Samples for details.
Ehcache 1.2 is 110KB making it convenient to package.
The only dependency for core use is the JCACHE API.
The largest Ehcache installations use memory and disk stores in the gigabyte range. Ehcache is tuned for these large sizes.
The largest Ehcache installations use hundreds of caches.
There is a tension between thread safety and performance. Ehcache's threading started off coarse-grained, but has increasingly made use of ideas from Doug Lea to achieve greater performance. Over the years there have been a number of scalability bottlenecks identified and fixed.
Ehcache 1.2 introduced multiple CacheManagers per virtual machine. This enables completely difference ehcache.xml configurations to be applied.
As of ehcache-1.2 there is an API for Objects in addition to the one for Serializable. Non-serializable Objects can use all parts of Ehcache except for DiskStore and replication. If an attempt is made to persist or replicate them they are discarded and a WARNING level log message emitted.
The APIs are identical except for the return methods from Element. Two new methods on Element: getObjectValue and getKeyValue are the only API differences between the Serializable and Object APIs. This makes it very easy to start with caching Objects and then change your Objects to Seralizable to participate in the extra features when needed. Also a large number of Java classes are simply not Serializable.
Time to lives and time to idles are settable per cache. In addition, from ehcache-1.2.1, overrides to these can be set per Element.
Ehcache 1.2 introduced Less Frequently Used and First In First Out caching eviction policies. These round out the eviction policies.
Ehcache, like most of the cache solutions, provides high performance memory and disk stores.
Flexible, extensible, high performance distributed caching. The default implementation supports cache discovery via multicast or manual configuration. Updates are delivered either asynchronously or synchronously via custom RMI connections. Additional discovery or delivery schemes can be plugged in by third parties.
See the Distributed Caching documentation for more feature details.
The time-to-live, time-to-idle, maximum in-memory and on-disk capacities can be tuned at runtime simply by mutating the cache's configuration object.
Ehcache offers the the most complete implementation of the JSR107 JCACHE to date.
Because JCACHE has not yet been released the JCACHE API that Ehcache implements has been released as net.sf.jsr107cache.
Implementers can code to the JCACHE API which will create portability to other caching solutions in the future.
The maintainer of ehcache, Greg Luck, is on the expert committee for JSR107.
Ehcache 1.2 provides CacheManagerEventListener and CacheEventListener interfaces. Implementations can be plugged in and configured in ehcache.xml.
Distributed caching, introduced in Ehcache 1.2 involves many choices and tradeoffs. The Ehcache team believe that one size will not fit all. Implementers can use built-in mechanisms or write their own. A plugin development guide is included for this purpose.
Create your own Cache Extensions, which hold a reference to a cache and are bound to its lifecycle.
Create your own Cache Loaders, which are general purpose asynchronous methods for loading data into caches, or use them in pull-through configuration.
Create an Exception Handler which is invoked if any Exception occurs on a cache operation.
With Ehcache 1.1 in 2004, Ehcache was the first open source Java cache to introduce persistent storage of cache data on disk on shutdown. The cached data is then accessible the next time the application runs.
With Ehcache 1.2, the flushing of entries to disk can be executed with a cache.flush() method whenever required, making it easier to use ehcache
Register Cache Manager listeners through the CacheManagerEventListener interface with the following event methods:
Register Cache Event Listeners through the CacheEventListener interfaces, which provides a lot of flexibility for post-processing of cache events. The methods are:
Ehcache is JMX enabled. You can monitor and manage the following MBeans:
See the net.sf.ehcache.management package.
See http://weblogs.java.net/blog/maxpoon/archive/2007/06/extending_the_n_2.html for an online tutorial.
Ehcache 1.2 introduced a full-featured, fine-grained distributed caching mechanism for clusters, supporting multiple replication mechanisms through plugins.
Ehcache 1.6 supports replication via RMI, JGroups, JMS or Terracotta.
Peer discovery may be either manually configured or automatic, using multicast. Multicast is simple, and adds and removes peers automatically. Manual configuration gives fine control and is useful for situations where multicast is blocked.
The built-in delivery mechanism uses RMI with custom sockets over TCP, not UDP.
Replication can be set to synchronous Or asynchronous, per cache.
Replication can be set to copy or invalidate, per cache, as is appropriate.
No programming changes are required to make use of replication. Only configuration in ehcache.xml.
Distributed caching, introduced in Ehcache 1.2 involves many choices and tradeoffs. The Ehcache team believe that one size will not fit all. Implementers can use built-in mechanisms or write their own. A plugin development guide is included for this purpose.
Distributed caches enter and leave the cluster at different times. Caches can be configured to bootstrap themselves from the cluster when they are first initialized.
An abstract factory, BootstrapCacheLoaderFactory has been defined along with an interface BootstrapCacheLoader along with an RMI based default implementation.
Ehcache now comes with a Cache Server, available as a WAR for most web containers, or as a standalone server. The Cache Server has two apis: RESTful resource oriented, and SOAP. Both support clients in any programming language.
The Ehcache implementation strictly follows the RESTful resource-oriented architecture style.
Specifically:
For performance, HTTP/1.1 caching features are fully supported such as Last-Modified, ETag and so on. Ehcache responsds correctly to HEAD and conditional GET requests.
The Ehcache RESTFul Web Services API exposes the singleton CacheManager, which typically has been configured in ehcache.xml or an IoC container. Multiple CacheManagers are not supported.
The API definition is as follows:
The standalone server comes with its own embedded Glassfish web container.
It also comes packaged as a WAR for deployment to any Servlet 2.5 web container. Glassfish V2/3, Tomcat 6 and Jetty 6 have been tested.
High quality implementations for common caching scenarios and patterns.
A cache which blocks subsequent threads until the first read thread populates a cache entry.
SelfPopulatingCache - a read-through cache. A cache that populates elements as they are requested without requiring the caller to know how the entries are populated. It also enables refreshes of cache entries without blocking reads on the same entries.
A high performance Java EE servlet filter that caches pages based on the request URI and Query String. It also gzips the pages and delivers them to browsers either gzipped or ungzipped depending on the HTTP request headers. Use to cache entire Servlet pages, whether from JSP, velocity, or any other rendering technology.
Tested with Orion and Tomcat.
A high performance Java EE filter that caches page fragments based on the request URI and Query String. Use with Servlet request dispatchers to cache parts of pages, whether from JSP, velocity, or any other rendering technology. Can be used from JSPs using jsp:include.
Tested with Orion and Tomcat.
This is the trusty old command pattern with a twist: asynchronous behaviour, fault tolerance and caching. Creates a command, caches it and then attempts to execute it.
Tested with Hibernate2.1.8 and Hibernate3.1.3, which can utilise all of the new features except for Object API and multiple session factories each using a different Ehcache CacheManager.
A new net.sf.ehcache.hibernate.EhCacheProvider makes those additional features available to Hibernate-3.1.3. A version of the new provider should make it into the Hibernate3.2 release.
Ehcache-1.6 is compatible with Google App Engine.
See the Google App Engine HowTo.
Ehcache-2.0 has support for JTA, making it a fully XA compliant resource participating in the transaction, two-phase commit and recovery.
See the complete JTA documentation.
The Ehcache team believe that the first and most important quality measure is a well designed and comprehensive test suite.
Ehcache has a relatively high 86% test coverage of source code. This has edged higher over time. Clover enforces the test coverage. Most of the missing 14% is logging and exception paths.
The Ehcache JUnit test suite contains some long-running system tests which place high load on different Ehcache subsystems to the point of failure and then are back off to just below that point. The same is done with limits such as the amount of Elements that can fit in a given heap size. The same is also done with performance testing of each subsystem and the whole together. The same is also done with network tests for cache replication.
The tests serve a number of purposes:
Ehcache also has concurrency testing, which typically uses 50 concurrent threads hammering a piece of code. The test suites are also run on multi-core or multi-cpu machines so that concurrency is real rather than simulated. Additionally, every concurrency related issue that has ever been anticipated or resulted in a bug report has a unit test which prevents the condition from recurring. There are no reported issues that have not been reproduced in a unit test.
Concurrency unit tests are somewhat difficult to write, and are often overlooked. The team considers these tests a major factor in ehcache's quality.
Ehcache came about in the first place because of production issues with another open source cache.
Final release versions of Ehcache have been production tested on a very busy e-commerce site, supporting thousands of concurrent users, gigabyte size caches on large multi-cpu machines. It has been the experience of the team that most threading issues do not surface until this type of load has been applied. Once an issue has been identified and investigated a concurrency unit test can then be crafted.
A core belief held by the project team is that a project needs good documentation to be useful.
In ehcache, this is manifested by:
Ehcache is used extensively. See the Who is Using? page, or browse Google.
Projects like Linux maintain their quality through a restricted change process, whereby changes are submitted as patches, then reviewed by the maintainer and included, or modified. Ehcache follows the same process.
Through the SourceForge project bug tracker, the full history of all bugs are shown, including current status. We take this for granted in an open source project, as this is typically a feature that all open source projects have, but this transparency makes it possible to gauge the quality and riskiness of a library, something not usually possible in commercial products.
The Ehcache team is serious about quality. If one user is having a problem, it probably means others are too, or will have. The Ehcache team use Ehcache themselves in production. Every effort will be made to provide fixes for serious production problems as soon as possible. These will be committed to trunk. From there an affected user can apply the fix to their own branch.
Ehcache's original Apache1.1 copyright and licensing was reviewed and approved by the Apache Software Foundation, making Ehcache suitable for use in Apache projects. ehcache-1.2 is released under the updated Apache 2.0 license.
The Apache license is also friendly one, making it safe and easy to include Ehcache in other open source projects or commercial products.
--- Key Concepts ---

Top Level Package Diagram
Ehcache consists of a CacheManager, which manages caches. Caches contain elements, which are essentially name value pairs. Caches are physically implemented either in-memory, or on disk.

CacheManager Class Diagram
The CacheManager comprises Caches which in turn comprise Elements.
Creation of, access to and removal of caches is controlled by the CacheManager.
CacheManager supports two creation modes: singleton and instance.
Ehcache-1.1 supported only one CacheManager instance which was a singleton. CacheManager can still be used in this way using the static factory methods.
From ehcache-1.2, CacheManager has constructors which mirror the various static create methods. This enables multiple CacheManagers to be created and used concurrently. Each CacheManager requires its own configuration.
If the Caches under management use only the MemoryStore, there are no special considerations. If Caches use the DiskStore, the diskStore path specified in each CacheManager configuration should be unique. When a new CacheManager is created, a check is made that there are no other CacheManagers using the same diskStore path. If there are, a CacheException is thrown. If a CacheManager is part of a cluster, there will also be listener ports which must be unique.
If an application creates instances of CacheManager using a constructor, and also calls a static create method, there will exist a singleton instance of CacheManager which will be returned each time the create method is called together with any other instances created via constructor. The two types will coexist peacefully.

Ehcache Interface Diagram
All caches implement the Ehcache interface. A cache has a name and attributes. Each cache contains Elements.
A Cache in Ehcache is analogous to a cache region in other caching systems.
Cache elements are stored in the MemoryStore. Optionally they also overflow to a DiskStore.

Element Class Diagram
An element is an atomic entry in a cache. It has a key, a value and a record of accesses. Elements are put into and removed from caches. They can also expire and be removed by the Cache, depending on the Cache settings.
As of ehcache-1.2 there is an API for Objects in addition to the one for Serializable. Non-serializable Objects can use all parts of Ehcache except for DiskStore and replication. If an attempt is made to persist or replicate them they are discarded without error and with a DEBUG level log message.
The APIs are identical except for the return methods from Element. Two new methods on Element: getObjectValue and getKeyValue are the only API differences between the Serializable and Object APIs. This makes it very easy to start with caching Objects and then change your Objects to Seralizable to participate in the extra features when needed. Also a large number of Java classes are simply not Serializable.
Caches can be used in different ways. Each of these ways follows a cache usage pattern. Ehcache supports the following:
Here, to put something in the cache you do cache.put(Element element) and to get something from the cache you do cache.get(Object key).
You are aware you are using a cache and you are doing so consciously.
Here, you just do gets to the cache using cache.get(Object key). The cache itself knows how to populate an entry.
See the SelfPopulatingCache for more on this pattern.
--- Architecture ---
This diagram shows the architecture of Ehcache. It is current as of Ehcache-1.6.2.

--- Cache Configuration ---
Caches can be configured in Ehcache either declaratively, in xml, or by creating them programmatically and specifying their parameters in the constructor.
While both approaches are fully supported it is generally a good idea to separate the cache configuration from runtime use. There are also these benefits:
Certain aspects of cache configuration can also be modified dynamically at runtime.
This chapter covers XML declarative configuration. See the Code samples for programmatic and dynamic configuration.
Ehcache is redistributed by lots of projects. They may or may not provide a sample Ehcache XML configuration file. If one is not provided, download Ehcache from http://ehcache.org. It, and the ehcache.xsd is provided in the distribution.
Ehcache configuration files must be comply with the Ehcache XML schema, ehcache.xsd, reproduced below.
It can also be downloaded from http://ehcache.org/ehcache.xsd.
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema" elementFormDefault="qualified"
version="1.7">
<xs:element name="ehcache" >
<xs:complexType>
<xs:sequence>
<xs:element minOccurs="0" maxOccurs="1" ref="diskStore"/>
<xs:element minOccurs="0" maxOccurs="1"
ref="cacheManagerEventListenerFactory"/>
<xs:element minOccurs="0" maxOccurs="unbounded"
ref="cacheManagerPeerProviderFactory"/>
<xs:element minOccurs="0" maxOccurs="unbounded"
ref="cacheManagerPeerListenerFactory"/>
<xs:element minOccurs="0" maxOccurs="1"
ref="terracottaConfig"/>
<xs:element ref="defaultCache"/>
<xs:element minOccurs="0" maxOccurs="unbounded" ref="cache"/>
</xs:sequence>
<xs:attribute name="name" use="optional"/>
<xs:attribute name="updateCheck" use="optional" type="xs:boolean" default="true"/>
<xs:attribute name="monitoring" use="optional" type="monitoringType"
default="autodetect"/>
</xs:complexType>
</xs:element>
<xs:element name="diskStore">
<xs:complexType>
<xs:attribute name="path" use="optional" />
</xs:complexType>
</xs:element>
<xs:element name="cacheManagerEventListenerFactory">
<xs:complexType>
<xs:attribute name="class" use="required"/>
<xs:attribute name="properties" use="optional"/>
<xs:attribute name="propertySeparator" use="optional"/>
</xs:complexType>
</xs:element>
<xs:element name="cacheManagerPeerProviderFactory">
<xs:complexType>
<xs:attribute name="class" use="required"/>
<xs:attribute name="properties" use="optional"/>
<xs:attribute name="propertySeparator" use="optional"/>
</xs:complexType>
</xs:element>
<xs:element name="cacheManagerPeerListenerFactory">
<xs:complexType>
<xs:attribute name="class" use="required"/>
<xs:attribute name="properties" use="optional"/>
<xs:attribute name="propertySeparator" use="optional"/>
</xs:complexType>
</xs:element>
<xs:element name="terracottaConfig">
<xs:complexType>
<xs:sequence>
<xs:element name="tc-config" minOccurs="0" maxOccurs="1">
<xs:complexType>
<xs:sequence>
<xs:any minOccurs="0" maxOccurs="unbounded" processContents="skip" />
</xs:sequence>
</xs:complexType>
</xs:element>
</xs:sequence>
<xs:attribute name="url" use="optional" default="localhost:9510"/>
<xs:attribute name="registerStatsMBean" type="xs:boolean" use="optional"/>
</xs:complexType>
</xs:element>
<!-- add clone support for addition of cacheExceptionHandler. Important! -->
<xs:element name="defaultCache">
<xs:complexType>
<xs:sequence>
<xs:element minOccurs="0" maxOccurs="unbounded" ref="cacheEventListenerFactory"/>
<xs:element minOccurs="0" maxOccurs="unbounded" ref="cacheExtensionFactory"/>
<xs:element minOccurs="0" maxOccurs="unbounded" ref="cacheLoaderFactory"/>
<xs:element minOccurs="0" maxOccurs="1" ref="bootstrapCacheLoaderFactory"/>
<xs:element minOccurs="0" maxOccurs="1" ref="cacheExceptionHandlerFactory"/>
<xs:element minOccurs="0" maxOccurs="1" ref="terracotta"/>
</xs:sequence>
<xs:attribute name="diskExpiryThreadIntervalSeconds" use="optional" type="xs:integer"/>
<xs:attribute name="diskSpoolBufferSizeMB" use="optional" type="xs:integer"/>
<xs:attribute name="diskPersistent" use="optional" type="xs:boolean"/>
<xs:attribute name="diskAccessStripes" type="xs:integer" use="optional" default="1"/>
<xs:attribute name="eternal" use="required" type="xs:boolean"/>
<xs:attribute name="maxElementsInMemory" use="required" type="xs:integer"/>
<xs:attribute name="clearOnFlush" use="optional" type="xs:boolean"/>
<xs:attribute name="memoryStoreEvictionPolicy" use="optional" type="xs:string"/>
<xs:attribute name="overflowToDisk" use="required" type="xs:boolean"/>
<xs:attribute name="timeToIdleSeconds" use="optional" type="xs:integer"/>
<xs:attribute name="timeToLiveSeconds" use="optional" type="xs:integer"/>
<xs:attribute name="maxElementsOnDisk" use="optional" type="xs:integer"/>
<xs:attribute name="statistics" type="xs:boolean" use="optional" default="true"/>
</xs:complexType>
</xs:element>
<xs:element name="cache">
<xs:complexType>
<xs:sequence >
<xs:element minOccurs="0" maxOccurs="unbounded" ref="cacheEventListenerFactory"/>
<xs:element minOccurs="0" maxOccurs="unbounded" ref="cacheExtensionFactory"/>
<xs:element minOccurs="0" maxOccurs="unbounded" ref="cacheLoaderFactory"/>
<xs:element minOccurs="0" maxOccurs="1" ref="bootstrapCacheLoaderFactory"/>
<xs:element minOccurs="0" maxOccurs="1" ref="cacheExceptionHandlerFactory"/>
<xs:element minOccurs="0" maxOccurs="1" ref="terracotta"/>
</xs:sequence>
<xs:attribute name="diskExpiryThreadIntervalSeconds" use="optional"
type="xs:integer"/>
<xs:attribute name="diskSpoolBufferSizeMB" use="optional" type="xs:integer"/>
<xs:attribute name="diskPersistent" use="optional" type="xs:boolean"/>
<xs:attribute name="diskAccessStripes" type="xs:integer" use="optional" default="1"/>
<xs:attribute name="eternal" use="required" type="xs:boolean"/>
<xs:attribute name="maxElementsInMemory" use="required" type="xs:integer"/>
<xs:attribute name="memoryStoreEvictionPolicy" use="optional" type="xs:string"/>
<xs:attribute name="clearOnFlush" use="optional" type="xs:boolean"/>
<xs:attribute name="name" use="required" type="xs:string"/>
<xs:attribute name="overflowToDisk" use="required" type="xs:boolean"/>
<xs:attribute name="timeToIdleSeconds" use="optional" type="xs:integer"/>
<xs:attribute name="timeToLiveSeconds" use="optional" type="xs:integer"/>
<xs:attribute name="maxElementsOnDisk" use="optional" type="xs:integer"/>
<xs:attribute name="statistics" type="xs:boolean" use="optional" default="true"/>
</xs:complexType>
</xs:element>
<xs:element name="cacheEventListenerFactory">
<xs:complexType>
<xs:attribute name="class" use="required"/>
<xs:attribute name="properties" use="optional"/>
<xs:attribute name="propertySeparator" use="optional"/>
</xs:complexType>
</xs:element>
<xs:element name="bootstrapCacheLoaderFactory">
<xs:complexType>
<xs:attribute name="class" use="required"/>
<xs:attribute name="properties" use="optional"/>
<xs:attribute name="propertySeparator" use="optional"/>
</xs:complexType>
</xs:element>
<xs:element name="cacheExtensionFactory">
<xs:complexType>
<xs:attribute name="class" use="required"/>
<xs:attribute name="properties" use="optional"/>
<xs:attribute name="propertySeparator" use="optional"/>
</xs:complexType>
</xs:element>
<xs:element name="cacheExceptionHandlerFactory">
<xs:complexType>
<xs:attribute name="class" use="required"/>
<xs:attribute name="properties" use="optional"/>
<xs:attribute name="propertySeparator" use="optional"/>
</xs:complexType>
</xs:element>
<xs:element name="cacheLoaderFactory">
<xs:complexType>
<xs:attribute name="class" use="required"/>
<xs:attribute name="properties" use="optional"/>
<xs:attribute name="propertySeparator" use="optional"/>
</xs:complexType>
</xs:element>
<xs:element name="terracotta">
<xs:complexType>
<xs:attribute name="clustered" use="optional" type="xs:boolean" default="true"/>
<xs:attribute name="valueMode" use="optional"
type="terracottaCacheValueType" default="serialization"/>
<xs:attribute name="coherentReads" use="optional" type="xs:boolean" default="true"/>
<xs:attribute name="localKeyCache" use="optional" type="xs:boolean" default="false"/>
<xs:attribute name="localKeyCacheSize" use="optional" type="xs:positiveInteger" default="10000"/>
<xs:attribute name="orphanEviction" use="optional" type="xs:boolean" default="true"/>
<xs:attribute name="orphanEvictionPeriod" use="optional" type="xs:positiveInteger" default="4"/>
</xs:complexType>
</xs:element>
<xs:simpleType name="monitoringType">
<xs:restriction base="xs:string">
<xs:enumeration value="autodetect" />
<xs:enumeration value="on" />
<xs:enumeration value="off" />
</xs:restriction>
</xs:simpleType>
<xs:simpleType name="terracottaCacheValueType">
<xs:restriction base="xs:string">
<xs:enumeration value="serialization" />
<xs:enumeration value="identity" />
</xs:restriction>
</xs:simpleType>
</xs:schema>
If the CacheManager default constructor or factory method is called, Ehcache looks for a file called ehcache.xml in the top level of the classpath. Failing that it looks for ehcache-failsafe.xml in the classpath. ehcache-failsafe.xml is packaged in the Ehcache jar and should always be found.
ehcache-failsafe.xml provides an extremely simple default configuration to enable users to get started before they create their own ehcache.xml.
If it used Ehcache will emit a warning, reminding the user to set up a proper configuration.
The meaning of the elements and attributes are explained in the section on ehcache.xml.
<ehcache>
<diskStore path="java.io.tmpdir"/>
<defaultCache
maxElementsInMemory="10000"
eternal="false"
timeToIdleSeconds="120"
timeToLiveSeconds="120"
overflowToDisk="true"
maxElementsOnDisk="10000000"
diskPersistent="false"
diskExpiryThreadIntervalSeconds="120"
memoryStoreEvictionPolicy="LRU"
/>
</ehcache>Prior to ehcache-1.6, Ehcache only supported ASCII ehcache.xml configuration files. Since ehcache-1.6, UTF8 is supported, so that configuration can use Unicode. As UTF8 is backwardly compatible with ASCII, no conversion is necessary.
If the CacheManager default constructor or factory method is called, Ehcache looks for a file called ehcache.xml in the top level of the classpath.
The non-default creation methods allow a configuration file to be specified which can be called anything.
One XML configuration is required for each CacheManager that is created. It is an error to use the same configuration, because things like directory paths and listener ports will conflict. Ehcache will attempt to resolve conflicts and will emit a warning reminding the user to configure a separate configuration for multiple CacheManagers with conflicting settings.
The sample ehcache.xml, which is included in the Ehcache distribution is reproduced below. The sample contains full commentary required to configure each element. Further information can be found in specific chapters in the Guide.
It can also be downloaded from http://ehcache.org/ehcache.xml.
<?xml version="1.0" encoding="UTF-8"?>
<!--
CacheManager Configuration
==========================
An ehcache.xml corresponds to a single CacheManager.
See instructions below or the ehcache schema (ehcache.xsd) on how to configure.
System property tokens can be specified in this file which are replaced when the
configuration is loaded. For example multicastGroupPort=${multicastGroupPort}
can be replaced with the System property either from an environment variable or
a system property specified with a command line switch such as
-DmulticastGroupPort=4446.
The attributes of <ehcache> are:
* name - an optional name for the CacheManager. The name is optional and primarily used
for documentation or to distinguish Terracotta clustered cache state. With Terracotta
clustered caches, a combination of CacheManager name and cache name uniquely identify a
particular cache store in the Terracotta clustered memory.
* updateCheck - an optional boolean flag specifying whether this CacheManager should check
for new versions of Ehcache over the Internet. If not specified, updateCheck="true".
* dynamicConfig - an optional boolean flag specifying whether this CacheManager should
support dynamic configuration changes to its attached caches.
* monitoring - an optional setting that determines whether the CacheManager should
automatically register the SampledCacheMBean with the system MBean server.
Currently, this monitoring is only useful when using Terracotta clustering and using the
Terracotta Developer Console. With the "autodetect" value, the presence of Terracotta
clustering will be detected and monitoring, via the Developer Console, will be enabled.
Other allowed values are "on" and "off". The default is "autodetect". This setting does
not perform any function when used with JMX monitors.
-->
<ehcache xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:noNamespaceSchemaLocation="ehcache.xsd"
updateCheck="true" monitoring="autodetect">
<!--
DiskStore configuration
=======================
The diskStore element is optional. To turn off disk store path creation, comment out
the diskStore element below.
Configure it if you have overflowToDisk or diskPersistent enabled for any cache.
If it is not configured, and a cache is created which requires a disk store, a warning
will be issued and java.io.tmpdir will automatically be used.
diskStore has only one attribute - "path". It is the path to the directory where
.data and .index files will be created.
If the path is one of the following Java System Property it is replaced by its value
in the running VM. For backward compatibility these should be specified without being
enclosed in the ${token} replacement syntax.
The following properties are translated:
* user.home - User's home directory
* user.dir - User's current working directory
* java.io.tmpdir - Default temp file path
* ehcache.disk.store.dir - A system property you would normally specify on the command
line e.g. java -Dehcache.disk.store.dir=/u01/myapp/diskdir ...
Subdirectories can be specified below the property e.g. java.io.tmpdir/one
-->
<diskStore path="java.io.tmpdir"/>
<!--
CacheManagerEventListener
=========================
Specifies a CacheManagerEventListenerFactory which is notified when Caches are added
or removed from the CacheManager.
The attributes of CacheManagerEventListenerFactory are:
* class - a fully qualified factory class name
* properties - comma separated properties having meaning only to the factory.
Sets the fully qualified class name to be registered as the CacheManager event listener.
The events include:
* adding a Cache
* removing a Cache
Callbacks to listener methods are synchronous and unsynchronized. It is the
responsibility of the implementer to safely handle the potential performance and
thread safety issues depending on what their listener is doing.
If no class is specified, no listener is created. There is no default.
-->
<cacheManagerEventListenerFactory class="" properties=""/>
<!--
CacheManagerPeerProvider
========================
(For distributed operation)
Specifies a CacheManagerPeerProviderFactory which will be used to create a
CacheManagerPeerProvider, which discovers other CacheManagers in the cluster.
One or more providers can be configured. The first one in the ehcache.xml is the
default, which is used for replication and bootstrapping.
The attributes of cacheManagerPeerProviderFactory are:
* class - a fully qualified factory class name
* properties - comma separated properties having meaning only to the factory.
Providers are available for RMI, JGroups and JMS as shown following.
RMICacheManagerPeerProvider
+++++++++++++++++++++++++++
Ehcache comes with a built-in RMI-based distribution system with two means of discovery
of CacheManager peers participating in the cluster:
* automatic, using a multicast group. This one automatically discovers peers and detects
changes such as peers entering and leaving the group
* manual, using manual rmiURL configuration. A hardcoded list of peers is provided at
configuration time.
Configuring Automatic Discovery:
Automatic discovery is configured as per the following example:
<cacheManagerPeerProviderFactory
class="net.sf.ehcache.distribution.RMICacheManagerPeerProviderFactory"
properties="hostName=fully_qualified_hostname_or_ip,
peerDiscovery=automatic, multicastGroupAddress=230.0.0.1,
multicastGroupPort=4446, timeToLive=32"/>
Valid properties are:
* peerDiscovery (mandatory) - specify "automatic"
* multicastGroupAddress (mandatory) - specify a valid multicast group address
* multicastGroupPort (mandatory) - specify a dedicated port for the multicast heartbeat
traffic
* timeToLive - specify a value between 0 and 255 which determines how far the packets
will propagate.
By convention, the restrictions are:
0 - the same host
1 - the same subnet
32 - the same site
64 - the same region
128 - the same continent
255 - unrestricted
* hostName - the hostname or IP of the interface to be used for sending and receiving
multicast packets (relevant to mulithomed hosts only)
Configuring Manual Discovery:
Manual discovery requires a unique configuration per host. It is contains a list of
rmiURLs for the peers, other than itself. So, if we have server1, server2 and server3
the configuration will be:
In server1's configuration:
<cacheManagerPeerProviderFactory class=
"net.sf.ehcache.distribution.RMICacheManagerPeerProviderFactory"
properties="peerDiscovery=manual,
rmiUrls=//server2:40000/sampleCache1|//server3:40000/sampleCache1
| //server2:40000/sampleCache2|//server3:40000/sampleCache2"
propertySeparator="," />
In server2's configuration:
<cacheManagerPeerProviderFactory class=
"net.sf.ehcache.distribution.RMICacheManagerPeerProviderFactory"
properties="peerDiscovery=manual,
rmiUrls=//server1:40000/sampleCache1|//server3:40000/sampleCache1
| //server1:40000/sampleCache2|//server3:40000/sampleCache2"
propertySeparator="," />
In server3's configuration:
<cacheManagerPeerProviderFactory class=
"net.sf.ehcache.distribution.RMICacheManagerPeerProviderFactory"
properties="peerDiscovery=manual,
rmiUrls=//server1:40000/sampleCache1|//server2:40000/sampleCache1
| //server1:40000/sampleCache2|//server2:40000/sampleCache2"
propertySeparator="," />
Valid properties are:
* peerDiscovery (mandatory) - specify "manual"
* rmiUrls (mandatory) - specify a pipe separated list of rmiUrls, in the form
//hostname:port
* hostname (optional) - the hostname is the hostname of the remote CacheManager peer.
The port is the listening port of the RMICacheManagerPeerListener of the remote
CacheManager peer.
JGroupsCacheManagerPeerProvider
+++++++++++++++++++++++++++++++
<cacheManagerPeerProviderFactory
class="net.sf.ehcache.distribution.jgroups.JGroupsCacheManagerPeerProviderFactory"
properties="connect=UDP(mcast_addr=231.12.21.132;mcast_port=45566;ip_ttl=32;
mcast_send_buf_size=150000;mcast_recv_buf_size=80000):
PING(timeout=2000;num_initial_members=6):
MERGE2(min_interval=5000;max_interval=10000):
FD_SOCK:VERIFY_SUSPECT(timeout=1500):
pbcast.NAKACK(gc_lag=10;retransmit_timeout=3000):
UNICAST(timeout=5000):
pbcast.STABLE(desired_avg_gossip=20000):
FRAG:
pbcast.GMS(join_timeout=5000;join_retry_timeout=2000;shun=false;print_local_addr=false)"
propertySeparator="::"
/>
The only property necessary is the connect String used by jgroups to configure itself.
Refer to the JGroups documentation for explanation of all the protocols. The example above
uses UDP multicast. If the connect property is not specified the default JGroups connection
will be used.
JMSCacheManagerPeerProviderFactory
++++++++++++++++++++++++++++++++++
<cacheManagerPeerProviderFactory
class="net.sf.ehcache.distribution.jms.JMSCacheManagerPeerProviderFactory"
properties="..."
propertySeparator=","
/>
The JMS PeerProviderFactory uses JNDI to maintain message queue independence. Refer to the
manual for full configuration examples using ActiveMQ and Open Message Queue.
Valid properties are:
* initialContextFactoryName (mandatory) - the name of the factory used to create the
message queue initial context.
* providerURL (mandatory) - the JNDI configuration information for the service provider
to use.
* topicConnectionFactoryBindingName (mandatory) - the JNDI binding name for the
TopicConnectionFactory
* topicBindingName (mandatory) - the JNDI binding name for the topic name
* getQueueBindingName (mandatory only if using jmsCacheLoader) - the JNDI binding name for
the queue name
* securityPrincipalName - the JNDI java.naming.security.principal
* securityCredentials - the JNDI java.naming.security.credentials
* urlPkgPrefixes - the JNDI java.naming.factory.url.pkgs
* userName - the user name to use when creating the TopicConnection to the Message Queue
* password - the password to use when creating the TopicConnection to the Message Queue
* acknowledgementMode - the JMS Acknowledgement mode for both publisher and subscriber.
The available choices are AUTO_ACKNOWLEDGE, DUPS_OK_ACKNOWLEDGE and SESSION_TRANSACTED.
The default is AUTO_ACKNOWLEDGE.
-->
<cacheManagerPeerProviderFactory
class="net.sf.ehcache.distribution.RMICacheManagerPeerProviderFactory"
properties="peerDiscovery=automatic,
multicastGroupAddress=230.0.0.1,
multicastGroupPort=4446, timeToLive=1"
propertySeparator=","
/>
<!--
CacheManagerPeerListener
========================
(Enable for distributed operation)
Specifies a CacheManagerPeerListenerFactory which will be used to create a
CacheManagerPeerListener, which listens for messages from cache replicators participating
in the cluster.
The attributes of cacheManagerPeerListenerFactory are:
class - a fully qualified factory class name
properties - comma separated properties having meaning only to the factory.
Ehcache comes with a built-in RMI-based distribution system. The listener component is
RMICacheManagerPeerListener which is configured using
RMICacheManagerPeerListenerFactory. It is configured as per the following example:
<cacheManagerPeerListenerFactory
class="net.sf.ehcache.distribution.RMICacheManagerPeerListenerFactory"
properties="hostName=fully_qualified_hostname_or_ip,
port=40001,
remoteObjectPort=40002,
socketTimeoutMillis=120000"
propertySeparator="," />
All properties are optional. They are:
* hostName - the hostName of the host the listener is running on. Specify
where the host is multihomed and you want to control the interface over which cluster
messages are received. Defaults to the host name of the default interface if not
specified.
* port - the port the RMI Registry listener listens on. This defaults to a free port
if not specified.
* remoteObjectPort - the port number on which the remote objects bound in the registry
receive calls. This defaults to a free port if not specified.
* socketTimeoutMillis - the number of ms client sockets will stay open when sending
messages to the listener. This should be long enough for the slowest message.
If not specified it defaults to 120000ms.
-->
<cacheManagerPeerListenerFactory
class="net.sf.ehcache.distribution.RMICacheManagerPeerListenerFactory"/>
<!--
TerracottaConfig
========================
(Enable for Terracotta clustered operation)
Note: You need to install and run one or more Terracotta servers to use Terracotta
clustering. See http://www.terracotta.org/web/display/orgsite/Download.
Specifies a TerracottaConfig which will be used to configure the Terracotta
runtime for this CacheManager.
Configuration can be specified in two main ways: by reference to a source of
configuration or by use of an embedded Terracotta configuration file.
To specify a reference to a source (or sources) of configuration, use the url
attribute. The url attribute must contain a comma-separated list of:
* path to Terracotta configuration file (usually named tc-config.xml)
* URL to Terracotta configuration file
* <server host>:<port> of running Terracotta Server instance
Simplest example for pointing to a Terracotta server on this machine:
<terracottaConfig url="localhost:9510"/>
Example using a path to Terracotta configuration file:
<terracottaConfig url="/app/config/tc-config.xml"/>
Example using a URL to a Terracotta configuration file:
<terracottaConfig url="http://internal/ehcache/app/tc-config.xml"/>
Example using multiple Terracotta server instance URLs (for fault tolerance):
<terracottaConfig url="host1:9510,host2:9510,host3:9510"/>
To embed a Terracotta configuration file within the ehcache configuration, simply
place a normal Terracotta XML config within the <terracottaConfig> element.
Example:
<terracottaConfig>
<tc-config>
<servers>
<server host="server1" name="s1"/>
<server host="server2" name="s2"/>
</servers>
<clients>
<logs>app/logs-%i</logs>
</clients>
</tc-config>
</terracottaConfig>
For more information on the Terracotta configuration, see the Terracotta documentation.
-->
<!--
Cache configuration
===================
The following attributes are required.
name:
Sets the name of the cache. This is used to identify the cache. It must be unique.
maxElementsInMemory:
Sets the maximum number of objects that will be created in memory.
0 indicates no in-memory limit.
maxElementsOnDisk:
Sets the maximum number of objects that will be maintained in the DiskStore
The default value is zero, meaning unlimited.
eternal:
Sets whether elements are eternal. If eternal, timeouts are ignored and the
element is never expired.
overflowToDisk:
Sets whether elements can overflow to disk when the memory store
has reached the maxInMemory limit.
The following attributes and elements are optional.
timeToIdleSeconds:
Sets the time to idle for an element before it expires.
i.e. The maximum amount of time between accesses before an element expires
Is only used if the element is not eternal.
Optional attribute. A value of 0 means that an Element can idle for infinity.
The default value is 0.
timeToLiveSeconds:
Sets the time to live for an element before it expires.
i.e. The maximum time between creation time and when an element expires.
Is only used if the element is not eternal.
Optional attribute. A value of 0 means that and Element can live for infinity.
The default value is 0.
diskPersistent:
Whether the disk store persists between restarts of the Virtual Machine.
The default value is false.
diskExpiryThreadIntervalSeconds:
The number of seconds between runs of the disk expiry thread. The default value
is 120 seconds.
diskSpoolBufferSizeMB:
This is the size to allocate the DiskStore for a spool buffer. Writes are made
to this area and then asynchronously written to disk. The default size is 30MB.
Each spool buffer is used only by its cache. If you get OutOfMemory errors consider
lowering this value. To improve DiskStore performance consider increasing it. Trace level
logging in the DiskStore will show if put back ups are occurring.
diskAccessStripes:
By default one RandomAccessFile object is created to read/write to and from the disk store.
By specifying a larger value here, multiple threads can read/write from the store concurrently
(assuming that the disk controller/driver can correctly optimize the resultant access to the disk).
clearOnFlush:
whether the MemoryStore should be cleared when flush() is called on the cache.
By default, this is true i.e. the MemoryStore is cleared.
memoryStoreEvictionPolicy:
Policy would be enforced upon reaching the maxElementsInMemory limit. Default
policy is Least Recently Used (specified as LRU). Other policies available -
First In First Out (specified as FIFO) and Less Frequently Used
(specified as LFU)
statistics:
Whether the Cache has statistics enabled upon creation. The default is to
enable statistics on cache creation.
Cache elements can also contain sub elements which take the same format of a factory class
and properties. Defined sub-elements are:
* cacheEventListenerFactory - Enables registration of listeners for cache events, such as
put, remove, update, and expire.
* bootstrapCacheLoaderFactory - Specifies a BootstrapCacheLoader, which is called by a
cache on initialisation to prepopulate itself.
* cacheExtensionFactory - Specifies a CacheExtension, a generic mechansim to tie a class
which holds a reference to a cache to the cache lifecycle.
* cacheExceptionHandlerFactory - Specifies a CacheExceptionHandler, which is called when
cache exceptions occur.
* cacheLoaderFactory - Specifies a CacheLoader, which can be used both asynchronously and
synchronously to load objects into a cache. More than one cacheLoaderFactory element
can be added, in which case the loaders form a chain which are executed in order. If a
loader returns null, the next in chain is called.
RMI Cache Replication
+++++++++++++++++++++
Each cache that will be distributed needs to set a cache event listener which replicates
messages to the other CacheManager peers. For the built-in RMI implementation this is done
by adding a cacheEventListenerFactory element of type RMICacheReplicatorFactory to each
distributed cache's configuration as per the following example:
<cacheEventListenerFactory class="net.sf.ehcache.distribution.RMICacheReplicatorFactory"
properties="replicateAsynchronously=true,
replicatePuts=true,
replicatePutsViaCopy=false,
replicateUpdates=true,
replicateUpdatesViaCopy=true,
replicateRemovals=true
asynchronousReplicationIntervalMillis=<number of milliseconds"
propertySeparator="," />
The RMICacheReplicatorFactory recognises the following properties:
* replicatePuts=true|false - whether new elements placed in a cache are
replicated to others. Defaults to true.
* replicatePutsViaCopy=true|false - whether the new elements are
copied to other caches (true), or whether a remove message is sent. Defaults to true.
* replicateUpdates=true|false - whether new elements which override an
element already existing with the same key are replicated. Defaults to true.
* replicateRemovals=true - whether element removals are replicated. Defaults to true.
* replicateAsynchronously=true | false - whether replications are
asynchronous (true) or synchronous (false). Defaults to true.
* replicateUpdatesViaCopy=true | false - whether the new elements are
copied to other caches (true), or whether a remove message is sent. Defaults to true.
* asynchronousReplicationIntervalMillis=<number of milliseconds> - The asynchronous
replicator runs at a set interval of milliseconds. The default is 1000. The minimum
is 10. This property is only applicable if replicateAsynchronously=true
JGroups Replication
+++++++++++++++++++
For the Jgroups replication this is done with:
<cacheEventListenerFactory
class="net.sf.ehcache.distribution.jgroups.JGroupsCacheReplicatorFactory"
properties="replicateAsynchronously=true, replicatePuts=true,
replicateUpdates=true, replicateUpdatesViaCopy=false,
replicateRemovals=true,asynchronousReplicationIntervalMillis=1000"/>
This listener supports the same properties as the RMICacheReplicationFactory.
JMS Replication
+++++++++++++++
For JMS-based replication this is done with:
<cacheEventListenerFactory
class="net.sf.ehcache.distribution.jms.JMSCacheReplicatorFactory"
properties="replicateAsynchronously=true,
replicatePuts=true,
replicateUpdates=true,
replicateUpdatesViaCopy=true,
replicateRemovals=true,
asynchronousReplicationIntervalMillis=1000"
propertySeparator=","/>
This listener supports the same properties as the RMICacheReplicationFactory.
Cluster Bootstrapping
+++++++++++++++++++++
Bootstrapping a cluster may use a different mechanism to replication. e.g you can mix
JMS replication with bootstrap via RMI - just make sure you have the
cacheManagerPeerProviderFactory and cacheManagerPeerListenerFactory configured.
There are two bootstrapping mechanisms: RMI and JGroups.
RMI Bootstrap
The RMIBootstrapCacheLoader bootstraps caches in clusters where RMICacheReplicators are
used. It is configured as per the following example:
<bootstrapCacheLoaderFactory
class="net.sf.ehcache.distribution.RMIBootstrapCacheLoaderFactory"
properties="bootstrapAsynchronously=true, maximumChunkSizeBytes=5000000"
propertySeparator="," />
The RMIBootstrapCacheLoaderFactory recognises the following optional properties:
* bootstrapAsynchronously=true|false - whether the bootstrap happens in the background
after the cache has started. If false, bootstrapping must complete before the cache is
made available. The default value is true.
* maximumChunkSizeBytes=<integer> - Caches can potentially be very large, larger than the
memory limits of the VM. This property allows the bootstraper to fetched elements in
chunks. The default chunk size is 5000000 (5MB).
JGroups Bootstrap
Here is an example of bootstrap configuration using JGroups boostrap:
<bootstrapCacheLoaderFactory
class="net.sf.ehcache.distribution.jgroups.JGroupsBootstrapCacheLoaderFactory"
properties="bootstrapAsynchronously=true"/>
The configuration properties are the same as for RMI above. Note that JGroups bootstrap
only supports asynchronous bootstrap mode.
Cache Exception Handling
By default, most cache operations will propagate a runtime CacheException on failure. An
interceptor, using a dynamic proxy, may be configured so that a CacheExceptionHandler can
be configured to intercept Exceptions. Errors are not intercepted.
It is configured as per the following example:
<cacheExceptionHandlerFactory class="com.example.ExampleExceptionHandlerFactory"
properties="logLevel=FINE"/>
Caches with ExceptionHandling configured are not of type Cache, but are of type Ehcache
only, and are not available using CacheManager.getCache(), but using
CacheManager.getEhcache().
Cache Loader
A default CacheLoader may be set which loads objects into the cache through asynchronous
and synchronous methods on Cache. This is different to the bootstrap cache loader, which
is used only in distributed caching.
It is configured as per the following example:
<cacheLoaderFactory class="com.example.ExampleCacheLoaderFactory"
properties="type=int,startCounter=10"/>
Cache Extension
CacheExtensions are a general purpose mechanism to allow generic extensions to a Cache.
CacheExtensions are tied into the Cache lifecycle.
CacheExtensions are created using the CacheExtensionFactory which has a
<code>createCacheCacheExtension()</code> method which takes as a parameter a
Cache and properties. It can thus call back into any public method on Cache, including, of
course, the load methods.
Extensions are added as per the following example:
<cacheExtensionFactory class="com.example.FileWatchingCacheRefresherExtensionFactory"
properties="refreshIntervalMillis=18000, loaderTimeout=3000,
flushPeriod=whatever, someOtherProperty=someValue ..."/>
Terracotta Clustering
Cache elements can also contain information about whether the cache can be clustered with
Terracotta. The <terracotta> sub-element has the following attributes:
* clustered=true|false - indicates whether this cache should be clustered with Terracotta.
By default, if the <terracotta> element is included, clustered=true.
* valueMode=serialization|identity - indicates whether this cache should be clustered with
serialized copies of the values or using Terracotta identity mode. By default, values
will be cached in serialization mode which is similar to other replicated Ehcache modes.
The identity mode is only available in certain Terracotta deployment scenarios and will
maintain actual object identity of the keys and values across the cluster. In this case,
all users of a value retrieved from the cache are using the same clustered value and must
provide appropriate locking for any changes made to the value (or objects referred to by
the value).
* coherentReads=true|false - indicates whether this cache should have coherent reads with
guaranteed consistency across the cluster. By default, this setting is true. If you set
this property to false, reads are allowed to check the local value without locking,
possibly seeing stale values. This is a performance optimization with weaker concurrency
guarantees and should generally be used with caches that contain read-only data or where
the application can tolerate reading stale data.
* localKeyCache=true|false - indicates whether this cache should use a local key cache on
each client. This caches the translations from the external object keys to the string
keys used internally by the Terracotta clustered store. This option is disabled by
default, and is generally only useful for small read-only caches.
* localKeyCacheSize=integer - indicates the maximum size of the local key cache. When using
a local key cache this should be set to the size of the local key set (either the cache
size or the partition size).
* orphanEviction=true|false - indicates whether orphan eviction is enabled for this cache.
Orphan eviction is the removal of cache elements that are not present in any client, but
are present on the Terracotta server array. This option is enabled by default, and should
only be enabled if you are certain that you have no need for orphan eviction.
* orphanEvictionPeriod=integer - indicates the period of the orphan eviction cycles, measured
in local eviction periods. The default value of 4 indicates that an orphan eviction cycle
will occur after every fourth local eviction cycle.
The simplest example to indicate clustering:
<terracotta/>
To indicate the cache should not be clustered (or remove the <terracotta> element
altogether):
<terracotta clustered="false"/>
To indicate the cache should be clustered using identity mode:
<terracotta clustered="true" valueMode="identity"/>
-->
<!--
Mandatory Default Cache configuration. These settings will be applied to caches
created programmtically using CacheManager.add(String cacheName).
The defaultCache has an implicit name "default" which is a reserved cache name.
-->
<defaultCache
maxElementsInMemory="10000"
eternal="false"
timeToIdleSeconds="120"
timeToLiveSeconds="120"
overflowToDisk="true"
diskSpoolBufferSizeMB="30"
maxElementsOnDisk="10000000"
diskPersistent="false"
diskExpiryThreadIntervalSeconds="120"
memoryStoreEvictionPolicy="LRU"
/>
<!--
Sample caches. Following are some example caches. Remove these before use.
-->
<!--
Sample cache named sampleCache1
This cache contains a maximum in memory of 10000 elements, and will expire
an element if it is idle for more than 5 minutes and lives for more than
10 minutes.
If there are more than 10000 elements it will overflow to the
disk cache, which in this configuration will go to wherever java.io.tmp is
defined on your system. On a standard Linux system this will be /tmp"
-->
<cache name="sampleCache1"
maxElementsInMemory="10000"
maxElementsOnDisk="1000"
eternal="false"
overflowToDisk="true"
diskSpoolBufferSizeMB="20"
timeToIdleSeconds="300"
timeToLiveSeconds="600"
memoryStoreEvictionPolicy="LFU"
/>
<!--
Sample cache named sampleCache2
This cache has a maximum of 1000 elements in memory. There is no overflow to disk, so 1000
is also the maximum cache size. Note that when a cache is eternal, timeToLive and
timeToIdle are not used and do not need to be specified.
-->
<cache name="sampleCache2"
maxElementsInMemory="1000"
eternal="true"
overflowToDisk="false"
memoryStoreEvictionPolicy="FIFO"
/>
<!--
Sample cache named sampleCache3. This cache overflows to disk. The disk store is
persistent between cache and VM restarts. The disk expiry thread interval is set to 10
minutes, overriding the default of 2 minutes.
-->
<cache name="sampleCache3"
maxElementsInMemory="500"
eternal="false"
overflowToDisk="true"
timeToIdleSeconds="300"
timeToLiveSeconds="600"
diskPersistent="true"
diskExpiryThreadIntervalSeconds="1"
memoryStoreEvictionPolicy="LFU"
/>
<!--
Sample distributed cache named sampleDistributedCache1.
This cache replicates using defaults.
It also bootstraps from the cluster, using default properties.
-->
<cache name="sampleDistributedCache1"
maxElementsInMemory="10"
eternal="false"
timeToIdleSeconds="100"
timeToLiveSeconds="100"
overflowToDisk="false">
<cacheEventListenerFactory
class="net.sf.ehcache.distribution.RMICacheReplicatorFactory"/>
<bootstrapCacheLoaderFactory
class="net.sf.ehcache.distribution.RMIBootstrapCacheLoaderFactory"/>
</cache>
<!--
Sample distributed cache named sampleDistributedCache2.
This cache replicates using specific properties.
It only replicates updates and does so synchronously via copy
-->
<cache name="sampleDistributedCache2"
maxElementsInMemory="10"
eternal="false"
timeToIdleSeconds="100"
timeToLiveSeconds="100"
overflowToDisk="false">
<cacheEventListenerFactory
class="net.sf.ehcache.distribution.RMICacheReplicatorFactory"
properties="replicateAsynchronously=false, replicatePuts=false,
replicatePutsViaCopy=false, replicateUpdates=true,
replicateUpdatesViaCopy=true, replicateRemovals=false"/>
</cache>
<!--
Sample distributed cache named sampleDistributedCache3.
This cache replicates using defaults except that the asynchronous replication
interval is set to 200ms.
This one includes / and # which were illegal in ehcache 1.5.
-->
<cache name="sample/DistributedCache3"
maxElementsInMemory="10"
eternal="false"
timeToIdleSeconds="100"
timeToLiveSeconds="100"
overflowToDisk="true">
<cacheEventListenerFactory
class="net.sf.ehcache.distribution.RMICacheReplicatorFactory"
properties="asynchronousReplicationIntervalMillis=200"/>
</cache>
<!--
Sample Terracotta clustered cache named sampleTerracottaCache.
This cache uses Terracotta to cluster the contents of the cache.
-->
<!--
<cache name="sampleTerracottaCache"
maxElementsInMemory="1000"
eternal="false"
timeToIdleSeconds="3600"
timeToLiveSeconds="1800"
overflowToDisk="false">
<terracotta/>
</cache>
-->
</ehcache>
Setting this System Property to true disables caching in ehcache. If disabled no elements will be added to a cache. i.e. puts are silently discarded.
e.g. java -Dnet.sf.ehcache.disabled=true in the Java command line.
Set this System property to true to use the older LruMemoryStore implementation when LRU is selected as the eviction policy.
This is provided for ease of migration.
e.g. java -Dnet.sf.ehcache.use.classic.lru=true in the Java command line. --- Storage Options ---
Ehcache has two stores:
The MemoryStore is always enabled. It is not directly manipulated, but is a component of every cache.
All Elements are suitable for placement in the MemoryStore.
It has the following characteristics:
Thread safe for use by multiple concurrent threads.
Tested for memory leaks. See MemoryCacheTest#testMemoryLeak. This test passes for Ehcache but exploits a number of memory leaks in JCS. JCS will give an OutOfMemory error with a default 64M in 10 seconds.
LinkedHashMap The MemoryStore for JDK1.4 and JDK 5 it is backed by an extended LinkedHashMap. This provides a combined linked list and a hash map, and is ideally suited for caching. Using this standard Java class simplifies the implementation of the memory cache. It directly supports obtaining the least recently used element.
The memory store, being all in memory, is the fastest caching option.
All caches specify their maximum in-memory size, in terms of the number of elements, at configuration time.
When an element is added to a cache and it goes beyond its maximum memory size, an existing element is either deleted, if overflowToDisk is false, or evaluated for spooling to disk, if overflowToDisk is true. In the latter case, a check for expiry is carried out. If it is expired it is deleted; if not it is spooled. The eviction of an item from the memory store is based on the MemoryStoreEvictionPolicy setting specified in the configuration file.
memoryStoreEvictionPolicy is an optional attribute in ehcache.xml introduced since 1.2. Legal values are LRU (default), LFU and FIFO.
LRU, LFU and FIFO eviction policies are supported. LRU is the default, consistent with all earlier releases of ehcache.
The eldest element, is the Least Recently Used (LRU). The last used timestamp is updated when an element is put into the cache or an element is retrieved from the cache with a get call.
For each get call on the element the number of hits is updated. When a put call is made for a new element (and assuming that the max limit is reached for the memory store) the element with least number of hits, the Less Frequently Used element, is evicted.
Elements are evicted in the same order as they come in. When a put call is made for a new element (and assuming that the max limit is reached for the memory store) the element that was placed first (First-In) in the store is the candidate for eviction (First-Out).
For all the eviction policies there are also putQuiet and getQuiet methods which do not update the last used timestamp.
When there is a get or a getQuiet on an element, it is checked for expiry. If expired, it is removed and null is returned.
Note that at any point in time there will usually be some expired elements in the cache. Memory sizing of an application must always take into account the maximum size of each cache. There is a convenience method which can provide an estimate of the size in bytes of the MemoryStore. See calculateInMemorySize(). It returns the serialized size of the cache. Do not use this method in production. It is very slow. It is only meant to provide a rough estimate.
The alternative would have been to have an expiry thread. This is a trade-off between lower memory use and short locking periods and cpu utilisation. The design is in favour of the latter. For those concerned with memory use, simply reduce the maxElementsInMemory.
The DiskStore provides a disk spooling facility.
The diskStore element in ehcache.xml is now optional (as of 1.5). If all caches use only MemoryStores, then there is no need to configure a diskStore. This simplifies configuration, and uses less threads. It is also good where where multiple CacheManagers are being used, and multiple disk store paths would need to be configured.
If one or more caches requires a DiskStore, and none is configured, java.io.tmpdir will be used and a warning message will be logged to encourage explicity configuration of the diskStore path.
To turn off disk store path creation, comment out the diskStore element in ehcache.xml.
The ehcache-failsafe.xml configuration uses a disk store. This will remain the case so as to not affect existing Ehcache deployments. So, if you do not wish to use a disk store make sure you specify your own ehcache.xml and comment out the diskStore element.
Only Elements which are Serializable can be placed in the DiskStore. Any non serializable Elements which attempt to overflow to the DiskStore will be removed instead, and a WARNING level log message emitted.
The disk store creates a data file for each cache on startup called "cache_name.data", and, if the DiskStore is configured to be persistent, an index file called "cache name.index" on flushing of the DiskStore either explicitly using Cache.flush or on CacheManager shutdown.
Files are created in the directory specified by the diskStore configuration element. The diskStore configuration for the ehcache-failsafe.xml and bundled sample configuration file ehcache.xml is "java.io.tmpdir", which causes files to be created in the system's temporary directory.
The diskStore element is has one attribute called path. --- diskStore path="java.io.tmpdir"/ --- Legal values for the path attibute are legal file system paths. e.g.for Unix
/home/application/cache
The following system properties are also legal, in which case they are translated:
Subdirectories can be specified below the system property e.g.
java.io.tmpdir/one
becomes, on a Unix system,
/tmp/oneOne thread per cache is used to remove expired elements. The optional attribute diskExpiryThreadIntervalSeconds sets the interval between runs of the expiry thread. Warning: setting this to a low value is not recommended. It can cause excessive DiskStore locking and high cpu utilisation. The default value is 120 seconds.
If the maxElementsOnDisk attribute is set, elements will be evicted from the DiskStore when it exceeds that amount. The LFU algorithm is used for these evictions. It is not configurable to use another algorithm.
Only Serializable objects can be stored in a DiskStore. A NotSerializableException will be thrown if the object is not serializable.
DiskStores are thread safe.
DiskStore persistence is controlled by the diskPersistent configuration element. If false or omitted, DiskStores will not persist between CacheManager restarts. The data file for each cache will be deleted, if it exists, both on shutdown and startup. No data from a previous instance CacheManager is available.
If diskPersistent is true, the data file, and an index file, are saved. Cache Elements are available to a new CacheManager. This CacheManager may be in the same VM instance, or a new one.
The data file is updated continuously during operation of the Disk Store if overflowToDisk is true. Otherwise it is not updated until either cache.flush() is called or the cache is disposed.
In all cases the index file is only written when dispose is called on the DiskStore. This happens when the CacheManager is shut down, a Cache is disposed, or the VM is being shut down. It is recommended that the CacheManager shutdown() method be used. See Virtual Machine Shutdown Considerations for guidance on how to safely shut the Virtual Machine down.
When a DiskStore is persisted, the following steps take place:
On startup the following steps take place:
These actions favour safety over persistence. Ehcache is a cache, not a database. If a file gets dirty, all data is deleted. Once started there is further checking for corruption. When a get is done, if the Element cannot be successfully derserialized, it is deleted, and null is returned. These measures prevent corrupt and inconsistent data being returned.
Expiring an element frees its space on the file. This space is available for reuse by new elements. The element is also removed from the in-memory index of elements.
Spool requests are placed in-memory and then asynchronously written to disk. There is one thread per cache. An in-memory index of elements on disk is maintained to quickly resolve whether a key exists on disk, and if so to seek it and read it.
Writes to and from the disk use ObjectInputStream and the Java serialization mechanism. This is not required for the MemoryStore. As a result the DiskStore can never be as fast as the MemoryStore.
Serialization speed is affected by the size of the objects being serialized and their type. It has been found in the ElementTest test that:
Byte arrays are 20 times faster to serialize. Make use of byte arrays to increase DiskStore performance.
One option to speed up disk stores is to use a RAM file system. On some operating systems there are a plethora of file systems to choose from. For example, the Disk Cache has been successfully used with Linux' RAMFS file system. This file system simply consists of memory. Linux presents it as a file system. The Disk Cache treats it like a normal disk - it is just way faster. With this type of file system, object serialization becomes the limiting factor to performance.
In this configuration case, the disk will be written on flush or shutdown.
The next time the cache is started, the disk store will initialise but will not permit overflow from the MemoryStore. In all other respects it acts like a normal disk store.
In practice this means that persistent in-memory cache will start up with all of its elements on disk. As gets cause cache hits, they will be loaded up into the MemoryStore. The oher thing that may happen is that the elements will expire, in which case the DiskStore expiry thread will reap them, (or they will get removed on a get if they are expired).
So, the Ehcache design does not load them all into memory on start up, but lazily loads them as required.
--- Cache Eviction Algorithms ---
A cache eviction algorithm is a way of deciding which Element to evict when the cache is full.
In Ehcache the MemoryStore has a fixed limited size set by maxElementsInMemory (unless the maxElementsInMemory is 0, in which case the capacity is unlimited). When the store gets full, elements are evicted. The eviction algorithms in Ehcache determines which elements is evicted. The default is LRU.
What happens on eviction depends on the cache configuration. If a DiskStore is configured, the evicted element will overflow to disk, otherwise it will be removed.
The DiskStore size by default is unbounded. But a maximum size can be set using the maxElementsOnDisk cache attribute. If the DiskStore is full, then adding an element will cause one to be evicted. The DiskStore eviction algorithm is not configurable. It uses LFU.
The idea here is, given a limit on the number of items to cache, how to choose the thing to evict that gives the best result.
In 1966 Laszlo Belady showed that the most efficient caching algorithm would be to always discard the information that will not be needed for the longest time in the future. This it a theoretical result that is unimplementable without domain knowledge. The Least Recently Used ("LRU") algorithm is often used as a proxy. It works pretty well because of the locality of reference phenonemon. As a result, LRU is the default eviction algorithm in Ehcache, as it is in most caches.
Ehcache users may sometimes have a good domain knowledge. Accordingly, Ehcache provides three eviction algorithms to choose from for the MemoryStore.
The MemoryStore supports three eviction algorithms: LRU, LFU and FIFO.
The default is LRU.
The eldest element, is the Least Recently Used (LRU). The last used timestamp is updated when an element is put into the cache or an element is retrieved from the cache with a get call.
For each get call on the element the number of hits is updated. When a put call is made for a new element (and assuming that the max limit is reached) the element with least number of hits, the Less Frequently Used element, is evicted.
If cache element use follows a pareto distribution, this algorithm may give better results than LRU.
LFU is an algorithm unique to Ehcache. It takes a random sample of the Elements and evicts the smallest. Using the sample size of 30 elements, empirical testing shows that an Element in the lowest quartile of use is evicted 99.99% of the time.
Elements are evicted in the same order as they come in. When a put call is made for a new element (and assuming that the max limit is reached for the memory store) the element that was placed first (First-In) in the store is the candidate for eviction (First-Out).
This algorithm is used if the use of an element makes it less likely to be used in the future. An example here would be an authentication cache.
The DiskStore uses the Less Frequently Used algorithm to evict an element when it is full.
--- Code Samples ---
This page shows some of the more common code samples to get you started. Code samples for each feature are in the relevant chapters.
All usages of Ehcache start with the creation of a CacheManager.
As of ehcache-1.2, Ehcache CacheManagers can be created as either singletons (use the create factory method) or instances (use new).
Create a singleton CacheManager using defaults, then list caches.
CacheManager.create(); String[] cacheNames = CacheManager.getInstance().getCacheNames();
Create a CacheManager instance using defaults, then list caches.
CacheManager manager = new CacheManager(); String[] cacheNames = manager.getCacheNames();
Create two CacheManagers, each with a different configuration, and list the caches in each.
CacheManager manager1 = new CacheManager("src/config/ehcache1.xml");
CacheManager manager2 = new CacheManager("src/config/ehcache2.xml");
String[] cacheNamesForManager1 = manager1.getCacheNames();
String[] cacheNamesForManager2 = manager2.getCacheNames();When the CacheManager is created it creates caches found in the configuration.
Create a CacheManager using defaults. Ehcache will look for ehcache.xml in the classpath.
CacheManager manager = new CacheManager();
Create a CacheManager specifying the path of a configuration file.
CacheManager manager = new CacheManager("src/config/ehcache.xml");Create a CacheManager from a configuration resource in the classpath.
URL url = getClass().getResource("/anotherconfigurationname.xml");
CacheManager manager = new CacheManager(url);Create a CacheManager from a configuration in an InputStream.
InputStream fis = new FileInputStream(new File("src/config/ehcache.xml").getAbsolutePath());
try {
CacheManager manager = new CacheManager(fis);
} finally {
fis.close();
}You are not just stuck with the caches that were placed in the configuration. You can create and remove them programmatically.
Add a cache using defaults, then use it. The following example creates a cache called testCache, which will be configured using defaultCache from the configuration.
CacheManager singletonManager = CacheManager.create();
singletonManager.addCache("testCache");
Cache test = singletonManager.getCache("testCache");Create a Cache and add it to the CacheManager, then use it. Note that Caches are not usable until they have been added to a CacheManager.
CacheManager singletonManager = CacheManager.create();
Cache memoryOnlyCache = new Cache("testCache", 5000, false, false, 5, 2);
manager.addCache(memoryOnlyCache);
Cache test = singletonManager.getCache("testCache");See the cache constructor for the full parameters for a new Cache:
Remove cache called sampleCache1
CacheManager singletonManager = CacheManager.create();
singletonManager.removeCache("sampleCache1");Ehcache should be shutdown after use. It does have a shutdown hook, but it is best practice to shut it down in your code.
Shutdown the singleton CacheManager
CacheManager.getInstance().shutdown();
Shutdown a CacheManager instance, assuming you have a reference to the CacheManager called manager
manager.shutdown();
See the CacheManagerTest for more examples.
A new cache with a given name can be created from defaults very simply:
manager.addCache(cache name);
The configuration for a Cache can be specified programmatically as an argument to the Cache constructor:
public Cache(CacheConfiguration cacheConfiguration) {
...
}Here is an example which creates a cache called test.
//Create a CacheManager using defaults
CacheManager manager = CacheManager.create();
//Create a Cache specifying its configuration.
Cache testCache = new Cache(
new CacheConfiguration("test", maxElements)
.memoryStoreEvictionPolicy(MemoryStoreEvictionPolicy.LFU)
.overflowToDisk(true)
.eternal(false)
.timeToLiveSeconds(60)
.timeToIdleSeconds(30)
.diskPersistent(false)
.diskExpiryThreadIntervalSeconds(0));
manager.addCache(cache);Once the cache is created, add it to the list of caches managed by the CacheManager:
manager.addCache(testCache);
The cache is not usable until it has been added.
All of these examples refer to manager, which is a reference to a CacheManager, which has a cache in it called sampleCache1.
Obtain a Cache called "sampleCache1", which has been preconfigured in the configuration file
Cache cache = manager.getCache("sampleCache1");Put an element into a cache
Cache cache = manager.getCache("sampleCache1");
Element element = new Element("key1", "value1");
cache.put(element);Update an element in a cache. Even though cache.put() is used, Ehcache knows there is an existing element, and considers the put an update for the purpose of notifying cache listeners.
Cache cache = manager.getCache("sampleCache1");
cache.put(new Element("key1", "value1"));
//This updates the entry for "key1"
cache.put(new Element("key1", "value2"));Get a Serializable value from an element in a cache with a key of "key1".
Cache cache = manager.getCache("sampleCache1");
Element element = cache.get("key1");
Serializable value = element.getValue();Get a NonSerializable value from an element in a cache with a key of "key1".
Cache cache = manager.getCache("sampleCache1");
Element element = cache.get("key1");
Object value = element.getObjectValue();Remove an element from a cache with a key of "key1".
Cache cache = manager.getCache("sampleCache1");
cache.remove("key1");sampleCache1 has a persistent diskStore. We wish to ensure that the data and index are written immediately.
Cache cache = manager.getCache("sampleCache1");
cache.flush();Get the number of elements currently in the Cache.
Cache cache = manager.getCache("sampleCache1");
int elementsInMemory = cache.getSize();Get the number of elements currently in the MemoryStore.
Cache cache = manager.getCache("sampleCache1");
long elementsInMemory = cache.getMemoryStoreSize();Get the number of elements currently in the DiskStore.
Cache cache = manager.getCache("sampleCache1");
long elementsInMemory = cache.getDiskStoreSize();These methods are useful for tuning cache configurations.
Get the number of times requested items were found in the cache. i.e. cache hits
Cache cache = manager.getCache("sampleCache1");
int hits = cache.getHitCount();Get the number of times requested items were found in the MemoryStore of the cache.
Cache cache = manager.getCache("sampleCache1");
int hits = cache.getMemoryStoreHitCount();Get the number of times requested items were found in the DiskStore of the cache.
Cache cache = manager.getCache("sampleCache1");
int hits = cache.getDiskStoreCount();Get the number of times requested items were not found in the cache. i.e. cache misses.
Cache cache = manager.getCache("sampleCache1");
int hits = cache.getMissCountNotFound();Get the number of times requested items were not found in the cache due to expiry of the elements.
Cache cache = manager.getCache("sampleCache1");
int hits = cache.getMissCountExpired();These are just the most commonly used methods. See CacheTest for more examples. See Cache for the full API.
A cache will automatically participate in the ongoing UserTransaction when configured in transactionalMode XA. This can be done programmatically:
//Create a CacheManager using defaults
CacheManager manager = CacheManager.create();
//Create a Cache specifying its configuration.
Cache xaCache = new Cache(
new CacheConfiguration("test", 1000)
.overflowToDisk(true)
.eternal(false)
.transactionalMode(CacheConfiguration.TransactionalMode.XA)
.terracotta(new TerracottaConfiguration().clustered(true)));
manager.addCache(xaCache);Or in your CacheManager's configuration file :
<cache name="xaCache"
maxElementsInMemory="500"
eternal="false"
timeToIdleSeconds="300"
timeToLiveSeconds="600"
overflowToDisk="false"
diskPersistent="false"
diskExpiryThreadIntervalSeconds="1"
transactionalMode="xa">
<terracotta clustered="true"/>
</cache>Please note that XA Transactional caches are currently only supported when clustered with Terracotta.
The Cache can then be used without any special requirement. Changes will only become visible to others, once the transaction has been committed.
Ehcache cache = cacheManager.getEhcache("xaCache");
transactionManager.begin();
try {
Element e = cache.get(key);
Object result = complexeService.doStuff(element.getValue());
// This put will be rolled back should complexeService.doMoreStuff throw an Exception
cache.put(new Element(key, result));
// Any changes to result in that call, will be visible to others when the Transaction commits
complexeService.doMoreStuff(result);
transactionManager.commit();
} catch (Exception e) {
transactionManager.rollback();
}This example shows how to dynamically modify the cache configuration of an already running cache:
Cache cache = manager.getCache("sampleCache");
CacheConfiguration config = cache.getCacheConfiguration();
config.setTimeToIdleSeconds(60);
config.setTimeToLiveSeconds(120);
config.setMaxElementsInMemory(10000);
config.setMaxElementsOnDisk(1000000);Dynamic cache configurations can also be frozen to prevent future changes:
Cache cache = manager.getCache("sampleCache");
cache.disableDynamicFeatures();This example shows how to register CacheStatistics in the JDK1.5 platform MBeanServer, which works with the JConsole management agent.
CacheManager manager = new CacheManager();
MBeanServer mBeanServer = ManagementFactory.getPlatformMBeanServer();
ManagementService.registerMBeans(manager, mBeanServer, false, false, false, true);Ehcache comes with a comprehensive JUnit test suite, which not only tests the code, but shows you how to use ehcache.
A link to browsable unit test source code for the major Ehcache classes is given per section. The unit tests are also in the src.zip in the Ehcache tarball.
See the examples in the JCache Chapter.
See the fully worked examples in the Terracotta Clustering Chapter.
See the examples in the Cache Server Chapter. --- Java Requirements and Dependencies ---
Current Ehcache releases require Java 1.5 and 1.6 at runtime.
Ehcache 1.5 requires Java 1.4.
The Ehcache DX product which provides management and monitoring will work with Ehcache 1.2.3 but only for Java 1.5 or higher.
Ehcache core 1.6 through to 1.7.0 has no dependencies.
Ehcache core 1.7.1 depends on SLF4J (http://www.slf4j.org), an increasingly commonly used logging framework which provides a choice of concrete logging implementation. See the chapter on Logging for configuration details.
Other modules have dependencies as specified in their maven poms.
--- Logging ---
As of 1.7.1, Ehcache uses the the slf4j (http://www.slf4j.org) logging facade. Plug in your own logging framework.
With slf4j, users must choose a concrete logging implementation at deploy time.
The maven dependency declarations are reproduced here for convenience. Add one of these to your Maven pom.
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-jdk14</artifactId>
<version>1.5.8</version>
</dependency>
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-log4j12</artifactId>
<version>1.5.8</version>
</dependency>
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-simple</artifactId>
<version>1.5.8</version>
</dependency>We provide the slf4j-api and slf4j-jdk14 jars in the kit along with the ehcache jars so that, if the app does not already use SLF4J, you have everything you need.
Additional concrete logging implementations can be downloaded from http://www.slf4j.org.
Ehcache seeks to trade off informing production support developers or important messages and cluttering the log.
ERROR ERROR messages should not occur in normal production and indicate that action should be taken.
WARN WARN messages generally indicate a configuration change should be made or an unusual event has occurred.
DEBUG DEBUG and TRACE messages are for development use. All DEBUG level statements are surrounded with a guard so that no performance cost is incurred unless the logging level is set.
Setting the logging level to DEBUG should provide more information on the source of any problems. Many logging systems enable a logging level change to be made without restarting the application.
--- Remote Network debugging and monitoring for Distributed Caches ---
The ehcache-1.x-remote-debugger.jar} can be used to debug replicated cache operations. When started with the same configuration as the cluster, it will join the cluster and then report cluster events for the cache of interest. By providing a window into the cluster it can help to identify the cause of cluster problems.
From version 1.5 it is packaged in its own distribution tarball along with a maven module.
It is provided as an executable jar.
This version of the debugger has been tested only with the default RMI based replication.
It is invoked as follows:
java -classpath [add your application jars here]
-jar ehcache-debugger-1.5.0.jar ehcache.xml sampleCache1
path_to_ehcache.xml [cacheToMonitor]
Note: Add to the classpath any libraries your project uses in addition to these above, otherwise RMI will attempt to load them remotely which requires specific security policy settings that surprise most people.
It takes one or two arguments:
If only the first argument is passed, it will print our a list of caches with replication configured from the configuration file, which are then available for monitoring.
If the second argument is also provided, the debugger will monitor cache operations received for the given cache.
This is done by registering a CacheEventListener which prints out each operation.
When monitoring a cache it prints a list of caches with replication configured, prints notifications as they happen, and periodically prints the cache name, size and total events received. See sample output below which is produced when the RemoteDebuggerTest is run.
Caches with replication configured which are available for monitoring are: sampleCache19 sampleCache20 sampleCache26 sampleCache42 sampleCache33 sampleCache51 sampleCache40 sampleCache32 sampleCache18 sampleCache25 sampleCache9 sampleCache15 sampleCache56 sampleCache31 sampleCache7 sampleCache12 sampleCache17 sampleCache45 sampleCache41 sampleCache30 sampleCache13 sampleCache46 sampleCache4 sampleCache36 sampleCache29 sampleCache50 sampleCache37 sampleCache49 sampleCache48 sampleCache38 sampleCache6 sampleCache2 sampleCache55 sampleCache16 sampleCache27 sampleCache11 sampleCache3 sampleCache54 sampleCache28 sampleCache10 sampleCache8 sampleCache47 sampleCache5 sampleCache53 sampleCache39 sampleCache23 sampleCache34 sampleCache22 sampleCache44 sampleCache52 sampleCache24 sampleCache35 sampleCache21 sampleCache43 sampleCache1 Monitoring cache: sampleCache1 Cache: sampleCache1 Notifications received: 0 Elements in cache: 0 Received put notification for element [ key = this is an id, value=this is a value, version=1, hitCount=0, CreationTime = 1210656023456, LastAccessTime = 0 ] Received update notification for element [ key = this is an id, value=this is a value, version=1210656025351, hitCount=0, CreationTime = 1210656024458, LastAccessTime = 0 ] Cache: sampleCache1 Notifications received: 2 Elements in cache: 1 Received remove notification for element this is an id Received removeAll notification.
If you see nothing happening, but cache operations should be going through, enable trace (LOG4J) or finest (JDK) level logging on codenet.sf.ehcache.distribution/code in the logging configuration being used by the debugger. A large volume of log messages will appear. The normal problem is that the CacheManager has not joined the cluster. Look for the list of cache peers.
Check the FAQ where a lot of commonly reported errors and their solutions are provided. Beyond that, post to the forums or mailing list or contact Ehcache for support.
--- Tuning Garbage Collection ---
Applications which use Ehcache can be expected to have larger heaps. Some Ehcache applications have heap sizes greater than 6GB.
Ehcache works well at this scale. However large heaps or long held object, which is what a cache is, can place strain on the default Garbage Collector.
Note. The following documentation relates to Sun JDK 1.5.
A full garbage collection event pauses all threads in the JVM. Nothing happens during the pause. If this pause takes more than a few seconds it will become noticeable.
The clearest way to see if this is happening is to run jstat. The following command will produce a log of garbage collection statistics, updated each ten seconds.
jstat -gcutil <pid> 10 1000000
The thing to watch for is the Full Garbage Collection Time. The difference between the total time for each reading is the time the system spends time paused. If there is a jump more than a few seconds this will not be acceptable in most application contexts.
The Sun core garbage collection team has offered the following tuning suggestion for virtual machines with large heaps using caching:
java ... -XX:+DisableExplicitGC -XX:+UseConcMarkSweepGC
-XX:NewSize=<1/4 of total heap size> -XX:SurvivorRatio=16The reasoning for each setting is as follows:
Some users have reported that enabling distributed caching causes a full GC each minute. This is an issue with RMI generally, which can be worked around by increasing the interval for garbage collection. The effect that RMI is having is similar to a user application calling System.gc() each minute. In the settings above this is disabled, but it does not disable the full GC initiated by RMI.
The default in JDK6 was increased to 1 hour. The following system properties control the interval.
-Dsun.rmi.dgc.client.gcInterval=60000 -Dsun.rmi.dgc.server.gcInterval=60000
See http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=4403367 for the bug report and detailed instructions on workarounds.
Increase the interval as required in your application.
--- JMX Management and Monitoring ---
An extensive new monitoring product, available in Ehcache DX, provides a monitoring server with probes supporting Ehcache-1.2.3 and higher for standalone and clustered Ehcache. It comes with a web console and a RESTful API for operations integration.
See the Ehcache DX documentation for more information.
When using Ehcache 1.7 with Terracotta clustering, the Terracotta Developer Console shows statistics for ehcache.
JMX, part of JDK1.5, and available as a download for 1.4, creates a standard way of instrumenting classes and making them available to a management and monitoring infrastructure.
The net.sf.ehcache.management package contains MBeans and a ManagementService for JMX management of ehcache. It is in a separate package so that JMX libraries are only required if you wish to use it - there is no leakage of JMX dependencies into the core Ehcache package.
This implementation attempts to follow Sun's JMX best practices. See http://java.sun.com/javase/technologies/core/mntr-mgmt/ javamanagement/best-practices.jsp.
Use net.sf.ehcache.management.ManagementService.registerMBeans(...) static method to register a selection of MBeans to the MBeanServer provided to the method.
If you wish to monitor Ehcache but not use JMX, just use the existing public methods on Cache and CacheStatistics.

The Management Package
Ehcache uses Standard MBeans. MBeans are available for the following:
All MBean attributes are available to a local MBeanServer. The CacheManager MBean allows traversal to its collection of Cache MBeans. Each Cache MBean likewise allows traversal to its CacheConfiguration MBean and its CacheStatistics MBean.
The JMX Remote API allows connection from a remote JMX Agent to an MBeanServer via an MBeanServerConnection.
Only Serializable attributes are available remotely. The following Ehcache MBean attributes are available remotely:
Most attributes use built-in types. To access all attributes, you need to add ehcache.jar to the remote JMX client's classpath e.g. jconsole -J-Djava.class.path=ehcache.jar.
The ManagementService class is the API entry point.

ManagementService
There is only one method, ManagementService.registerMBeans which is used to initiate JMX registration of an Ehcache CacheManager's instrumented MBeans.
The ManagementService is a CacheManagerEventListener and is therefore notified of any new Caches added or disposed and updates the MBeanServer appropriately.
Once initiated the MBeans remain registered in the MBeanServer until the CacheManager shuts down, at which time the MBeans are deregistered. This behaviour ensures correct behaviour in application servers where applications are deployed and undeployed.
/**
* This method causes the selected monitoring options to be be registered
* with the provided MBeanServer for caches in the given CacheManager.
* <p/>
* While registering the CacheManager enables traversal to all of the other
* items,
* this requires programmatic traversal. The other options allow entry points closer
* to an item of interest and are more accessible from JMX management tools like JConsole.
* Moreover CacheManager and Cache are not serializable, so remote monitoring is not
* possible * for CacheManager or Cache, while CacheStatistics and CacheConfiguration are.
* Finally * CacheManager and Cache enable management operations to be performed.
* <p/>
* Once monitoring is enabled caches will automatically added and removed from the
* MBeanServer * as they are added and disposed of from the CacheManager. When the
* CacheManager itself * shutsdown all registered MBeans will be unregistered.
*
* @param cacheManager the CacheManager to listen to
* @param mBeanServer the MBeanServer to register MBeans to
* @param registerCacheManager Whether to register the CacheManager MBean
* @param registerCaches Whether to register the Cache MBeans
* @param registerCacheConfigurations Whether to register the CacheConfiguration MBeans
* @param registerCacheStatistics Whether to register the CacheStatistics MBeans
*/
public static void registerMBeans(
net.sf.ehcache.CacheManager cacheManager,
MBeanServer mBeanServer,
boolean registerCacheManager,
boolean registerCaches,
boolean registerCacheConfigurations,
boolean registerCacheStatistics) throws CacheException {This example shows how to register CacheStatistics in the JDK1.5 platform MBeanServer, which works with the JConsole management agent.
CacheManager manager = new CacheManager();
MBeanServer mBeanServer = ManagementFactory.getPlatformMBeanServer();
ManagementService.registerMBeans(manager, mBeanServer, false, false, false, true);CacheStatistics MBeans are then registered.

CacheStatistics MBeans in JConsole
If you are running Terracotta clustered caches as hibernate second-level cache provider, it is possible to access the hibernate statistics + ehcache stats etc via jmx.
EhcacheHibernateMBean is the main interface that exposes all the API's via jmx. It basically extends two interfaces -- EhcacheStats and HibernateStats. And as the name implies EhcacheStats contains methods related with Ehcache and HibernateStats related with Hibernate.
You can see cache hit/miss/put rates, change config element values dynamically -- like maxElementInMemory, TTI, TTL, enable/disable statistics collection etc and various other things. Please look into the specific interface for more details.
See http://weblogs.java.net/blog/maxpoon/archive/2007/06/extending_the_n_2.html for an online tutorial.
--- JTA ---
JTA is supported in versions of Ehcache 2.0 and
higher.
Ehcache acts as an XAResouce and participates in JTA ("Java Transaction API") transactions.
Ehcache automatically detects and uses the following transaction managers in the following order:
No configuration is required; they work out of the box.
The first found is used.
If you Transaction Manager is not in the above list or you wish to change the priority you need to configure your own lookup class and specify it in place of the DefaultTransactionManagerLookup in the ehcache.xml config::
<transactionManagerLookup class= "net.sf.ehcache.transaction.manager.DefaultTransactionManagerLookup" properties="" propertySeparator=":"/>
You can also provide a different location for the JNDI lookup by providing the jndiName property to the DefaultTransactionManagerLookup.
The example below provides the proper location for the TransactionManager in GlassFish v3:
<transactionManagerLookup class="net.sf.ehcache.transaction.manager.DefaultTransactionManagerLookup" properties="jndiName=java:appserver/TransactionManager" propertySeparator=";"/>
JTA is enabled on a cache by cache basis with the transactionalMode cache attribute
The allowed values are xa and off. By default it is off.
Enabling a cache for JTA is shown in the following example:
<cache name="xaCache"
maxElementsInMemory="500"
eternal="false"
timeToIdleSeconds="300"
timeToLiveSeconds="600"
overflowToDisk="false"
diskPersistent="false"
diskExpiryThreadIntervalSeconds="1"
transactionalMode="xa">
<terracotta clustered="true"/>
</cache>Note that in Ehcache 2.0 JTA requires Terracotta serialization value mode otherwise a a CacheException will be thrown on start up. We plan to support standalone Ehcache in the next release.
If a cache is enabled for JTA all operations on it must happen within a transaction context, otherwise a TransactionRequiredException will be thrown.
The isolation level offered in Ehcache JTA is READ_COMMITTED. Ehcache is an XAResource. Full two-phase commit is supported.
Specifically:
If your XA enabled cache is being used with a writer, write operations will be queued until transaction commit time. Solely a Write-through approach would have its potential XAResource participate in the same transaction. Write-behind, while supported, should probably not be used with an XA transactional Cache, as the operations would never be part of the same transaction. Your writer would also be responsible for obtaining a new transaction...
Using Write-through with a non XA resource would also work, but there is no guarantee the transaction will succeed after the write operation have been executed successfully. On the other hand, any thrown exception during these write operations would cause the transaction to be rolled back by having UserTransaction.commit() throw a RollbackException.
Transactional support is implemented at the Store level, through XaTransactionalStore. The store actually decorates the underlying MemoryStore implementation, augmenting it with transaction isolation and two-phase commit support.
During it's initialization, the Cache will lookup the TransactionManager using the provided TransactionManagerLookup implementation. Using the TransactionManagerLookup.register(XAResouce): void callback, the newly created XAResource is potentially registered with the TransactionManager.
That same TransactionManager will from there on be used by the Cache to access the current transaction on all transactional method calls.
The store is automatically configured to copy every Element read from the cache or written to it. Cache is copy-on-read and copy-on-write.
Every read from the Cache, or remove() without a previous get(), will have the transactional track versioning information for these cache values. This version information will be checked against at commit time, to make sure we're still mutating the same information.
Write operation to the cache (puts and removes) are not effectively executed against the underlying memory store. Rather a local transaction context is being altered. It queues all commands to be executed against the Store at commit time. This context also alters the behavior of cache accesses: e.g. within the same transaction a put and then a getSize call will reflect that previous put, while other transaction would not be impacted. This gives read_commited isolation.
During the two phase commit, the context is first prepared: where all keys to be altered are checked for consistency against the optimistic locking mechanism. If a key to be updated or removed has since been changed by a commited transaction, the transaction will be rolled back. For each key a write lock is acquired, version checked and the old value is copied to a temporary "guarding" store. That store is always queried before the real underlying memory store is. That way, while write locked, old values that are about to be updated can still be read, non blocking, from the "oldVersionStore". If all keys could be validated and write locked the prepare operation as finished successfully and Ehcache votes OK on commit.
If all other XAResource eventually vote OK, the transaction is committed: the old value(s) are removed and write-locks are released. If not, the old values are copied back to the store and the lock released.
As specified by the JTA specification, only prepared transaction data is recoverable. Which means that any transaction still alive at VM failure will be lost. Since all these operations are non locking, the cluster isn't suffering from these.
Prepared data on the other hand, is persisted to the L2 and locks on the memory are being held. Should the L1 come back up before the locks timed out, like network failure, the VM will be able to keep doing its work.
Should the XA recovery scan be required by the transaction manager, Ehcache will provide all Xid prepared, but these will only be able to be rolled back. Indeed when locks time out, no guarantee can be made about the locked keys and their value. If the transaction manager still asks Ehcache to commit these, a HeuristicException will be thrown.
We have three sample applications showing how to use JTA with a variety of technologies.
This sample application uses JBoss application server. It shows an example using User managed transactions. While we expect most people will use JTA from within Spring or EJB where the container rather than managing it themselves, it clearly shows what is going on.
The following snippet from our SimpleTX servlet shows a complete transaction.
Ehcache cache = cacheManager.getEhcache("xaCache");
UserTransaction ut = getUserTransaction();
printLine(servletResponse, "Hello...");
try {
ut.begin();
int index = serviceWithinTx(servletResponse, cache);
printLine(servletResponse, "Bye #" + index);
ut.commit();
} catch(Exception e) {
printLine(servletResponse,
"Caught a " + e.getClass() + "! Rolling Tx back");
if(!printStackTrace) {
PrintWriter s = servletResponse.getWriter();
e.printStackTrace(s);
s.flush();
}
rollbackTransaction(ut);
}The source code for the demo can be checked out from
http://svn.terracotta.org/svn/forge/projects/ehcache-jta-sample/trunk

A README.txt explains how to get the JTA Sample app going.
The Idea of this application is to show a real world scenario. AwWeb app reads account transfer messages from a queue and tries to execute these account transfers.
With JTA turned on, failures are rolled back so that the cached account balance is always the same as the true balance summed from the database.
This app is a Spring-based Java web app running in a Jetty container. It has (embedded) the following components:
All XA Resources are managed by Atomikos TransactionManager. Transaction demarcation is done using Spring AOP's @Transactional annotation.
You can run it with: mvn clean jetty:run. Then point your browser at: http://localhost:9080.
To see what happens without XA transactions:
mvn clean jetty:run -Dxa=no ---
The source code for the demo can be checked out from
https://svn.terracotta.org/repo/forge/projects/ehcache-jta-banking/trunk

A README.txt explains how to get the JTA Sample app going.
Examinator is our complete application that shows many aspects of caching in one web based Exam application, all using the Terracotta Server Array.
Check out from
http://svn.terracotta.org/svn/forge/projects/exam/

There are two limitations in this first release of JTA for Ehcache.
It only has effect then using Ehcache with the Terracotta Server Array ("TSA"). We are planning to add support for standalone Ehcache will be added in the next release. Doing so will require implementing copy on read and copy on write functionality into the core which is not yet present.
Ehcache is not a "transactional" cache for Hibernate purposes. We expect to add that in the next release.
WebLogic uses an optimization that is not supported by our implementation. By default WebLogic 10 will spawn threads to start the Transaction on each XAResource in parallel. As we need transaction work to be performed on the same Thread, you will have to turn this optimization off by setting parallel-xa-enabled option to false in your domain configuration :
<jta>
...
<checkpoint-interval-seconds>300</checkpoint-interval-seconds>
<parallel-xa-enabled>false</parallel-xa-enabled>
<unregister-resource-grace-period>30</unregister-resource-grace-period>
...
</jta>--- Ehcache Monitor ---
This add-on tool for Ehcache is designed to provide enterprise-class monitoring and management capabilities for use in both development and production. It is intended to help understand and tune cache usage, detect errors, and provide an easy to use access point to integrate with production management systems. It provides administrative functionality such as the ability to forcefully remove items from caches.
The package contains a probe and a server. The probe installs with your existing Ehcache cache instance, and communicates to a central server. The server aggregates data from multiple probes. It can be accessed via a simple web UI, as well as a scriptable API. In this way, it is easy to integrate with common third party systems management tools (such as Hyperic, Nagios etc). The probe is designed to be compatible with all versions of Ehcache from 1.4.1 and requires JDK 1.5 or 1.6.
First download and extract the Ehcache Monitor package.
The package consists of a lib directory with the probe and monitor server jars, a bin directory with startup and shutdown scripts for the monitor server and an etc directory with an example monitor server configuration file.
To include the probe in your Ehcache application, you need to perform two steps:
<cacheManagerPeerListenerFactory
class="org.terracotta.ehcachedx.monitor.ProbePeerListenerFactory"
properties="monitorAddress=localhost, monitorPort=9889" />Copy the monitor package to a monitoring server.
To start the monitor, run the startup script provided in the bin directory: startup.sh on Unix and startup.bat on Microsoft Windows. The monitor port selected in this script should match the port specified in ehcache.xml.
The monitor can be configured, including interface, port and security settings, in the etc/ehcache-monitor.conf.
The web-based GUI is available by pointing your browser at http://monitor-host-name:monitor-port/monitor. For a default installation on the local machine, this would be http://localhost:9889/monitor
The GUI contains 4 tabs, described as follows:
This tab shows aggregate statistics for the cache managers being monitored by probes connected to the monitor server. Double-clicking on any cache manager drills down to the detailed Statistics tab for that manager.
This tab shows the statistics being gathered for each cache managed by the selected cache manager.
The Settings button permits you to add additional statistics fields to the display. Note: only displayed fields are collected and aggregated by the probe. Adding additional display fields will increase the processing required for probe and the monitor. The selected settings are stored in a preferences cookie in your browser.
Double-clicking on any cache drills down to the Contents tab for that cache.
This tab shows the key configuration information for each cache managed by the selected cache manager.
This tab enables you to look inside the cache, search for elements via their keys and remove individual or groups of elements from the cache.
The GUI is set to refresh at the same frequency that the probes aggregate their statistic samples which is every 10 seconds by default. The progress bar at the bottom of the screen indicates the time until the next refresh.
The Monitor provides a API over HTTP on the same port as the Web GUI.
The list of functions supported by the API can be accessed by pointing your browser at http://monitor-host-name:monitor-port/monitor/list. For a default installation on the local machine, this would be http://localhost:9889/monitor/list
The API returns data as either structured XML or plan text. The default format is txt.
For example, the getVersion function returns the software version of the monitor server. It can be called as follows:
http://localhost:9889/monitor/getVersion
or, to receive the results as XML:
http://localhost:9889/monitor/getVersion?format=xml
To query the data collected by the monitor server from scripts that can then be used to pass the data to enterprise system management frameworks, commands such as curl or wget can be used.
For example, on a Linux system, to query the list of probes that a local monitor on the default port is currently aware of, and return the data in XML format, the following command could be used:
$ curl http://localhost:9889/monitor/listProbes?format=xml
The GUI is designed to work in most browsers. Currently it has been tested in Firefox and Safari and is known not to work in Microsoft Internet Explorer. Wider browser support is planned for future release builds.
Unless otherwise indicated, this module is licensed for usage in development.
For details see the license terms in the appropriate LICENSE.txt. To obtain a commercial license for use in production, please contact sales@terracottatech.com
--- Bulk Loading in Ehcache ---
Ehcache has a bulk loading mode that dramatically speeds up bulk
loading into caches using the Terracotta Server
Array.
Bulk loading is designed to be used for:
The characteristics of bulk loading are that
With bulk loading, the API for putting data into the cache stays the same. Just use cache.put(...) cache.load(...) or cache.loadAll(...)>>>.
What changes is that there is a special mode that suspends Terracotta's normal coherence guarantees and provides optimised flushing to the Terracotta Server Array (the L2 cache).
This mode can be enabled programmatically or statically in ehcache.xml. Programmatically, four methods control coherent behaviour: setNodeCoherence(boolean mode), isNodeCoherent(), isClusterCoherent() and waitUntilClusterCoherent().
setNodeCoherence(false) sets coherence to false for the Ehcache node. The setting for the rest of the cluster stays the same. The effect is that normal read and write locks are not obtained. setNodeCoherence(true) brings back the cache to coherent mode for the node.
Use this to find out if the node is in coherent mode locally. This does not account for other nodes in the cluster (if any). The node may be coherent while its incoherent cluster-wide (like some other node is incoherent)
Reflects whether the cache is in coherent or incoherent mode cluster-wide. Coherent cluster-wide means that all nodes in the cluster is using the cache in coherent mode. If even one of the nodes is using the cache in incoherent mode, the cache is incoherent cluster-wide
Calling this method will block the calling thread until the cache becomes coherent cluster-wide.
waitUntilClusterCoherent
waits until everyone is coherent. Will not return until the entire cluster is coherent.
setNodeCoherence(true | false)
This affects the local node only. The settings in the rest of the cluster are not affected.
Then to put it back call with true parameter.
This method does not return until all the transactions are flushed to the cluster. Only the calling thread is blocked. This way you know when coherence is restored. This returns as soon DONT SAY. Will make async later.
Everyone block
The initial state is from the config.
In a local standalone cache, setNodeCoherence should throw an UnsupportedOperationException. waitUntilClusterCoherent will also throw an UnsupportedOperationException.
Coherent mode may be set by default in the configuration.
The terracotta element has an attribute coherent which can be true or false. By default it is true.
Ehcache 1.7 introduced a partial implementation of this feature for reads only. That is the coherentRead. It is still honoured but deprecated.
Writes can also be synchronous or asynchronous. This is controlled by the synchronousWrites. When you are running in incoherent mode synchronousWrites are ignored - it is always asynchronous.
The speed performance improvement is an order of magnitude faster.
ehcacheperf (Spring Pet Clinic) now has a bulk load test which shows the performance improvement for using a Terracotta cluster.
Ehcache, both standalone and replicated is already very fast and nothing needed to be added.
The core updates are very fast. RMI updates are batched by default once per second, so bulk loading will be efficiently replicated.
It is not necessary to create multiple threads when calling cache.put. Only a marginal performance improvement will result, because the call is already so fast.
It is only necessary if the source is slow. By reading from the source in multiple threads a speed up could result. An example is a database, where multiple reading threads will often be better.
The implementation scales very well when the load is split up against multiple Ehcache CacheManagers on multiple machines.
You add extra nodes for bulk loading to get up to 93 times performance.
Terracotta clustering provides coherence, scaling and durability. Some applications will require coherence, or not for some caches, such as reference data. It is possible to run a cache permanently in incoherent mode.
In ehcache.xml, set the coherent attribute to false in the terracotta element. The terracotta element is a sub-element of cache, so this can be configured per cache.
The bulk loading feature is in the ehcache-core module but only provides a performance improvement to Terracotta clusters (as bulk loading to Ehcache standalone is very fast already)
Download here.
For a full distribution enabling connection to the Terracotta Server array download here.
Saravanan who was the lead on this feature has blogged about it here.
--- Class loading and Class Loaders ---
Class loading within the plethora of environments Ehcache can be running is a somewhat vexed issue.
Since ehcache-1.2 all classloading is done in a standard way in one utility class: ClassLoaderUtil.
Ehcache allows plugins for events and distribution. These are loaded and created as follows:
/**
* Creates a new class instance. Logs errors along the way. Classes are loaded using the
* Ehcache standard classloader.
*
* @param className a fully qualified class name
* @return null if the instance cannot be loaded
*/
public static Object createNewInstance(String className) throws CacheException {
Class clazz;
Object newInstance;
try {
clazz = Class.forName(className, true, getStandardClassLoader());
} catch (ClassNotFoundException e) {
//try fallback
try {
clazz = Class.forName(className, true, getFallbackClassLoader());
} catch (ClassNotFoundException ex) {
throw new CacheException("Unable to load class " + className +
". Initial cause was " + e.getMessage(), e);
}
}
try {
newInstance = clazz.newInstance();
} catch (IllegalAccessException e) {
throw new CacheException("Unable to load class " + className +
". Initial cause was " + e.getMessage(), e);
} catch (InstantiationException e) {
throw new CacheException("Unable to load class " + className +
". Initial cause was " + e.getMessage(), e);
}
return newInstance;
}
/**
* Gets the <code>ClassLoader</code> that all classes in ehcache, and extensions, should
* use for classloading. All ClassLoading in Ehcache should use this one. This is the only
* thing that seems to work for all of the class loading situations found in the wild.
* @return the thread context class loader.
*/
public static ClassLoader getStandardClassLoader() {
return Thread.currentThread().getContextClassLoader();
}
/**
* Gets a fallback <code>ClassLoader</code> that all classes in ehcache, and extensions,
* should use for classloading. This is used if the context class loader does not work.
* @return the <code>ClassLoaderUtil.class.getClassLoader();</code>
*/
public static ClassLoader getFallbackClassLoader() {
return ClassLoaderUtil.class.getClassLoader();
}If this does not work for some reason a CacheException is thrown with a detailed error message.
If the configuration is otherwise unspecified, Ehcache looks for a configuration in the following order:
Ehcache uses the first configuration found.
Note the use of "/ehcache.xml" which requires that ehcache.xml be placed at the root of the classpath, i.e. not in any package.
If Terracotta clustering is being used with valueMode="serialization" then keys and values will be moved across the cluster in byte[] and deserialized on other nodes.
The classloaders used (in order) to instantiate those classes will be:
--- Performance Considerations ---
Ehcache comes with a MemoryStore and a DiskStore. The MemoryStore is approximately an order of magnitude faster than the DiskStore. The reason is that the DiskStore incurs the following extra overhead:
Note that writing to disk is not a synchronous performance overhead because it is handled by a separate thread.
A Cache should alway have its maximumSize attribute set to 1 or higher. A Cache with a maximum size of 1 has twice the performance of a disk only cache, i.e. one where the maximumSize is set to 0. For this reason a warning will be issued if a Cache is created with a 0 maximumSize.
The asynchronous replicator is the highest performance. There are two different effects:
Collection of cache statistics is not entirely free of overhead. In production systems where monitoring is not required statistics can be disabled. This can be done either programatically by calling setStatisticsEnabled(false) on the cache instance, or in configuration by setting the statistics="false" attribute of the relevant cache configuration element. --- Cache Decorators ---
Ehcache 1.2 introduced the Ehcache interface, of which Cache is an implementation. It is possible and encouraged to create Ehcache decorators that are backed by a Cache instance, implement Ehcache and provide extra functionality.
The Decorator pattern is one of the the well known Gang of Four patterns.
Cache decorators are created as follows:
BlockingCache newBlockingCache = new BlockingCache(cache);
The class must implement Ehcache.
Having created a decorator it is generally useful to put it in a place where multiple threads may access it. This can be achieved in multiple ways.
A built-in way is to replace the Cache in CacheManager with the decorated one. This is achieved as in the following example:
cacheManager.replaceCacheWithDecoratedCache(cache, newBlockingCache);
The CacheManager replaceCacheWithDecoratedCache method requires that the decorated cache be built from the underlying cache from the same name.
Note that any overwritten Ehcache methods will take on new behaviours without casting, as per the normal rules of Java. Casting is only required for new methods that the decorator introduces.
Any calls to get the cache out of the CacheManager now return the decorated one.
A word of caution. This method should be called in an appropriately synchronized init style method before multiple threads attempt to use it. All threads must be referencing the same decorated cache. An example of a suitable init method is found in CachingFilter:
/**
* The cache holding the web pages. Ensure that all threads for a given cache name
* are using the same instance of this.
*/
private BlockingCache blockingCache;
/**
* Initialises blockingCache to use
*
* @throws CacheException The most likely cause is that a cache has not been
* configured in Ehcache's configuration file ehcache.xml for the
* filter name
*/
public void doInit() throws CacheException {
synchronized (this.getClass()) {
if (blockingCache == null) {
final String cacheName = getCacheName();
Ehcache cache = getCacheManager().getEhcache(cacheName);
if (!(cache instanceof BlockingCache)) {
//decorate and substitute
BlockingCache newBlockingCache = new BlockingCache(cache);
getCacheManager().replaceCacheWithDecoratedCache(cache, newBlockingCache);
}
blockingCache = (BlockingCache) getCacheManager().getEhcache(getCacheName());
}
}
}Ehcache blockingCache = singletonManager.getEhcache("sampleCache1");The returned cache will exhibit the decorations.
A blocking decorator for an Ehcache, backed by a @link Ehcache.
It allows concurrent read access to elements already in the cache. If the element is null, other reads will block until an element with the same key is put into the cache.
This is useful for constructing read-through or self-populating caches.
BlockingCache is used by CachingFilter.

BlockingCache
A selfpopulating decorator for @link Ehcache that creates entries on demand.
Clients of the cache simply call it without needing knowledge of whether the entry exists in the cache. If null the entry is created.
The cache is designed to be refreshed. Refreshes operate on the backing cache, and do not degrade performance of get calls.
SelfPopulatingCache extends BlockingCache. Multiple threads attempting to access a null element will block until the first thread completes. If refresh is being called the threads do not block - they return the stale data.
This is very useful for engineering highly scalable systems.

SelfPopulatingCache
These are decorated. See Cache Exception Handlers for full details.
--- Hibernate Second Level Cache ---
Ehcache easily integrates with the Hibernate Object/Relational persistence and query service. Gavin King, the maintainer of Hibernate, is also a committer to the Ehcache project. This ensures Ehcache will remain a first class cache for Hibernate.
Note these instructions are for Hibernate 3. Go to Guide for Version 1.1 for older instructions on how to use Hibernate 2.1.
The net.sf.ehcache.hibernate package provides classes integrating Ehcache with Hibernate.
The Hibernate provider is in the ehcache-core module. Download here.
For a full distribution enabling connection to the Terracotta Server array download here.
Users of Ehcache and/or Terracotta Ehcache for Hibernate prior to
Ehcache 2.0 should read Upgrade Notes for
Ehcache versions prior to
2.0.
Follow these steps to get up and running quickly:
For more about cache configuration in Hibernate see the Hibernate documentation. Parts of this chapter are drawn from Hibernate documentation and source code comments.
They are reproduced here for convenience in using ehcache.
To configure Ehcache as a Hibernate second level cache, set the region factory property (for Hibernate 3.3 and above) or the factory class property (Hibernate 3.2 and below) to one of the following in the Hibernate configuration.
Hibernate configuration is configured either via hibernate.cfg.xml, hibernate.properties or Spring. The format given is for hibernate.cfg.xml.
Use:
<property name="hibernate.cache.region.factory_class">
net.sf.ehcache.hibernate.EhCacheRegionFactory
</property>for instance creation, or
<property name="hibernate.cache.region.factory_class">
net.sf.ehcache.hibernate.SingletonEhCacheRegionFactory
</property>to force Hibernate to use a singleton of Ehcache CacheManager.
Use:
<property name="hibernate.cache.provider_class">
net.sf.ehcache.hibernate.EhCacheProvider
</property>for instance creation, or
<property name="hibernate.cache.provider_class">
net.sf.ehcache.hibernate.SingletonEhCacheProvider
</property>to force Hibernate to use a singleton Ehcache CacheManager.
The configurationResourceName property is used to specify the location of the ehcache configuration file to be used with the given Hibernate instance and cache provider/region-factory.
hibernate.cache.region.factory_class=net.sf.ehcache.hibernate.EhCacheRegionFactory net.sf.ehcache.configurationResourceName=/name_of_ehcache.xml
net.sf.ehcache.configurationResourceName - The name of a configuration resource to use.
The resource is searched for in the root of the classpath. It is needed to support multiple CacheManagers in the same VM. It tells Hibernate which configuration to use. An example might be "ehcache-2.xml".
When using multiple Hibernate instances it is therefore recommended to use multiple non-singleton providers or region factories, each with a dedicated Ehcache configuration resource.
The provider can also be set programmatically in Hibernate by adding necessary Hibernate property settings to the configuration before creating the SessionFactory: --- Configuration.setProperty("hibernate.cache.region.factory_class", "net.sf.ehcache.hibernate.EhCacheRegionFactory"). ---
In addition to configuring the Hibernate second level cache provider, Hibernate must also be told to enable caching for entities, collections, and queries.
For example to enable cache entries for the domain object com.somecompany.someproject.domain.Country there would be a mapping file something like the following:
<hibernate-mapping>
<class
name="com.somecompany.someproject.domain.Country"
table="ut_Countries"
dynamic-update="false"
dynamic-insert="false"
>
...
</class>
</hibernate-mapping>
To enable caching, add the following element.
<cache usage="read-write|nonstrict-read-write|read-only" />
e.g.
<hibernate-mapping>
<class
name="com.somecompany.someproject.domain.Country"
table="ut_Countries"
dynamic-update="false"
dynamic-insert="false"
>
<cache usage="read-write" />
...
</class>
</hibernate-mapping>This can also be achieved using the @Cache annotation, e.g.
@Entity
@Cache(usage = CacheConcurrencyStrategy.READ_WRITE)
public class Country { ... }Caches data that is never updated.
Caches data that is sometimes updated without ever locking the cache. If concurrent access to an item is possible, this concurrency strategy makes no guarantee that the item returned from the cache is the latest version available in the database. Configure your cache timeout accordingly!
Caches data that is sometimes updated while maintaining the semantics of "read committed" isolation level. If the database is set to "repeatable read", this concurrency strategy almost maintains the semantics. Repeatable read isolation is compromised in the case of concurrent writes.
Because ehcache.xml has a defaultCache, caches will always be created when required by Hibernate. However more control can be exerted by specifying a configuration per cache, based on its name.
In particular, because Hibernate caches are populated from databases, there is potential for them to get very large. This can be controlled by capping their maxElementsInMemory and specifying whether to overflowToDisk beyond that.
Hibernate uses a specific convention for the naming of caches of Domain Objects, Collections, and Queries.
Hibernate creates caches named after the fully qualified name of Domain Objects.
So, for example to create a cache for com.somecompany.someproject.domain.Country create a cache configuration entry similar to the following in ehcache.xml.
<cache
name="com.somecompany.someproject.domain.Country"
maxElementsInMemory="10000"
eternal="false"
timeToIdleSeconds="300"
timeToLiveSeconds="600"
overflowToDisk="true"
/>CacheConcurrencyStrategy read-write, nonstrict-read-write and read-only policies apply to Domain Objects.
Hibernate creates collection caches named after the fully qualified name of the Domain Object followed by "." followed by the collection field name.
For example, a Country domain object has a set of advancedSearchFacilities. The Hibernate doclet for the accessor looks like:
/**
* Returns the advanced search facilities that should appear for this country.
* @hibernate.set cascade="all" inverse="true"
* @hibernate.collection-key column="COUNTRY_ID"
* @hibernate.collection-one-to-many class="com.wotif.jaguar.domain.AdvancedSearchFacility"
* @hibernate.cache usage="read-write"
*/
public Set getAdvancedSearchFacilities() {
return advancedSearchFacilities;
}You need an additional cache configured for the set. The ehcache.xml configuration looks like:
<cache name="com.somecompany.someproject.domain.Country"
maxElementsInMemory="50"
eternal="false"
timeToLiveSeconds="600"
overflowToDisk="true"
/>
<cache
name="com.somecompany.someproject.domain.Country.advancedSearchFacilities"
maxElementsInMemory="450"
eternal="false"
timeToLiveSeconds="600"
overflowToDisk="true"
/>read-write, nonstrict-read-write and read-only policies apply to Domain Object collections.
Hibernate allows the caching of query results using two caches.
"net.sf.hibernate.cache.StandardQueryCache" and "net.sf.hibernate.cache.UpdateTimestampsCache" in versions 2.1 to 3.1 and "org.hibernate.cache.StandardQueryCache" and "org.hibernate.cache.UpdateTimestampsCache" in version 3.2. are always used.
This cache is used if you use a query cache without setting a name. A typical ehcache.xml configuration is:
<cache
name="org.hibernate.cache.StandardQueryCache"
maxElementsInMemory="5"
eternal="false"
timeToLiveSeconds="120"
overflowToDisk="true"/>Tracks the timestamps of the most recent updates to particular tables. It is important that the cache timeout of the underlying cache implementation be set to a higher value than the timeouts of any of the query caches. In fact, it is recommend that the the underlying cache not be configured for expiry at all.
A typical ehcache.xml configuration is:
<cache
name="org.hibernate.cache.UpdateTimestampsCache"
maxElementsInMemory="5000"
eternal="true"
overflowToDisk="true"/>In addition, a QueryCache can be given a specific name in Hibernate using Query.setCacheRegion(String name). The name of the cache in ehcache.xml is then the name given in that method. The name can be whatever you want, but by convention you should use "query." followed by a descriptive name.
E.g.
<cache name="query.AdministrativeAreasPerCountry"
maxElementsInMemory="5"
eternal="false"
timeToLiveSeconds="86400"
overflowToDisk="true"/>For example, let's say we have a common query running against the Country Domain.
Code to use a query cache follows:
public List getStreetTypes(final Country country) throws HibernateException {
final Session session = createSession();
try {
final Query query = session.createQuery(
"select st.id, st.name"
+ " from StreetType st "
+ " where st.country.id = :countryId "
+ " order by st.sortOrder desc, st.name");
query.setLong("countryId", country.getId().longValue());
query.setCacheable(true);
query.setCacheRegion("query.StreetTypes");
return query.list();
} finally {
session.close();
}
}The query.setCacheable(true) line caches the query.
The query.setCacheRegion("query.StreetTypes") line sets the name of the Query Cache.
Alex Miller has a good article on the query cache here.
None of read-write, nonstrict-read-write and read-only policies apply to Domain Objects. Cache policies are not configurable for query cache. They act like a non-locking read only cache.
We have demo applications showing how to use the Hibernate 3.3 CacheRegionFactory.
Check out from
https://svn.terracotta.org/repo/forge/projects/hibernate-tutorial-web/trunk

Examinator is our complete application that shows many aspects of caching, all using the Terracotta Server Array.
Check out from
https://svn.terracotta.org/svn/forge/projects/exam/

Since Hibernate 2.1, Hibernate has included an Ehcache CacheProvider. That provider is periodically synced up with the provider in the Ehcache Core distribution. New features are generally added in to the Ehcache Core provider and then the Hibernate one.
Gavin King and Greg Luck cooperated to create Ehcache and include it in Hibernate. Since 2009 Greg Luck has been a committer on the Hibernate project so as to ensure Ehcache remains a first-class 2nd level cache for Hibernate.
Yes. Ehcache 2.0 supports this new API.
No. JTA support is new in Ehcache 2.0. We plan to add JTA support for Hibernate in an upcoming release at which time we will support this strategy. An exception will be thrown if this strategy is selected.
hibernate.org maintains a table listing the providers. While ehcache works as a distributed cache for Hibernate, it is not listed as "Cluster Safe". What this means is that `Hibernate's lock and unlock methods are not implemented. Changes in one node will be applied without locking. This may or may not be a noticeable problem.
In Ehcache 1.7 when using Terracotta, this cannot happen as access to the clustered cache itself is controlled with read locks and write locks.
In Ehcache 2.0 when using Terracotta, the lock and unlock methods tie-in to the underlying clustered cache locks. We expect Ehcache 2.0 to be marked as cluster safe in new versions of the Hibernate documentation.
Hibernate identifies cached Entities via an object id. This is normally the primary key of a database row.
You cannot use identity mode clustered cache with Hibernate. If the cache is exclusively used by Hibernate we will convert identity mode caches to serialization mode. If the cache cannot be determined to be exclusively used by Hibernate (i.e. generated from a singleton cache manager) then an exception will be thrown indicating the misconfigured cache. Serialization mode is in any case the default for Terracotta clustered caches.
Soft locks are implemented by replacing a value with a special type that marks the element as locked, thus indicating to other threads to treat it differently to a normal element. This is used in the Hibernate Read/Write strategy to force fall-through to the database during the two-phase commit - since we don't know exactly what should be returned by the cache while the commit is in process (but the db does).
If a soft-locked Element is evicted by the cache during the 2 phase commit, then once the 2 phase commit completes the cache will fail to update (since the soft-locked Element was evicted) and the cache entry will be reloaded from the database on the next read of that object. This is obviously non-fatal (we're a cache failure here so it should not be a problem).
The only problem it really causes would I imagine be a small rise in db load.
So, in summary the Hibernate messages are not problematic.
The underlying cause is the probabilistic evictor can theoretically evict recently loaded items. This evictor has been tuned over successive ehcache releases. As a result this warning will happen most often in 1.6, less often in 1.7 and very rarely in 1.8.
You can also use the deterministic evictor to avoid this problem. Specify the java -Dnet.sf.ehcache.use.classic.lru=true system property to turn on classic LRU which contains a deterministic evictor.
Session.load will always try to use the cache.
Session.find does not use the cache for the primary object. Hibernate will try to use the cache for any associated objects. Session.find does however cause the cache to be populated.
Query.find works in exactly the same way.
Use these where the chance of getting a cache hit is low.
Session.iterate always uses the cache for the primary object and any associated objects.
Query.iterate works in exactly the same way.
Use these where the chance of getting a cache hit is high.
Configuring each Hibernate instance with a standalone ehcache will dramatically improve performance. However most production applications use multiple application instances for redundancy and for scalability. Ideally applications are horizontally scalable, where adding more application instances linearly improves throughput.
With an application deployed on multiple nodes, using standalone Ehcache means that each instance holds its own data. On a cache miss on any node, Hibernate will hit the database. As each new node gets added database workload goes up. The solution is to turn on distributed caching.
Ehcache comes with replicated caching via RMI, JGroups or JMS. These replicate without locking and are suitable for database offload. Generally session.refresh() should be used to check the cache against the database before performing a write that must be correct. Secondly, as each node stores all data, the cache size is limited to a comfortable storage size. Memory size is usually limited by garbage collection. Disk can also be used, but the graphs are serialized which adds overhead and results in duplication in the deserialized object graphs.
Ehcache is also the caching API to the Terracotta Server Array. Reads and writes use cluster wide locks, so when using read write Hibernate caches, the cache data on all nodes will be correct, and it is not necessary to call session.refresh().
Ehcache EX, using a single or redundant Terracotta Server Array server can comfortably store approximately 20GB per stripe. The maxElementsInMemory cache setting is used to apportion a percentage of that in process for added performance, it does not limit the size. Using striping which comes with Ehcache FX, terabyte sized caches are possible. It is possible to cache the entire database with a resulting large database offload.
These scaling decisions can be deferred. The plugin is the same regardless of how it is configured. The optimal deployment can thus be determined during performance testing or based on production experience. Finally a new application can scale as it's use grows without expensive re-architecting.
--- Shutting Down Ehcache ---
If you are using persistent disk stores, or distributed caching, care should be taken to shutdown ehcache.
Note that Hibernate automatically shuts down its Ehcache CacheManager.
The recommended way to shutdown the Ehcache is:
Though not recommended, Ehcache also lets you register a JVM shutdown hook.
Ehcache proivdes a ServletContextListener that shutsdown CacheManager. Use this when you want to shutdown Ehcache automatically when the web application is shutdown.
To receive notification events, this class must be configured in the deployment descriptor for the web application.
To do so, add the following to web.xml in your web application:
<listener>
<listener-class>net.sf.ehcache.constructs.web.ShutdownListener</listener-class>
</listener>Ehcache CacheManager can optionally register a shutdown hook.
To do so, set the system property net.sf.ehcache.enableShutdownHook=true.
This will shutdown the CacheManager when it detects the Virtual Machine shutting down and it is not already shut down.
Use the shutdown hook where:
Having said that, shutdown hooks are inherently dangerous. The JVM is shutting down, so sometimes things that can never be null are. Ehcache guards against as many of these as it can, but the shutdown hook should be the last option to use.
The shutdown hook is on CacheManager. It simply calls the shutdown method.
The sequence of events is:
Each Cache will:
The shutdown hook runs when:
The shutdown hook will not run when:
If Ehcache is shutdown dirty then any persistent disk stores will be corrupted. They will be deleted, with a log message, on the next startup.
Replications waiting to happen to other nodes in a distributed cache will also not get written.
--- Web Caching ---
Ehcache provides a set of general purpose web caching filters in the ehcache-web module.
Using these can make an amazing difference to web application performance. A typical server can deliver 5000+ pages per second from the page cache. With built-in gzipping, storage and network transmission is highly efficient. Cache pages and fragments make excellent candidates for DiskStore storage, because the object graphs are simple and the largest part is already a byte[].
This is a simple caching filter suitable for caching compressable HTTP responses such as HTML, XML or JSON.
It uses a Singleton CacheManager created with the default factory method. Override to use a different CacheManager
It is suitable for:
For fragments see the SimplePageFragmentCachingFilter.
Pages are cached based on their key. The key for this cache is the URI followed by the query string. An example is /admin/SomePage.jsp?id=1234&name=Beagle.
This key technique is suitable for a wide range of uses. It is independent of hostname and port number, so will work well in situations where there are multiple domains which get the same content, or where users access based on different port numbers.
A problem can occur with tracking software, where unique ids are inserted into request query strings. Because each request generates a unique key, there will never be a cache hit. For these situations it is better to parse the request parameters and override calculateKey(javax.servlet.http.HttpServletRequest) with an implementation that takes account of only the significant ones.
A cache entry in ehcache.xml should be configured with the name of the filter.
Names can be set using the init-param codecacheName/code, or by sub-classing this class and overriding the name.
A cache miss will cause the filter chain, upstream of the caching filter to be processed. To avoid threads requesting the same key to do useless duplicate work, these threads block behind the first thread.
The thead timeout can be set to fail after a certain wait by setting the init-param codeblockingTimeoutMillis/code. By default threads wait indefinitely. In the event upstream processing never returns, eventually the web server may get overwhelmed with connections it has not responded to. By setting a timeout, the waiting threads will only block for the set time, and then throw a @link net.sf.ehcache.constructs.blocking.LockTimeoutException. Under either scenario an upstream failure will still cause a failure.
Significant network efficiencies, and page loading speedups, can be gained by gzipping responses.
Whether a response can be gzipped depends on:
Accept-Encoding: gzip
Responses are automatically gzipped and stored that way in the cache. For requests which do not accept gzip encoding the page is retrieved from the cache, ungzipped and returned to the user agent. The ungzipping is high performance.
The SimpleCachingHeadersPageCachingFilter extends SimplePageCachingFilter to provide the HTTP cache headers: ETag, Last-Modified and Expires. It supports conditional GET.
Because browsers and other HTTP clients have the expiry information returned in the response headers, they do not even need to request the page again. Even once the local browser copy has expired, the browser will do a conditional GET.
So why would you ever want to use SimplePageCachingFilter, which does not set these headers? The answer is that in some caching scenarios you may wish to remove a page before its natural expiry. Consider a scenario where a web page shows dynamic data. Under Ehcache the Element can be removed at any time. However if a browser is holding expiry information, those browsers will have to wait until the expiry time before getting updated. The caching in this scenario is more about defraying server load rather than minimising browser calls.
The following init-params are supported:
Care should be taken not to define a filter chain such that the same CachingFilter class is reentered. The CachingFilter uses the BlockingCache. It blocks until the thread which did a get which results in a null does a put. If reentry happens a second get happens before the first put. The second get could wait indefinitely. This situation is monitored and if it happens, an IllegalStateException will be thrown.
The SimplePageFragmentCachingFilter does everyting that SimplePageCachingFilter does, except it never gzips, so the fragments can be combined. There is variant of this filter which sets browser caching headers, because that is only applicable to the entire page.
<web-app xmlns="http://java.sun.com/xml/ns/javaee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://java.sun.com/xml/ns/javaee
http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd "
version="2.5">
<filter>
<filter-name>CachePage1CachingFilter</filter-name>
<filter-class>net.sf.ehcache.constructs.web.filter.SimplePageCachingFilter
</filter-class>
<init-param>
<param-name>suppressStackTraces</param-name>
<param-value>false</param-value>
</init-param>
<init-param>
<param-name>cacheName</param-name>
<param-value>CachePage1CachingFilter</param-value>
</init-param>
</filter>
<filter>
<filter-name>SimplePageFragmentCachingFilter</filter-name>
<filter-class>net.sf.ehcache.constructs.web.filter.SimplePageFragmentCachingFilter
</filter-class>
<init-param>
<param-name>suppressStackTraces</param-name>
<param-value>false</param-value>
</init-param>
<init-param>
<param-name>cacheName</param-name>
<param-value>SimplePageFragmentCachingFilter</param-value>
</init-param>
</filter>
<filter>
<filter-name>SimpleCachingHeadersPageCachingFilter</filter-name>
<filter-class>net.sf.ehcache.constructs.web.filter.SimpleCachingHeadersPageCachingFilter
</filter-class>
<init-param>
<param-name>suppressStackTraces</param-name>
<param-value>false</param-value>
</init-param>
<init-param>
<param-name>cacheName</param-name>
<param-value>CachedPage2Cache</param-value>
</init-param>
</filter>
<!-- This is a filter chain. They are executed in the order below.
Do not change the order. -->
<filter-mapping>
<filter-name>CachePage1CachingFilter</filter-name>
<url-pattern>/CachedPage.jsp</url-pattern>
<dispatcher>REQUEST</dispatcher>
<dispatcher>INCLUDE</dispatcher>
<dispatcher>FORWARD</dispatcher>
</filter-mapping>
<filter-mapping>
<filter-name>SimplePageFragmentCachingFilter</filter-name>
<url-pattern>/include/Footer.jsp</url-pattern>
</filter-mapping>
<filter-mapping>
<filter-name>SimplePageFragmentCachingFilter</filter-name>
<url-pattern>/fragment/CachedFragment.jsp</url-pattern>
</filter-mapping>
<filter-mapping>
<filter-name>SimpleCachingHeadersPageCachingFilter</filter-name>
<url-pattern>/CachedPage2.jsp</url-pattern>
</filter-mapping>
An ehcache.xml configuration file, matching the above would then be:
<Ehcache xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:noNamespaceSchemaLocation="../../main/config/ehcache.xsd">
<diskStore path="java.io.tmpdir"/>
<defaultCache
maxElementsInMemory="10"
eternal="false"
timeToIdleSeconds="5"
timeToLiveSeconds="10"
overflowToDisk="true"
/>
<!-- Page and Page Fragment Caches -->
<cache name="CachePage1CachingFilter"
maxElementsInMemory="10"
eternal="false"
timeToIdleSeconds="10000"
timeToLiveSeconds="10000"
overflowToDisk="true">
</cache>
<cache name="CachedPage2Cache"
maxElementsInMemory="10"
eternal="false"
timeToLiveSeconds="3600"
overflowToDisk="true">
</cache>
<cache name="SimplePageFragmentCachingFilter"
maxElementsInMemory="10"
eternal="false"
timeToIdleSeconds="10000"
timeToLiveSeconds="10000"
overflowToDisk="true">
</cache>
<cache name="SimpleCachingHeadersTimeoutPageCachingFilter"
maxElementsInMemory="10"
eternal="false"
timeToIdleSeconds="10000"
timeToLiveSeconds="10000"
overflowToDisk="true">
</cache>
</ehcache>
Additional exception types have been added to the Caching Filter.
Thrown when it is detected that a caching filter's doFilter method is reentered by the same thread. Reentrant calls will block indefinitely because the first request has not yet unblocked the cache. Nasty.
The web package performs gzipping operations. One cause of problems on web browsers is getting content that is double or triple gzipped. They will either get gobblydeegook or a blank page. This exception is thrown when a gzip is attempted on already gzipped content.
A gzip encoding header needs to be added for gzipped content. The HttpServletResponse#setHeader() method is used for that purpose. If the header had already been set, the new value normally overwrites the previous one. In some cases according to the servlet specification, setHeader silently fails. Two scenarios where this happens are:
Ehcache provides a pluggable distributed caching mechanism. This enables for multiple CacheManagers and their caches in multiple JVMs to share data with each other.
Ehcache has a pluggable cache replication scheme which enables the addition of cache replication mechanisms.
The following distribution mechanisms are supported in Ehcache 1.7:
Each of the is covered in its own chapter.
Many production applications are deployed in clusters. If each application maintains its own cache, then updates made to one cache will not appear in the others. A workaround for web based applications is to use sticky sessions, so that a user, having established a session on one server, stays on that server for the rest of the session. A workaround for transaction processing systems using Hibernate is to do a session.refresh on each persistent object as part of the save. session.refresh explicitly reloads the object from the database, ignoring any cache values.
One solution is to replicate data between the caches to keep them consistent, or coherent. Typical operations which Applicable operations include:
Update supports updateViaCopy or updateViaInvalidate. The latter sends the a remove message out to the cache cluster, so that other caches remove the Element, thus preserving coherency. It is typically a lower cost option than a copy.
Ehcache 1.5 supports the Ehcache Cache Server.
To achieve shared data, all JVMs read to and write from a Cache Server, which runs it in its own JVM.
To achieve redundancy, the Ehcache inside the Cache Server can be set up in its own cluster.
This technique will be expanded upon in Ehcache 1.6.
The best way of notifying of put and update depends on the nature of the cache.
If the Element is not available anywhere else then the Element itself should form the payload of the notification. An example is a cached web page. This notification strategy is called copy.
Where the cached data is available in a database, there are two choices. Copy as before, or invalidate the data. By invalidating the data, the application tied to the other cache instance will be forced to refresh its cache from the database, preserving cache coherency. Only the Element key needs to be passed over the network.
Ehcache supports notification through copy and invalidate, selectable per cache.
Timing scenarios, race conditions, delivery, reliability constraints and concurrent updates to the same cached data can cause inconsistency (and thus a lack of coherency) across the cache instances.
This potential exists within the Ehcache implementation. These issues are the same as what is seen when two completely separate systems are sharing a database; a common scenario.
Whether data inconsistency is a problem depends on the data and how it is used. For those times when it is important, Ehcache provides for synchronous delivery of puts and updates via invalidation. These are discussed below:
Delivery can be specified to be synchronous or asynchronous. Asynchronous delivery gives faster returns to operations on the local cache and is usually preferred. Synchronous delivery adds time to the local operation, however delivery of an update to all peers in the cluster happens before the cache operation returns.
The default is to update other caches by copying the new value to them. If the replicatePutsViaCopy property is set to false in the replication configuration, puts are made by removing the element in any other cache peers. If the replicateUpdatesViaCopy property is set to false in the replication configuration, updates are made by removing the element in any other cache peers.
This forces the applications using the cache peers to return to a canonical source for the data.
A similar effect can be obtained by setting the element TTL to a low value such as a second.
Note that these features impact cache performance and should not be used where the main purpose of a cache is performance boosting over coherency.
Time To Idle is inconsistent with distributed caching. Time-to-idle makes some entries live longer on some nodes than in others because of cache usage patterns. However, the cache entry "last touched" timestamp is not replicated across the distributed cache.
Do not use Time To Idle with distributed caching, unless you do not care about inconsistent data across nodes.
--- Distributed Caching Using Terracotta Server Array ---
Terracotta has been integrated with Ehcache since Ehcache 1.4.
From version 1.7 Ehcache has been seamlessly integrated with Terracotta 3.1.1 and takes just a few lines of config in ehcache.xml to get up and running.
In Ehcache 2.0 additional configuration options have
been added which provide finer grained control.
Distribution with the Terracotta Server Array ("TSA") is the preferred distribution mechanism. It provides coherency, JTA, HA, scale and high performance. It is available as open source or with additional features in the Ehcache EX and FX product editions.
Ehcache distributed with TSA is different to the other distribution mechanisms. They all replicate data, with 100% of data held in each node. Scaling is thus limited to how much can be comfortably held in each node. Replication is also not JTA transactional or guaranteed coherent.
With TSA the data is split between an Ehcache node, which is the L1 Cache and the TSA, which is the L2 Cache. As with the other replication mechanisms the L1 can hold as much data as is comfortable. All the rest lies in the L2. In Ehcache EX, each CacheManager can have only one logical TSA (there can be multiple redundant TSAs for HA). In Ehcache FX, the TSAs are striped for unlimited scale.
Data is held in-process in the Ehcache L1 for rapid access, however the data is also always in the TSA. So the cache is unaffected by termination of an Ehcache node. When the node comes back up it reconnects to the TSA L2 and as it uses data fills its local L1. There is thus no notion of a bootstrap as there is with the other distribution mechanisms.
As this example shows, running Ehcache with Terracotta clustering is no different from normal programmatic use.
import net.sf.ehcache.Cache;
import net.sf.ehcache.CacheManager;
import net.sf.ehcache.Element;
public class TerracottaExample {
CacheManager cacheManager = new CacheManager();
public TerracottaExample() {
Cache cache = cacheManager.getCache("sampleTerracottaCache");
int cacheSize = cache.getKeys().size();
cache.put(new Element("" + cacheSize, cacheSize));
for (Object key : cache.getKeys()) {
System.out.println("Key:" + key);
}
}
public static void main(String[] args) throws Exception {
new TerracottaExample();
}
}
The above example looks for sampleTerracottaCache.
In ehcache.xml, we need to uncomment or add the following line:
<terracottaConfig url="localhost:9510"/>
which tells Ehcache to load the Terracotta server config from localhost port 9510. Note: You must have a Terracotta 3.1.1 or higher server running locally for this example.
Next we want to enable Terracotta clustering for the cache named sampleTerracottaCache. Uncomment or add the following in ehcache.xml.
<cache name="sampleTerracottaCache"
maxElementsInMemory="1000"
eternal="false"
timeToIdleSeconds="3600"
timeToLiveSeconds="1800"
overflowToDisk="false">
<terracotta/>
</cache>That's it!
Terracotta configuration in ehcache.xml is in three parts:
The attributes of ehcache are:
an optional name for the CacheManager. The name is optional and primarily used for documentation or to distinguish Terracotta clustered cache state. With Terracotta clustered caches, a combination of CacheManager name and cache name uniquely identify a particular cache store in the Terracotta clustered memory.
The name will show up in the Developer Consoles.
an optional boolean flag specifying whether this CacheManager should check for new versions of Ehcache over the Internet. If not specified, updateCheck="true".
an optional setting that determines whether the CacheManager should automatically register the SampledCacheMBean with the system MBean server. Currently, this monitoring is only useful when using Terracotta and thus the "autodetect" value will detect the presence of Terracotta and register the MBean. Other allowed values are "on" and "off". The default is "autodetect".
<Ehcache xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:noNamespaceSchemaLocation="ehcache.xsd"
updateCheck="true" monitoring="autodetect">
Note: You need to install and run one or more Terracotta servers to use Terracotta clustering.
See http://www.terracotta.org/web/display/orgsite/Download.
With a server/servers up and running you need to specify the location of the servers.
Configuration can be specified in two main ways: by reference to a source of configuration or by use of an embedded Terracotta configuration file.
To specify a reference to a source (or sources) of configuration, use the url attribute. The url attribute must contain a comma-separated list of:
Example using a path to Terracotta configuration file:
<terracottaConfig url="/app/config/tc-config.xml"/>
Example using a URL to a Terracotta configuration file:
<terracottaConfig url="http://internal/ehcache/app/tc-config.xml"/>
Example pointing to a Terracotta server installed on localhost:
<terracottaConfig url="localhost:9510"/>
Example using multiple Terracotta server instance URLs (for fault tolerance):
<terracottaConfig url="host1:9510,host2:9510,host3:9510"/>
To embed a Terracotta configuration file within the Ehcache configuration, simply place the usual Terracotta XML config within the terracottaConfig element.
In this example we have two Terracotta servers running on server1 and server2.
<terracottaConfig>
<tc-config>
<servers>
<server host="server1" name="s1"/>
<server host="server2" name="s2"/>
</servers>
<clients>
<logs>app/logs-%i</logs>
</clients>
</tc-config>
</terracottaConfig>Cache elements can also contain information about whether the cache can be clustered with Terracotta.
The terracotta sub-element has the following attributes:
Indicates whether this cache should be clustered with Terracotta. By default, if the terracotta element is included, clustered=true.
Indicates whether this cache should be clustered with serialized copies of the values or using Terracotta identity mode. By default, values will be cached in serialization mode which is similar to other replicated Ehcache modes. The identity mode is only available in certain Terracotta deployment scenarios and will maintain actual object identity of the keys and values across the cluster. In this case, all users of a value retrieved from the cache are using the same clustered value and must provide appropriate locking for any changes made to the value (or objects referred to by the value).
Indicates whether this cache should have coherent reads with guaranteed consistency across the cluster. By default, this setting is true. If you set this property to false, reads are allowed to check the local value without locking, possibly seeing stale values.
This is a performance optimization with weaker concurrency guarantees and should generally be used with caches that contain read-only data or where the application can tolerate reading stale data.
Note that from Ehcache 2.0, this setting has the same affect as coherent.

Indicates whether cache values are deserialized on every read or if the materialized cache value can be re-used between get() calls.
This setting is useful if a cache is being shared by callers with disparate classloaders or to prevent local drift if keys/values are mutated locally w/o putting back to the cache. i.e. if set to true then each thread has its own copy and cannot affect other threads.
NOTE: This setting is only relevant for caches with valueMode=serialization

Indicates whether this cache should have coherent reads and writes with guaranteed consistency across the cluster. By default, its value is true. If this attribute is set to false (or "incoherent" mode), values from the cache are read without locking, possibly yielding stale data. Writes to a cache in incoherent mode are batched and applied without acquiring cluster-wide locks, possibly creating inconsistent values across cluster. Incoherent mode is a performance optimization with weaker concurrency guarantees and should generally be used for bulk-loading caches, for loading a read-only cache, or where the application that can tolerate reading stale data.
This setting overrides coherentReads, which is deprecated. For backward compatibility any configurations setting a value for coherentReads will apply to coherent.

When set to true, clustered caches use Terracotta SYNCHRONOUS WRITE locks. Asynchronous writes(synchronousWrites="false") maximize performance byallowing clients to proceed without waiting for a "transaction received" acknowledgement from the server. Synchronous writes (synchronousWrites="true") maximizes data safety by requiring that a client receive server acknowledgement of a transaction before that client can proceed. If coherence mode is disabled using configuration (coherent="false") or through the coherence API, only asynchronous writes can occur (synchronousWrites="true" is ignored). By default this value is false (i.e. clustered caches use normal Terracotta WRITE locks).
The simplest way to enable clustering is to add:
<terracotta/>
To indicate the cache should not be clustered (or remove the terracotta element altogether):
<terracotta clustered="false"/>
To indicate the cache should be clustered using identity mode:
<terracotta clustered="true" valueMode="identity"/>
Following is an example Terracotta clustered cache named sampleTerracottaCache.
<cache name="sampleTerracottaCache"
maxElementsInMemory="1000"
eternal="false"
timeToIdleSeconds="3600"
timeToLiveSeconds="1800"
overflowToDisk="false">
<terracotta/>
</cache>The copyOnRead setting is most easily explained by first examining what it does when not enabled and exploring the potential problems that can arise.
For a cache for which copyOnRead is NOT enabled, the following reference comparsion will always be true (NOTE: assuming no other thread changes the cache mapping between the get()'s)
Object obj1 = c.get("key").getValue();
Object obj2 = c.get("key").getValue();
if (obj1 == obj2) {
System.err.println("Same value objects!");
}The fact that the same object reference is returned accross multiple get()'s implies that the cache is storing a direct reference to cache value. When copyOnRead is enabled the object references will be fresh and unique upon every get().
This default behavior (copyOnRead=false) is usually what you want although there are at least two scenarios in which this is problematic: (1) Caches shared between classloaders and (2) Mutable value objects
Imagine two web applications that both have access to the same Cache instance (this implies that the core ehcache classes are in a common classloader). Imagine further that the classes for value types in the cache are duplicated in the web application (ie. they are not present in the common loader). In this scenario you would get ClassCastExceptions when one web application accessed a value previously read by the other application. One solution to this problem is obviously to move the value types to the common loader, but another is to enable copyOnRead so that thread context loader of the caller will be used to materialize the cache values on each get(). This feature has utility in OSGi environments as well where a common cache service might be shared between bundles
Another subtle issue concerns mutable value objects in a clustered cache. Consider this simple code which shows a Cache that contains a mutable value type (Foo):
class Foo {
int field;
}
Foo foo = (Foo) c.get("key").getValue();
foo.field++;
// foo instance is never re-put() to the cache
// ...If the Foo instance is never re-put() to the Cache your local cache is no longer consistent with the cluster (it is locally modified only). Enabling copyOnRead eliminates this possibility since the only way to affect cache values is to call mutator methods on the Cache.
It is worth noting that there is a performance penalty to copyOnRead since values are deserialized on every get().
Terracotta clustering works by clustering the MemoryStore, unlike the replication mechanisms which use the CacheEventListener infrastructure.
This results in a simpler programming contract than with the replication mechanisms.
Things to note:
Cache listeners listen for changes, including replicated cluster changes, made through the Cache API. Because Terracotta cluster changes happen transparently directly to the MemoryStore a listener will not be invoked when an event occurs out on the cluster. If it occurs locally, then it must have occurred through the Cache API, so a local event will be detected by a local listener.
A common use of listeners is to trigger a reload of a just invalidated Element. In Terracotta clustering this is avoided as a change in one node is always coherent to the other nodes.
To send out cache change events across the cluster, you need to set up a local listener on the relevant cache so that these events can be propagated to other nodes. This is done by adding the following cacheEventListenerFactory tag to the cache:
<cacheEventListenerFactory class="net.sf.ehcache.event.TerracottaCacheEventReplicationFactory"/>
Overflow to Disk is ignored when using Terracotta Clustering. However it is not needed because the Terracotta server has its own overflow to disk. Once the maxElementsInMemory limit is reached Elements will be evicted to the cluster.

The interface net.sf.ehcache.cluster.CacheCluster provides methods for obtaining topology information for a Terracotta cluster.
The following methods are available:
The interface net.sf.ehcache.cluster.ClusterNode provides methods for obtaining information on specific cluster nodes.
public interface ClusterNode {
/**
* Get a unique (per cluster) identifier for this node.
*
* @return Unique per cluster identifier
*/
String getId();
/**
* Get the host name of the node
*
* @return Host name of node
*/
String getHostname();
/**
* Get the IP address of the node
*
* @return IP address of node
*/
String getIp();
}
Terracotta has a Terracotta Cluster event notification mechanism. From Ehcache 2.0, Ehcache can receive these events.
This is not cache event notification, rather it is cluster event notification.
The Terracotta Distributed Ehcache cluster events API provides access to Terracotta cluster events and cluster topology.
The interface net.sf.ehcache.cluster.ClusterTopologyListener provides methods for detecting the following cluster events:
public interface ClusterTopologyListener {
/**
* A node has joined the cluster
*
* @param node The joining node
*/
void nodeJoined(ClusterNode node);
/**
* A node has left the cluster
*
* @param node The departing node
*/
void nodeLeft(ClusterNode node);
/**
* This node has established contact with the cluster and can execute clustered operations.
*
* @param node The current node
*/
void clusterOnline(ClusterNode node);
/**
* This node has lost contact (possibly temporarily) with the cluster and cannot execute
* clustered operations
*
* @param node The current node
*/
void clusterOffline(ClusterNode node);
}This example prints out the cluster nodes and then registers a ClusterTopologyListener which prints out events as they happen.
CacheManager mgr = ...
CacheCluster cluster = mgr.getCluster("Terracotta");
// Get current nodes
Collection<ClusterNode> nodes = cluster.getNodes();
for(ClusterNode node : nodes) {
System.out.println(node.getId() + " " + node.getHostname() + " " + node.getIp());
}
// Register listener
cluster.addTopologyListener(new ClusterTopologyListener() {
public void nodeJoined(ClusterNode node) { System.out.println(node + " joined"); }
public void nodeLeft(ClusterNode node) { System.out.println(node + " left"); }
public void clusterOnline(ClusterNode node) { System.out.println(node + " enabled"); }
public void clusterOffline(ClusterNode node) { System.out.println(node + " disabled"); }
});If Ehcache got disconnected from the Terracotta Server Array say due to a network issue, then in Ehcache 2.0 each cache operation will block indefinitely. In other words it is configured for fail-fast to protect the ACIDity of the cluster.
However this approach will also cause processing of requests to the cache to stop likely causing the outage to cascade. In some cases graceful degradation may be more appropriate. When the clusterOffline events fires you could call Cache.setDisabled() which will cause puts and gets to bypass the cache. Your application would then degrade to operating without a cache, but might be able to do useful work.
You could also take the whole application off-line.
When connectivity is restored you could then reverse the action, taking the cache back online or the application back on line as the case may be.
We expect to add some of these common behaviours into configuration in the next release:
Please see Terracotta Documentation for much more information.
timeToIdle and timeToLive work as usual. Ehcache 1.7 introduced a less fine grained age recording in Element which rounds up to the nearest second. Some APIs may be sensitive to this change.
In Ehcache Elements can have overridden TTI and TTLs. Terracotta supports this functionality.
Ehcache supports LRU, LFU and FIFO eviction strategies.
Terracotta supports LRU and LFU eviction from the local node. Not FIFO and not custom evictors.
The Terracotta server provides an additional store, generally referred to as the Level 2 or L2 store.
The MemoryStore in JVM in the local node is referred to as the L1 Store.
maxElementsInMemory - the maximum number of elements in the local L1 store.
maxElementsOnDisk - is overridden when using Terracotta to provide the L2 size. The L2 size is effectively the maximum cache size.
overflowToDisk normally controls whether to overflow to the DiskStore. This is ignored when using Terracotta - the DiskStore is never used. When the store gets full, elements will always overflow to the Terracotta L2 Store running on the server. The L2 can be further configured with the tcconfig.
Two things to cause elements to be flushed from L1 to L2.
An Element, key and value in Ehcache is guaranteed to .equals() another as it moves between stores.
In the Express install or Serialization mode of Terracotta, which is the default, Terracotta is the same. Elements will not == each other as they move between stores.
An Element in Ehcache is guaranteed to .equals() another as it moves between stores.
However in Identity mode, Terracotta makes a further guarantee that they key and the value ==. This is achieved using extensions to the Java Memory Model.
Terracotta' non Ehcache API offers an async writethrough to the database which is guaranteed. It uses the TIM Async module and works by putting the database update in a clustered queue. It guarantees that a node, even if the local node fails, will take it out and process it.
That option is not available with Ehcache although it may get added.
It isn't. This is a problem with using a database as an integration point. Integration via a message queue, with a Terracotta clustered application acting as a message queue listener and updating the database avoids this. As would The application receiving a REST or SOAP call and writing to the database.
AQ can have DB trigger put in a poll. Or AQ can push it up.
A local CacheEventListener will work locally, but other nodes in a Terracotta cluster are not notified unless the TerracottaCacheEventReplicationFactory event listener is registered for the cache.
SampledCache and SampledCacheManager MBeans are made available in the Terracotta Developer Console.
These are time based gauges, based on once per second measurements. These are different to the JMX MBeans available through the ManagementService.
The following classloaders are tried in this order:
For full compatibility Ehcache 2.0 should be used with Terracotta Server 3.2.1.
Ehcache 1.7 works with TC 3.1.1.
Ehcache Core 1.7.3 core works with TC 3.2.
Note that existing threads doing I/O against the TC server (whether for data or for locks) are stuck.

Since version 1.2, Ehcache has provided distributed caching using RMI.
An RMI implementation is desirable because:
While RMI is a point-to-point protocol, which can generate a lot of network traffic, Ehcache manages this through batching of communications for the asynchronous replicator.
To set up RMI distributed caching you need to configure the CacheManager with:
The for each cache that will operate distributed, you then need to add one of the RMI cacheEventListener types to propagate messages.
You can also optionally configure a cache to bootstrap from other caches in the cluster.
Only Serializable Elements are suitable for replication.
Some operations, such as remove, work off Element keys rather than the full Element itself. In this case the operation will be replicated provided the key is Serializable, even if the Element is not.
Ehcache has the notion of a group of caches acting as a distributed cache. Each of the caches is a peer to the others. There is no master cache. How do you know about the other caches that are in your cluster? This problem can be given the name Peer Discovery.
Ehcache provides two mechanisms for peer discovery, just like a car: manual and automatic.
To use one of the built-in peer discovery mechanisms specify the class attribute of cacheManagerPeerProviderFactory as net.sf.ehcache.distribution.RMICacheManagerPeerProviderFactory in the ehcache.xml configuration file.
Automatic discovery uses TCP multicast to establish and maintain a multicast group. It features minimal configuration and automatic addition to and deletion of members from the group. No a priori knowledge of the servers in the cluster is required. This is recommended as the default option.
Peers send heartbeats to the group once per second. If a peer has not been heard of for 5 seconds it is dropped from the group. If a new peer starts sending heartbeats it is admitted to the group.
Any cache within the configuration set up as replicated will be made available for discovery by other peers.
To set automatic peer discovery, specify the properties attribute of cacheManagerPeerProviderFactory as follows:
peerDiscovery=automatic multicastGroupAddress=multicast address | multicast host name multicastGroupPort=port timeToLive=0-255 (See below in common problems before setting this) hostName= the hostname or IP of the interface to be used for sending and receiving multicast packets (relevant to mulithomed hosts only)
Suppose you have two servers in a cluster. You wish to distribute sampleCache11 and sampleCache12. The configuration required for each server is identical:
Configuration for server1 and server2
<cacheManagerPeerProviderFactory class="net.sf.ehcache.distribution.RMICacheManagerPeerProviderFactory" properties="peerDiscovery=automatic, multicastGroupAddress=230.0.0.1, multicastGroupPort=4446, timeToLive=32"/>
Manual peer configuration requires the IP address and port of each listener to be known. Peers cannot be added or removed at runtime. Manual peer discovery is recommended where there are technical difficulties using multicast, such as a router between servers in a cluster that does not propagate multicast datagrams. You can also use it to set up one way replications of data, by having server2 know about server1 but not vice versa.
To set manual peer discovery, specify the properties attribute of cacheManagerPeerProviderFactory as follows: peerDiscovery=manual rmiUrls=//server:port/cacheName, ...
The rmiUrls is a list of the cache peers of the server being configured. Do not include the server being configured in the list.
Suppose you have two servers in a cluster. You wish to distribute sampleCache11 and sampleCache12. Following is the configuration required for each server:
Configuration for server1
<cacheManagerPeerProviderFactory class="net.sf.ehcache.distribution.RMICacheManagerPeerProviderFactory" properties="peerDiscovery=manual, rmiUrls=//server2:40001/sampleCache11|//server2:40001/sampleCache12"/>
Configuration for server2
<cacheManagerPeerProviderFactory class="net.sf.ehcache.distribution.RMICacheManagerPeerProviderFactory" properties="peerDiscovery=manual, rmiUrls=//server1:40001/sampleCache11|//server1:40001/sampleCache12"/>
A CacheManagerPeerListener listens for messages from peers to the current CacheManager.
You configure the CacheManagerPeerListener by specifiying a CacheManagerPeerListenerFactory which is used to create the CacheManagerPeerListener using the plugin mechanism.
The attributes of cacheManagerPeerListenerFactory are:
Ehcache comes with a built-in RMI-based distribution system. The listener component is RMICacheManagerPeerListener which is configured using RMICacheManagerPeerListenerFactory. It is configured as per the following example:
<cacheManagerPeerListenerFactory class="net.sf.ehcache.distribution.RMICacheManagerPeerListenerFactory" properties="hostName=localhost, port=40001, socketTimeoutMillis=2000"/>
Valid properties are:
The hostname is checked for reachability during CacheManager initialisation.
If the hostName is unreachable, the CacheManager will refuse to start and an CacheException will be thrown indicating connection was refused.
If unspecified, the hostname will use InetAddress.getLocalHost().getHostAddress(), which corresponds to the default host network interface.
Warning: Explicitly setting this to localhost refers to the local loopback of 127.0.0.1, which is not network visible and will cause no replications to be received from remote hosts. You should only use this setting when multiple CacheManagers are on the same machine.
Each cache that will be distributed needs to set a cache event listener which then replicates messages to the other CacheManager peers. This is done by adding a cacheEventListenerFactory element to each cache's configuration.
<!-- Sample cache named sampleCache2. -->
<cache name="sampleCache2"
maxElementsInMemory="10"
eternal="false"
timeToIdleSeconds="100"
timeToLiveSeconds="100"
overflowToDisk="false">
<cacheEventListenerFactory
class="net.sf.ehcache.distribution.RMICacheReplicatorFactory"
properties="replicateAsynchronously=true, replicatePuts=true, replicateUpdates=true,
replicateUpdatesViaCopy=false, replicateRemovals=true "/>
</cache>class - use net.sf.ehcache.distribution.RMICacheReplicatorFactory
The factory recognises the following properties:
To reduce typing if you want default behaviour, which is replicate everything in asynchronous mode, you can leave off the RMICacheReplicatorFactory properties as per the following example:
<!-- Sample cache named sampleCache4. All missing RMICacheReplicatorFactory properties
default to true -->
<cache name="sampleCache4"
maxElementsInMemory="10"
eternal="true"
overflowToDisk="false"
memoryStoreEvictionPolicy="LFU">
<cacheEventListenerFactory
class="net.sf.ehcache.distribution.RMICacheReplicatorFactory"/>
</cache>When a peer comes up, it will be incoherent with other caches. When the bootstrap completes it will be partially coherent. Bootstrap gets the list of keys from a random peer, and then loads those in batches from random peers. If bootstrap fails then the Cache will not start (not like this right now). However if a distributed cache operation occurs which is then overwritten by bootstrap there is a chance that the cache could be inconsistent.
Here are some scenarios:
Delete overwritten by boostrap put --- Cache A keys with values: 1, 2, 3, 4, 5
Cache B starts bootstrap
Cache A removes key 2
Cache B removes key 2 and then bootstrap puts it back
---
Put overwritten by boostrap put --- Cache A keys with values: 1, 2, 3, 4, 5
Cache B starts bootstrap
Cache A updates the value of key 2
Cache B updates the value of key 2 and then bootstrap overwrites it with the old value
---
The solution is for bootstrap to get a list of keys and write them all before committing transactions.
This could cause synchronous transaction replicates to back up. To solve this problem, commits will be accepted, but not written to the cache until after bootstrap. Coherency is maintained because the cache is not available until bootstrap has completed and the transactions have been completed.
Ehcache's own integration tests provide complete examples of RMI-based replication. The best example is the integration test for cache replication. You can see it online here: http://ehcache.org/xref-test/net/sf/ehcache/distribution/RMICacheReplicatorTest.html
The test uses 5 ehcache.xml's representing 5 CacheManagers set up to distribute using RMI.
There is a bug in Tomcat and/or the JDK where any RMI listener will fail to start on Tomcat if the installation path has spaces in it. See http://archives.java.sun.com/cgi-bin/wa?A2=ind0205&L=rmi-users&P=797 and http://www.ontotext.com/kim/doc/sys-doc/faq-howto-bugs/known-bugs.html.
As the default on Windows is to install Tomcat in "Program Files", this issue will occur by default.
The automatic peer discovery process relies on multicast. Multicast can be blocked by routers. Virtualisation technologies like Xen and VMWare may be blocking multicast. If so enable it. You may also need to turn it on in the configuration for your network interface card.
An easy way to tell if your multicast is getting through is to use the Ehcache remote debugger and watch for the heartbeat packets to arrive.
You can control how far the multicast packets propagate by setting the badly misnamed time to live. Using the multicast IP protocol, the timeToLive value indicates the scope or range in which a packet may be forwarded. By convention:
0 is restricted to the same host 1 is restricted to the same subnet 32 is restricted to the same site 64 is restricted to the same region 128 is restricted to the same continent 255 is unrestricted
The default value in Java is 1, which propagates to the same subnet. Change the timeToLive property to restrict or expand propagation.
--- Distributed Caching using JGroups ---
As of version 1.5, JGroups can be used as the underlying mechanism for the distributed operations in ehcache. JGroups offers a very flexible protocol stack, reliable unicast and multicast message transmission. On the down side JGroups can be complex to configure and some protocol stacks have dependencies on others.
To set up distributed caching using JGroups you need to configure a PeerProviderFactory of type JGroupsCacheManagerPeerProviderFactory which is done globally for a CacheManager For each cache that will operate distributed, you then need to add a cacheEventListenerFactory of type JGroupsCacheReplicatorFactory to propagate messages.
Only Serializable Elements are suitable for replication.
Some operations, such as remove, work off Element keys rather than the full Element itself. In this case the operation will be replicated provided the key is Serializable, even if the Element is not.
If you use the UDP multicast stack there is no additional configuration. If you use a TCP stack you will need to specify the initial hosts in the cluster.
There are two things to configure:
The main configuration happens in the JGroupsCacheManagerPeerProviderFactory connect sub-property. A connect property is passed directly to the JGroups channel and therefore all the protocol stacks and options available in JGroups can be set.
Suppose you have two servers in a cluster. You wish to distribute sampleCache11 and sampleCache12 and you wish to use UDP multicast as the underlying mechanism.
The configuration for server1 and server2 are identical and will look like this:
<cacheManagerPeerProviderFactory
class="net.sf.ehcache.distribution.jgroups.JGroupsCacheManagerPeerProviderFactory"
properties="connect=UDP(mcast_addr=231.12.21.132;mcast_port=45566;):PING:
MERGE2:FD_SOCK:VERIFY_SUSPECT:pbcast.NAKACK:UNICAST:pbcast.STABLE:FRAG:pbcast.GMS"
propertySeparator="::"
/>The TCP protocol requires the IP address of all servers to be known. They are configured through the TCPPING protocol of Jgroups.
Suppose you have 2 servers host1 and host2, then the configuration is:
<cacheManagerPeerProviderFactory
class="net.sf.ehcache.distribution.jgroups.JGroupsCacheManagerPeerProviderFactory"
properties="connect=TCP(start_port=7800):
TCPPING(initial_hosts=host1[7800],host2[7800];port_range=10;timeout=3000;
num_initial_members=3;up_thread=true;down_thread=true):
VERIFY_SUSPECT(timeout=1500;down_thread=false;up_thread=false):
pbcast.NAKACK(down_thread=true;up_thread=true;gc_lag=100;retransmit_timeout=3000):
pbcast.GMS(join_timeout=5000;join_retry_timeout=2000;shun=false;
print_local_addr=false;down_thread=true;up_thread=true)"
propertySeparator="::" />You should read the JGroups documentation to configure the protocols correctly.
See http://www.jgroups.org/javagroupsnew/docs/manual/html_single/index.html.
If using UDP you should at least configure PING, FD_SOCK (Failure detection), VERIFY_SUSPECT, pbcast.NAKACK (Message reliability), pbcast.STABLE (message garbage collection).
Each cache that will be distributed needs to set a cache event listener which then replicates messages to the other CacheManager peers. This is done by adding a cacheEventListenerFactory element to each cache's configuration. The properties are identical to the one used for RMI replication.
The listener factory MUST be of type JGroupsCacheReplicatorFactory.
<!-- Sample cache named sampleCache2. --> <cache name="sampleCache2" maxElementsInMemory="10" eternal="false" timeToIdleSeconds="100" timeToLiveSeconds="100" overflowToDisk="false"> <cacheEventListenerFactory class="net.sf.ehcache.distribution.jgroups.JGroupsCacheReplicatorFactory" properties="replicateAsynchronously=true, replicatePuts=true, replicateUpdates=true, replicateUpdatesViaCopy=false, replicateRemovals=true" /> </cache>
The configuration options are explained below:
class - use net.sf.ehcache.distribution.jgroups.JGroupsCacheReplicatorFactory
The factory recognises the following properties:
A typical complete configuration for one replicated cache configured for UDP will look like:
<Ehcache xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:noNamespaceSchemaLocation="../../../main/config/ehcache.xsd">
<diskStore path="java.io.tmpdir/one"/>
<cacheManagerPeerProviderFactory class="net.sf.ehcache.distribution.jgroups
.JGroupsCacheManagerPeerProviderFactory"
properties="connect=UDP(mcast_addr=231.12.21.132;mcast_port=45566;ip_ttl=32;
mcast_send_buf_size=150000;mcast_recv_buf_size=80000):
PING(timeout=2000;num_initial_members=6):
MERGE2(min_interval=5000;max_interval=10000):
FD_SOCK:VERIFY_SUSPECT(timeout=1500):
pbcast.NAKACK(gc_lag=10;retransmit_timeout=3000):
UNICAST(timeout=5000):
pbcast.STABLE(desired_avg_gossip=20000):
FRAG:
pbcast.GMS(join_timeout=5000;join_retry_timeout=2000;
shun=false;print_local_addr=true)"
propertySeparator="::"
/>
<cache name="sampleCacheAsync"
maxElementsInMemory="1000"
eternal="false"
timeToIdleSeconds="1000"
timeToLiveSeconds="1000"
overflowToDisk="false">
<cacheEventListenerFactory
class="net.sf.ehcache.distribution.jgroups.JGroupsCacheReplicatorFactory"
properties="replicateAsynchronously=true, replicatePuts=true,
replicateUpdates=true, replicateUpdatesViaCopy=false,
replicateRemovals=true" />
</cache>
</ehcache>
If replication using JGroups doesnt't work the way you have it configured try this configuration which has been extensively tested:
<cacheManagerPeerProviderFactory
class="net.sf.ehcache.distribution.jgroups.JGroupsCacheManagerPeerProviderFactory"/>
<cache name="sampleCacheAsync"
maxElementsInMemory="1000"
eternal="false"
timeToIdleSeconds="1000"
timeToLiveSeconds="1000"
overflowToDisk="false">
<cacheEventListenerFactory
class="net.sf.ehcache.distribution.jgroups.JGroupsCacheReplicatorFactory"
properties="replicateAsynchronously=true, replicatePuts=true,
replicateUpdates=true, replicateUpdatesViaCopy=false,
replicateRemovals=true" />
</cache>If this fails to replicate, try to get the example programs from JGroups to run:
http://www.jgroups.org/javagroupsnew/docs/manual/html/ch02.html#d0e451
and
http://www.jgroups.org/javagroupsnew/docs/manual/html/ch02.html#ItDoesntWork
Once you have figured out the connection string that works in your network for JGroups, you can directly paste it in the connect property of JGroupsCacheManagerPeerProviderFactory.
--- Distributed Caching using JMS ---
As of version 1.6, JMS can be used as the underlying mechanism for the distributed operations in Ehcache with the jmsreplication module.
JMS, ("Java Message Service") is an industry standard mechanism for interacting with message queues. Message queues themselves are a very mature piece of infrastructure used in many enterprise software contexts. Because they are a required part of the Java EE specification, the large enterprise vendors all provide their own implementations. There are also several open source choices including Open MQ and Active MQ. Ehcache is integration tested against both of these.
The Ehcache jmsreplication module lets organisations with a message queue investment leverage it for caching.
It provides:
Ehcache replicates using JMS as follows:
To set up distributed caching using JMS you need to configure a JMSCacheManagerPeerProviderFactory which is done globally for a CacheManager.
For each cache that wishing to replicate, you add a JGroupsCacheReplicatorFactory element to the cache element.

Each cluster needs to use a fixed topic name for replication. Set up a topic using the tools in your message queue. Out of the box, both ActiveMQ and Open MQ support auto creation of destinations, so this step may be optional.
Configuration is done in the ehcache.xml.
There are two things to configure:
The main configuration happens in the JGroupsCacheManagerPeerProviderFactory connect sub-property. A connect property is passed directly to the JGroups channel and therefore all the protocol stacks and options available in JGroups can be set.
Following is the configuration instructions as it appears in the sample ehcache.xml shipped with ehcache:
{Configuring JMS replication}.
===========================
<cacheManagerPeerProviderFactory
class="net.sf.ehcache.distribution.jms.JMSCacheManagerPeerProviderFactory"
properties="..."
propertySeparator=","
/>
The JMS PeerProviderFactory uses JNDI to maintain message queue independence.
Refer to the manual for full configuration examples using ActiveMQ and Open Message Queue.
Valid properties are:
* initialContextFactoryName (mandatory) - the name of the factory used to create the
message queue initial context.
* providerURL (mandatory) - the JNDI configuration information for the service provider to
use.
* topicConnectionFactoryBindingName (mandatory) - the JNDI binding name for the
TopicConnectionFactory
* topicBindingName (mandatory) - the JNDI binding name for the topic name
* securityPrincipalName - the JNDI java.naming.security.principal
* securityCredentials - the JNDI java.naming.security.credentials
* urlPkgPrefixes - the JNDI java.naming.factory.url.pkgs
* userName - the user name to use when creating the TopicConnection to the Message Queue
* password - the password to use when creating the TopicConnection to the Message Queue
* acknowledgementMode - the JMS Acknowledgement mode for both publisher and subscriber.
The available choices are
AUTO_ACKNOWLEDGE, DUPS_OK_ACKNOWLEDGE and SESSION_TRANSACTED.
The default is AUTO_ACKNOWLEDGE.
* listenToTopic - true or false. If false, this cache will send to the JMS topic but will
not listen for updates.
* Default is true.Usage is best illustrated with concrete examples for Active MQ and Open MQ.
This configuration works with Active MQ out of the box.
<cacheManagerPeerProviderFactory
class="net.sf.ehcache.distribution.jms.JMSCacheManagerPeerProviderFactory"
properties="initialContextFactoryName=ExampleActiveMQInitialContextFactory,
providerURL=tcp://localhost:61616,
topicConnectionFactoryBindingName=topicConnectionFactory,
topicBindingName=ehcache"
propertySeparator=","
/>You need to provide your own ActiveMQInitialContextFactory for the initialContextFactoryName.
An example which should work for most purposes is:
public class ExampleActiveMQInitialContextFactory extends ActiveMQInitialContextFactory {
/**
* {@inheritDoc}
*/
@Override
@SuppressWarnings("unchecked")
public Context getInitialContext(Hashtable environment) throws NamingException {
Map<String, Object> data = new ConcurrentHashMap<String, Object>();
String factoryBindingName = (String)environment.get(JMSCacheManagerPeerProviderFactory
.TOPIC_CONNECTION_FACTORY_BINDING_NAME);
try {
data.put(factoryBindingName, createConnectionFactory(environment));
} catch (URISyntaxException e) {
throw new NamingException("Error initialisating ConnectionFactory with message "
+ e.getMessage());
}
String topicBindingName = (String)environment.get(JMSCacheManagerPeerProviderFactory
.TOPIC_BINDING_NAME);
data.put(topicBindingName, createTopic(topicBindingName));
return createContext(environment, data);
}
}
This configuration works with an out of the box Open MQ.
<cacheManagerPeerProviderFactory
class="net.sf.ehcache.distribution.jms.JMSCacheManagerPeerProviderFactory"
properties="initialContextFactoryName=com.sun.jndi.fscontext.RefFSContextFactory,
providerURL=file:///tmp,
topicConnectionFactoryBindingName=MyConnectionFactory,
topicBindingName=ehcache"
propertySeparator=","
/>To set up the Open MQ file system initial context to work with this example use the following imqobjmgr commands to create the requires objects in the context.
imqobjmgr add -t tf -l 'MyConnectionFactory' -j java.naming.provider.url \ =file:///tmp -j java.naming.factory.initial=com.sun.jndi.fscontext.RefFSContextFactory -f imqobjmgr add -t t -l 'ehcache' -o 'imqDestinationName=EhcacheTopicDest' -j java.naming.provider.url\ =file:///tmp -j java.naming.factory.initial=com.sun.jndi.fscontext.RefFSContextFactory -f
This is the same as configuring any of the cache replicators. The class should be net.sf.ehcache.distribution.jms.JMSCacheReplicatorFactory.
See the following example:
<cache name="sampleCacheAsync"
maxElementsInMemory="1000"
eternal="false"
timeToIdleSeconds="1000"
timeToLiveSeconds="1000"
overflowToDisk="false">
<cacheEventListenerFactory
class="net.sf.ehcache.distribution.jms.JMSCacheReplicatorFactory"
properties="replicateAsynchronously=true,
replicatePuts=true,
replicateUpdates=true,
replicateUpdatesViaCopy=true,
replicateRemovals=true,
asynchronousReplicationIntervalMillis=1000"
propertySeparator=","/>
</cache>
Anything that can publish to a message queue can also add cache entries to ehcache. These are called non-cache publishers.
Publishers need to set up to four String properties on each message: cacheName, action, mimeType and key.
A JMS message property which contains the name of the cache to operate on.
If no cacheName is set the message will be ignored. A warning log message will indicate that the message has been ignored.
A JMS message property which contains the action to perform on the cache.
Available actions are strings labeled PUT, REMOVE and REMOVE_ALL.
If not set no action is performed. A warning log message will indicate that the message has been ignored.
A JMS message property which contains the mimeType of the message. Applies to the PUT action. If not set the message is interpreted as follows:
ObjectMessage - if it is an net.sf.ehcache.Element, then it is treated as such and stored in the cache.
For other objects, a new Element is created using the object in the ObjectMessage as the value and the key property as a key. Because objects are already typed, the mimeType is ignored.
TextMessage - Stored in the cache as value of MimeTypeByteArray. The mimeType should be specified. If not specified it is stored as type text/plain.
BytesMessage - Stored in the cache as value of MimeTypeByteArray. The mimeType should be specified. If not specified it is stored as type application/octet-stream.
Other message types are not supported.
To send XML use a TextMessage or BytesMessage and set the mimeType to application/xml.It will be stored in the cache as a value of MimeTypeByteArray.
The REMOVE and REMOVE_ALL actions do not require a mimeType property.
The key in the cache on which to operate on. The key is of type String.
The REMOVE_ALL action does not require a key property.
If an ObjectMessage of type net.sf.ehcache.Element is sent, the key is contained in the element. Any key set as a property is ignored.
If the key is required but not provided, a warning log message will indicate that the message has been ignored.
These samples use Open MQ as the message queue and use it with out of the box defaults. They are heavily based on Ehcache's own JMS integration tests. See the test source for more details.
Messages should be sent to the topic that Ehcache is listening on. In these samples it is EhcacheTopicDest.
All samples get a Topic Connection using the following method:
private TopicConnection getMQConnection() throws JMSException {
com.sun.messaging.ConnectionFactory factory = new com.sun.messaging.ConnectionFactory();
factory.setProperty(ConnectionConfiguration.imqAddressList, "localhost:7676");
factory.setProperty(ConnectionConfiguration.imqReconnectEnabled, "true");
TopicConnection myConnection = factory.createTopicConnection();
return myConnection;
}String payload = "this is an object";
TopicConnection connection = getMQConnection();
connection.start();
TopicSession publisherSession =
connection.createTopicSession(false, Session.AUTO_ACKNOWLEDGE);
ObjectMessage message = publisherSession.createObjectMessage(payload);
message.setStringProperty(ACTION_PROPERTY, "PUT");
message.setStringProperty(CACHE_NAME_PROPERTY, "sampleCacheAsync");
//don't set. Should work.
//message.setStringProperty(MIME_TYPE_PROPERTY, null);
//should work. Key should be ignored when sending an element.
message.setStringProperty(KEY_PROPERTY, "1234");
Topic topic = publisherSession.createTopic("EhcacheTopicDest");
TopicPublisher publisher = publisherSession.createPublisher(topic);
publisher.send(message);
connection.stop();Ehcache will create an Element in cache "sampleCacheAsync" with key "1234" and a Java class String value of "this is an object".
TopicConnection connection = getMQConnection();
connection.start();
TopicSession publisherSession = connection.createTopicSession(false,
Session.AUTO_ACKNOWLEDGE);
String value = "<?xml version=\"1.0\"?>\n" +
"<oldjoke>\n" +
"<burns>Say <quote>goodnight</quote>,\n" +
"Gracie.</burns>\n" +
"<allen><quote>Goodnight, \n" +
"Gracie.</quote></allen>\n" +
"<applause/>\n" +
"</oldjoke>";
TextMessage message = publisherSession.createTextMessage(value);
message.setStringProperty(ACTION_PROPERTY, "PUT");
message.setStringProperty(CACHE_NAME_PROPERTY, "sampleCacheAsync");
message.setStringProperty(MIME_TYPE_PROPERTY, "application/xml");
message.setStringProperty(KEY_PROPERTY, "1234");
Topic topic = publisherSession.createTopic("EhcacheTopicDest");
TopicPublisher publisher = publisherSession.createPublisher(topic);
publisher.send(message);
connection.stop();Ehcache will create an Element in cache "sampleCacheAsync" with key "1234" and a value of type MimeTypeByteArray.
On a get from the cache the MimeTypeByteArray will be returned. It is an Ehcache value object from which a mimeType and byte[] can be retrieved. The mimeType will be "application/xml". The byte[] will contain the XML String encoded in bytes, using the platform's default charset.
byte[] bytes = new byte[]{0x34, (byte) 0xe3, (byte) 0x88};
TopicConnection connection = getMQConnection();
connection.start();
TopicSession publisherSession = connection.createTopicSession(false,
Session.AUTO_ACKNOWLEDGE);
BytesMessage message = publisherSession.createBytesMessage();
message.writeBytes(bytes);
message.setStringProperty(ACTION_PROPERTY, "PUT");
message.setStringProperty(CACHE_NAME_PROPERTY, "sampleCacheAsync");
message.setStringProperty(MIME_TYPE_PROPERTY, "application/octet-stream");
message.setStringProperty(KEY_PROPERTY, "1234");
Topic topic = publisherSession.createTopic("EhcacheTopicDest");
TopicPublisher publisher = publisherSession.createPublisher(topic);
publisher.send(message);Ehcache will create an Element in cache "sampleCacheAsync" with key "1234" in and a value of type MimeTypeByteArray.
On a get from the cache the MimeTypeByteArray will be returned. It is an Ehcache value object from which a mimeType and byte[] can be retrieved. The mimeType will be "application/octet-stream". The byte[] will contain the original bytes.
TopicConnection connection = getMQConnection();
connection.start();
TopicSession publisherSession = connection.createTopicSession(false, Session.AUTO_ACKNOWLEDGE);
ObjectMessage message = publisherSession.createObjectMessage();
message.setStringProperty(ACTION_PROPERTY, "REMOVE");
message.setStringProperty(CACHE_NAME_PROPERTY, "sampleCacheAsync");
message.setStringProperty(KEY_PROPERTY, "1234");
Topic topic = publisherSession.createTopic("EhcacheTopicDest");
TopicPublisher publisher = publisherSession.createPublisher(topic);
publisher.send(message);Ehcache will remove the Element with key "1234" from cache "sampleCacheAsync" from the cluster.
TopicConnection connection = getMQConnection();
connection.start();
TopicSession publisherSession = connection.createTopicSession(false,
Session.AUTO_ACKNOWLEDGE);
ObjectMessage message = publisherSession.createObjectMessage();
message.setStringProperty(ACTION_PROPERTY, "REMOVE_ALL");
message.setStringProperty(CACHE_NAME_PROPERTY, "sampleCacheAsync");
Topic topic = publisherSession.createTopic("EhcacheTopicDest");
TopicPublisher publisher = publisherSession.createPublisher(topic);
publisher.send(message);
connection.stop();Ehcache will remove all Elements from cache "sampleCacheAsync" in the cluster.
The JMSCacheLoader is a CacheLoader which loads objects into the cache by sending requests to a JMS Queue.
The loader places an ObjectMessage of type JMSEventMessage on the getQueue with an Action of type GET.
It is configured with the following String properties, loaderArgument.
The defaultLoaderArgument, or the loaderArgument if specified on the load request. To work with the JMSCacheManagerPeerProvider this should be the name of the cache to load from. For custom responders, it can be anything which has meaning to the responder.
A queue responder will respond to the request. You can either create your own or use the one built-into the JMSCacheManagerPeerProviderFactory, which attempts to load the queue from its cache.
The JMSCacheLoader uses JNDI to maintain message queue independence. Refer to the manual for full configuration examples using ActiveMQ and Open Message Queue.
It is configured as per the following example:
<cacheLoaderFactory class="net.sf.ehcache.distribution.jms.JMSCacheLoaderFactory" properties="initialContextFactoryName=com.sun.jndi.fscontext.RefFSContextFactory, providerURL=file:///tmp, replicationTopicConnectionFactoryBindingName=MyConnectionFactory, replicationTopicBindingName=ehcache, getQueueConnectionFactoryBindingName=queueConnectionFactory, getQueueBindingName=ehcacheGetQueue, timeoutMillis=20000 defaultLoaderArgument=/>
Valid properties are:
<cache name="sampleCacheNorep"
maxElementsInMemory="1000"
eternal="false"
timeToIdleSeconds="1000"
timeToLiveSeconds="1000"
overflowToDisk="false">
<cacheEventListenerFactory
class="net.sf.ehcache.distribution.jms.JMSCacheReplicatorFactory"
properties="replicateAsynchronously=false, replicatePuts=false,
replicateUpdates=false, replicateUpdatesViaCopy=false,
replicateRemovals=false, loaderArgument=sampleCacheNorep"
propertySeparator=","/>
<cacheLoaderFactory class="net.sf.ehcache.distribution.jms.JMSCacheLoaderFactory"
properties="initialContextFactoryName=net.sf.ehcache.distribution.jms.
TestActiveMQInitialContextFactory,
providerURL=tcp://localhost:61616,
replicationTopicConnectionFactoryBindingName=topicConnectionFactory,
getQueueConnectionFactoryBindingName=queueConnectionFactory,
replicationTopicBindingName=ehcache,
getQueueBindingName=ehcacheGetQueue,
timeoutMillis=10000"/>
</cache><cache name="sampleCacheNorep"
maxElementsInMemory="1000"
eternal="false"
timeToIdleSeconds="100000"
timeToLiveSeconds="100000"
overflowToDisk="false">
<cacheEventListenerFactory
class="net.sf.ehcache.distribution.jms.JMSCacheReplicatorFactory"
properties="replicateAsynchronously=false, replicatePuts=false,
replicateUpdates=false, replicateUpdatesViaCopy=false,
replicateRemovals=false"
propertySeparator=","/>
<cacheLoaderFactory class="net.sf.ehcache.distribution.jms.JMSCacheLoaderFactory"
properties="initialContextFactoryName=com.sun.jndi.fscontext.RefFSContextFactory,
providerURL=file:///tmp,
replicationTopicConnectionFactoryBindingName=MyConnectionFactory,
replicationTopicBindingName=ehcache,
getQueueConnectionFactoryBindingName=queueConnectionFactory,
getQueueBindingName=ehcacheGetQueue,
timeoutMillis=10000,
userName=test,
password=test"/>
</cache>Ehcache replication and cache loading is designed to gracefully degrade if the message queue infrastructure stops. Replicates and loads will fail. But when the message queue comes back, these operations will start up again.
For this to work, the ConnectionFactory used with the specific message queue needs to be configured correctly.
For example, with Open MQ, reconnection is configured as follows:
For greater reliability consider using a message queue cluster. Most message queues support clustering. The cluster configuration is once again placed in the ConnectionFactory configuration.
This open source message queue is tested in integration tests. It works perfectly.
This open source message queue is tested in integration tests. It works perfectly other than having a problem with temporary reply queues which prevents the use of JMSCacheLoader. JMSCacheLoader is not used during replication.
Versions up to an including 0.4 do not work, due to Oracle not supporting the unified API (send) for topics.
Works as reported by a user.
ActiveMQ seems to have a bug in at least ActiveMQ 5.1 where it does not cleanup temporary queues, even though they have been deleted. That bug appears to be long standing but was though to have been fixed.
See:
The JMSCacheLoader uses temporary reply queues when loading. The Active MQ issue is readily reproduced in Ehcache integration testing. Accordingly, use of the JMSCacheLoader with ActiveMQ is not recommended. Open MQ tests fine.
Active MQ works fine for replication.
Websphere Application Server prevents MessageListeners, which are not MDBs, from being created in the container. While this is a general Java EE limitation, most other app servers either are permissive or can be configured to be permissive. WebSphere 4 worked, but 5 and 6 enforce the restriction.
Accordingly the JMS replicator cannot be used with WebSphere 5 and 6.
--- BlockingCache} and SelfPopulatingCache ---
The net.sf.ehcache.constructs package contains some applied caching classes which use the core classes to solve everyday caching problems.
Imagine you have a very busy web site with thousands of concurrent users. Rather than being evenly distributed in what they do, they tend to gravitate to popular pages. These pages are not static, they have dynamic data which goes stale in a few minutes. Or imagine you have collections of data which go stale in a few minutes. In each case the data is extremely expensive to calculate.
Let's say each request thread asks for the same thing. That is a lot of work. Now, add a cache. Get each thread to check the cache; if the data is not there, go and get it and put it in the cache. Now, imagine that there are so many users contending for the same data that in the time it takes the first user to request the data and put it in the cache, 10 other users have done the same thing. The upstream system, whether a JSP or velocity page, or interactions with a service layer or database are doing 10 times more work than they need to.
Enter the BlockingCache.

Blocking Cache
It is blocking because all threads requesting the same key wait for the first thread to complete. Once the first thread has completed the other threads simply obtain the cache entry and return.
The BlockingCache can scale up to very busy systems. Each thread can either wait indefinitely, or you can specify a timeout using the timeoutMillis constructor argument.
You want to use the BlockingCache, but the requirement to always release the lock creates gnarly code. You also want to think about what you are doing without thinking about the caching.
Enter the SelfPopulatingCache. The name SelfPopulatingCache is synonymous with Pull-through cache, which is a common caching term. SelfPopulatingCache though always is in addition to a BlockingCache.
SelfPopulatingCache uses a CacheEntryFactory, that given a key, knows how to populate the entry.
Note: JCache inspired getWithLoader and getAllWithLoader directly in Ehcache which work with a CacheLoader may be used as an alternative to SelfPopulatingCache. --- CacheManager Event Listeners ---
CacheManager event listeners allow implementers to register callback methods that will be executed when a CacheManager event occurs. Cache listeners implement the CacheManagerEventListener interface.
The events include:
Callbacks to these methods are synchronous and unsynchronized. It is the responsibility of the implementer to safely handle the potential performance and thread safety issues depending on what their listener is doing.
One CacheManagerEventListenerFactory and hence one CacheManagerEventListener can be specified per CacheManager instance.
The factory is configured as below:
<cacheManagerEventListenerFactory class="" properties=""/>
The entry specifies a CacheManagerEventListenerFactory which will be used to create a CacheManagerPeerProvider, which is notified when Caches are added or removed from the CacheManager.
The attributes of CacheManagerEventListenerFactory are:
Callbacks to listener methods are synchronous and unsynchronized. It is the responsibility of the implementer to safely handle the potential performance and thread safety issues depending on what their listener is doing.
If no class is specified, or there is no cacheManagerEventListenerFactory element, no listener is created. There is no default.
CacheManagerEventListenerFactory is an abstract factory for creating cache manager listeners. Implementers should provide their own concrete factory extending this abstract factory. It can then be configured in ehcache.xml.
The factory class needs to be a concrete subclass of the abstract factory CacheManagerEventListenerFactory, which is reproduced below:
/**
* An abstract factory for creating {@link CacheManagerEventListener}s. Implementers should
* provide their own concrete factory extending this factory. It can then be configured in
* ehcache.xml
*
* @author Greg Luck
* @version $Id: cachemanager_event_listeners.apt 1961 2010-03-02 19:03:27Z gluck $
* @see "http://ehcache.org/documentation/cachemanager_event_listeners.html"
*/
public abstract class CacheManagerEventListenerFactory {
/**
* Create a <code>CacheEventListener</code>
*
* @param properties implementation specific properties. These are configured as comma
* separated name value pairs in ehcache.xml. Properties may be null
* @return a constructed CacheManagerEventListener
*/
public abstract CacheManagerEventListener
createCacheManagerEventListener(Properties properties);
}
The factory creates a concrete implementation of CacheManagerEventListener, which is reproduced below:
/**
* Allows implementers to register callback methods that will be executed when a
* <code>CacheManager</code> event occurs.
* The events include:
* <ol>
* <li>adding a <code>Cache</code>
* <li>removing a <code>Cache</code>
* </ol>
* <p/>
* Callbacks to these methods are synchronous and unsynchronized. It is the responsibility of
* the implementer to safely handle the potential performance and thread safety issues
* depending on what their listener is doing.
* @author Greg Luck
* @version $Id: cachemanager_event_listeners.apt 1961 2010-03-02 19:03:27Z gluck $
* @since 1.2
* @see CacheEventListener
*/
public interface CacheManagerEventListener {
/**
* Called immediately after a cache has been added and activated.
* <p/>
* Note that the CacheManager calls this method from a synchronized method. Any attempt to
* call a synchronized method on CacheManager from this method will cause a deadlock.
* <p/>
* Note that activation will also cause a CacheEventListener status change notification
* from {@link net.sf.ehcache.Status#STATUS_UNINITIALISED} to
* {@link net.sf.ehcache.Status#STATUS_ALIVE}. Care should be taken on processing that
* notification because:
* <ul>
* <li>the cache will not yet be accessible from the CacheManager.
* <li>the addCaches methods whih cause this notification are synchronized on the
* CacheManager. An attempt to call {@link net.sf.ehcache.CacheManager#getCache(String)}
* will cause a deadlock.
* </ul>
* The calling method will block until this method returns.
* <p/>
* @param cacheName the name of the <code>Cache</code> the operation relates to
* @see CacheEventListener
*/
void notifyCacheAdded(String cacheName);
/**
* Called immediately after a cache has been disposed and removed. The calling method will
* block until this method returns.
* <p/>
* Note that the CacheManager calls this method from a synchronized method. Any attempt to
* call a synchronized method on CacheManager from this method will cause a deadlock.
* <p/>
* Note that a {@link CacheEventListener} status changed will also be triggered. Any
* attempt from that notification to access CacheManager will also result in a deadlock.
* @param cacheName the name of the <code>Cache</code> the operation relates to
*/
void notifyCacheRemoved(String cacheName);
}The implementations need to be placed in the classpath accessible to ehcache. Ehcache uses the ClassLoader returned by Thread.currentThread().getContextClassLoader() to load classes.
--- Cache Loaders ---
A CacheLoader is an interface which specifies load and loadAll methods with a variety of parameters.
CacheLoaders come from JCache, but are a frequently requested feature, so they have been incorporated into the core Ehcache classes and can be configured in ehcache.xml.
CacheLoaders are invoked in the following Cache methods:
They are also invoked in similar (though slightly differently named) JCache methods.
The methods will invoke a CacheLoader if there is no entry for the key or keys requested. By implementing CacheLoader, an application form of loading can take place. The get... methods follow the pull-through cache pattern. The load... methods are useful as cache warmers.
CacheLoaders are similar to the CacheEntryFactory used in SelfPopulatingCache. However SelfPopulatingCache is a decorator to ehcache. The CacheLoader functionality is available right in a Cache, Ehcache or JCache and follows a more industry standard convention.
CacheLoaders may be set either declaratively in the ehcache.xml configuration file or programmatically. This becomes the default CacheLoader. Some of the methods invoking loaders enable an override CacheLoader to be passed in as a parameter.
More than one cacheLoader can be registered, in which case the loaders form a chain which are executed in order. If a loader returns null, the next in chain is called.
cacheLoaderFactory - Specifies a CacheLoader, which can be used both asynchronously and synchronously to load objects into a cache. More than one cacheLoaderFactory element can be added, in which case the loaders form a chain which are executed in order. If a loader returns null, the next in chain is called.
<cache ...>
<cacheLoaderFactory class="com.example.ExampleCacheLoaderFactory"
properties="type=int,startCounter=10"/>
</cache>
CacheLoaderFactory is an abstract factory for creating CacheLoaders. Implementers should provide their own concrete factory, extending this abstract factory. It can then be configured in ehcache.xml
The factory class needs to be a concrete subclass of the abstract factory class CacheLoaderFactory, which is reproduced below:
/**
* An abstract factory for creating cache loaders. Implementers should provide their own
* concrete factory extending this factory.
* <p/>
* There is one factory method for JSR107 Cache Loaders and one for Ehcache ones. The Ehcache
* loader is a sub interface of the JSR107 Cache Loader.
* <p/>
* Note that both the JCache and Ehcache APIs also allow the CacheLoader to be set
* programmatically.
* @author Greg Luck
* @version $Id: cache_loaders.apt 1512 2009-12-11 02:15:16Z gluck $
*/
public abstract class CacheLoaderFactory {
/**
* Creates a CacheLoader using the JSR107 creational mechanism.
* This method is called from {@link net.sf.ehcache.jcache.JCacheFactory}
*
* @param environment the same environment passed into
* {@link net.sf.ehcache.jcache.JCacheFactory}.
* This factory can extract any properties it needs from the environment.
* @return a constructed CacheLoader
*/
public abstract net.sf.jsr107cache.CacheLoader createCacheLoader(Map environment);
/**
* Creates a CacheLoader using the Ehcache configuration mechanism at the time
* the associated cache is created.
*
* @param properties implementation specific properties. These are configured as comma
* separated name value pairs in ehcache.xml
* @return a constructed CacheLoader
*/
public abstract net.sf.ehcache.loader.CacheLoader createCacheLoader(Properties properties);
/**
* @param cache the cache this extension should hold a reference to,
* and to whose lifecycle it should be bound.
* @param properties implementation specific properties configured as delimiter
* separated name value pairs in ehcache.xml
* @return a constructed CacheLoader
*/
public abstract CacheLoader createCacheLoader(Ehcache cache, Properties properties);
}The factory creates a concrete implementation of the CacheLoader interface, which is reproduced below.
A CacheLoader is bound to the lifecycle of a cache, so that init() is called during cache initialization, and dispose() is called on disposal of a cache.
/**
* Extends JCache CacheLoader with load methods that take an argument in addition to a key
* @author Greg Luck
* @version $Id: cache_loaders.apt 1512 2009-12-11 02:15:16Z gluck $
*/
public interface CacheLoader extends net.sf.jsr107cache.CacheLoader {
/**
* Load using both a key and an argument.
* <p/>
* JCache will call through to the load(key) method, rather than this method,
* where the argument is null.
*
* @param key the key to load the object for
* @param argument can be anything that makes sense to the loader
* @return the Object loaded
* @throws CacheException
*/
Object load(Object key, Object argument) throws CacheException;
/**
* Load using both a key and an argument.
* <p/>
* JCache will use the loadAll(key) method where the argument is null.
*
* @param keys the keys to load objects for
* @param argument can be anything that makes sense to the loader
* @return a map of Objects keyed by the collection of keys passed in.
* @throws CacheException
*/
Map loadAll(Collection keys, Object argument) throws CacheException;
/**
* Gets the name of a CacheLoader
*
* @return the name of this CacheLoader
*/
String getName();
/**
* Creates a clone of this extension. This method will only be called by Ehcache before a
* cache is initialized.
* <p/>
* Implementations should throw CloneNotSupportedException if they do not support clone
* but that will stop them from being used with defaultCache.
*
* @return a clone
* @throws CloneNotSupportedException if the extension could not be cloned.
*/
public CacheLoader clone(Ehcache cache) throws CloneNotSupportedException;
/**
* Notifies providers to initialise themselves.
* <p/>
* This method is called during the Cache's initialise method after it has changed it's
* status to alive. Cache operations are legal in this method.
*
* @throws net.sf.ehcache.CacheException
*/
void init();
/**
* Providers may be doing all sorts of exotic things and need to be able to clean up on
* dispose.
* <p/>
* Cache operations are illegal when this method is called. The cache itself is partly
* disposed when this method is called.
*
* @throws net.sf.ehcache.CacheException
*/
void dispose() throws net.sf.ehcache.CacheException;
/**
* @return the status of the extension
*/
public Status getStatus();
}
The implementations need to be placed in the classpath accessible to ehcache.
See the chapter on Classloading for details on how classloading of these classes will be done.
The following methods on Cache allow runtime interrogation, registration and unregistration of loaders:
/**
* Register a {@link CacheLoader} with the cache. It will then be tied into the cache
* lifecycle.
* <p/>
* If the CacheLoader is not initialised, initialise it.
*
* @param cacheLoader A Cache Loader to register
*/
public void registerCacheLoader(CacheLoader cacheLoader) {
registeredCacheLoaders.add(cacheLoader);
}
/**
* Unregister a {@link CacheLoader} with the cache. It will then be detached from the cache
* lifecycle.
*
* @param cacheLoader A Cache Loader to unregister
*/
public void unregisterCacheLoader(CacheLoader cacheLoader) {
registeredCacheLoaders.remove(cacheLoader);
}
/**
* @return the cache loaders as a live list
*/
public List<CacheLoader> getRegisteredCacheLoaders() {
return registeredCacheLoaders;
}--- Cache Event Listeners ---
Cache listeners allow implementers to register callback methods that will be executed when a cache event occurs. Cache listeners implement the CacheEventListener interface.
The events include:
Callbacks to these methods are synchronous and unsynchronized. It is the responsibility of the implementer to safely handle the potential performance and thread safety issues depending on what their listener is doing.
Listeners are guaranteed to be notified of events in the order in which they occurred.
Elements can be put or removed from a Cache without notifying listeners by using the putQuiet and removeQuiet methods.
In clustered environments event propagation can be
configured to be propagated only locally, only remotely, or both. The default
is both, to be backwardly
compatible.
Cache event listeners are configured per cache. Each cache can have multiple listeners.
Each listener is configured by adding a cacheManagerEventListenerFactory element as follows:
<cache ...> <cacheEventListenerFactory class="" properties="" listenFor=""/> ... </cache>
The entry specifies a CacheManagerEventListenerFactory which is used to create a CachePeerProvider, which then receives notifications.
The attributes of CacheManagerEventListenerFactory are:
These are the possible values:
Callbacks to listener methods are synchronous and unsynchronized. It is the responsibility of the implementer to safely handle the potential performance and thread safety issues depending on what their listener is doing.
CacheEventListenerFactory is an abstract factory for creating cache event listeners. Implementers should provide their own concrete factory, extending this abstract factory. It can then be configured in ehcache.xml
The factory class needs to be a concrete subclass of the abstract factory class CacheEventListenerFactory, which is reproduced below:
/**
* An abstract factory for creating listeners. Implementers should provide their own
* concrete factory extending this factory. It can then be configured in ehcache.xml
*
* @author Greg Luck
* @version $Id: cache_event_listeners.apt 1961 2010-03-02 19:03:27Z gluck $
*/
public abstract class CacheEventListenerFactory {
/**
* Create a <code>CacheEventListener</code>
*
* @param properties implementation specific properties. These are configured as comma
* separated name value pairs in ehcache.xml
* @return a constructed CacheEventListener
*/
public abstract CacheEventListener createCacheEventListener(Properties properties);
}The factory creates a concrete implementation of the CacheEventListener interface, which is reproduced below:
/**
* Allows implementers to register callback methods that will be executed when a cache event
* occurs.
* The events include:
* <ol>
* <li>put Element
* <li>update Element
* <li>remove Element
* <li>an Element expires, either because timeToLive or timeToIdle has been reached.
* </ol>
* <p/>
* Callbacks to these methods are synchronous and unsynchronized. It is the responsibility of
* the implementer to safely handle the potential performance and thread safety issues
* depending on what their listener is doing.
* <p/>
* Events are guaranteed to be notified in the order in which they occurred.
* <p/>
* Cache also has putQuiet and removeQuiet methods which do not notify listeners.
*
* @author Greg Luck
* @version $Id: cache_event_listeners.apt 1961 2010-03-02 19:03:27Z gluck $
* @see CacheManagerEventListener
* @since 1.2
*/
public interface CacheEventListener extends Cloneable {
/**
* Called immediately after an element has been removed. The remove method will block until
* this method returns.
* <p/>
* Ehcache does not chech for
* <p/>
* As the {@link net.sf.ehcache.Element} has been removed, only what was the key of the
* element is known.
* <p/>
*
* @param cache the cache emitting the notification
* @param element just deleted
*/
void notifyElementRemoved(final Ehcache cache, final Element element) throws CacheException;
/**
* Called immediately after an element has been put into the cache. The
* {@link net.sf.ehcache.Cache#put(net.sf.ehcache.Element)} method
* will block until this method returns.
* <p/>
* Implementers may wish to have access to the Element's fields, including value, so the
* element is provided. Implementers should be careful not to modify the element. The
* effect of any modifications is undefined.
*
* @param cache the cache emitting the notification
* @param element the element which was just put into the cache.
*/
void notifyElementPut(final Ehcache cache, final Element element) throws CacheException;
/**
* Called immediately after an element has been put into the cache and the element already
* existed in the cache. This is thus an update.
* <p/>
* The {@link net.sf.ehcache.Cache#put(net.sf.ehcache.Element)} method
* will block until this method returns.
* <p/>
* Implementers may wish to have access to the Element's fields, including value, so the
* element is provided. Implementers should be careful not to modify the element. The
* effect of any modifications is undefined.
*
* @param cache the cache emitting the notification
* @param element the element which was just put into the cache.
*/
void notifyElementUpdated(final Ehcache cache, final Element element) throws CacheException;
/**
* Called immediately after an element is <i>found</i> to be expired. The
* {@link net.sf.ehcache.Cache#remove(Object)} method will block until this method returns.
* <p/>
* As the {@link Element} has been expired, only what was the key of the element is known.
* <p/>
* Elements are checked for expiry in Ehcache at the following times:
* <ul>
* <li>When a get request is made
* <li>When an element is spooled to the diskStore in accordance with a MemoryStore
* eviction policy
* <li>In the DiskStore when the expiry thread runs, which by default is
* {@link net.sf.ehcache.Cache#DEFAULT_EXPIRY_THREAD_INTERVAL_SECONDS}
* </ul>
* If an element is found to be expired, it is deleted and this method is notified.
*
* @param cache the cache emitting the notification
* @param element the element that has just expired
* <p/>
* Deadlock Warning: expiry will often come from the <code>DiskStore</code>
* expiry thread. It holds a lock to the DiskStorea the time the
* notification is sent. If the implementation of this method calls into a
* synchronized <code>Cache</code> method and that subsequently calls into
* DiskStore a deadlock will result. Accordingly implementers of this method
* should not call back into Cache.
*/
void notifyElementExpired(final Ehcache cache, final Element element);
/**
* Give the replicator a chance to cleanup and free resources when no longer needed
*/
void dispose();
/**
* Creates a clone of this listener. This method will only be called by Ehcache before a
* cache is initialized.
* <p/>
* This may not be possible for listeners after they have been initialized. Implementations
* should throw CloneNotSupportedException if they do not support clone.
* @return a clone
* @throws CloneNotSupportedException if the listener could not be cloned.
*/
public Object clone() throws CloneNotSupportedException;
}The implementations need to be placed in the classpath accessible to Ehcache.
See the chapter on Classloading for details on how classloading of these classes will be done.
--- Cache Exception Handlers ---
By default, most cache operations will propagate a runtime CacheException on failure. An interceptor, using a dynamic proxy, may be configured so that a CacheExceptionHandler can be configured to intercept Exceptions. Errors are not intercepted.
Caches with ExceptionHandling configured are of type Ehcache. To get the exception handling behaviour they must be referenced using CacheManager.getEhcache(), not CacheManager.getCache(), which returns the underlying undecorated cache.
CacheExceptionHandlers may be set either declaratively in the ehcache.xml configuration file or programmatically.
Cache event listeners are configured per cache. Each cache can have at most one exception handler.
An exception handler is configured by adding a cacheExceptionHandlerFactory element as shown in the following example:
<cache ...>
<cacheExceptionHandlerFactory
class="net.sf.ehcache.exceptionhandler.CountingExceptionHandlerFactory"
properties="logLevel=FINE"/>
</cache>
CacheExceptionHandlerFactory is an abstract factory for creating cache exception handlers. Implementers should provide their own concrete factory, extending this abstract factory. It can then be configured in ehcache.xml
The factory class needs to be a concrete subclass of the abstract factory class CacheExceptionHandlerFactory, which is reproduced below:
/**
* An abstract factory for creating <code>CacheExceptionHandler</code>s at configuration
* time, in ehcache.xml.
* <p/>
* Extend to create a concrete factory
*
* @author <a href="mailto:gluck@gregluck.com">Greg Luck</a>
* @version $Id: cache_exception_handlers.apt 1512 2009-12-11 02:15:16Z gluck $
*/
public abstract class CacheExceptionHandlerFactory {
/**
* Create an <code>CacheExceptionHandler</code>
*
* @param properties implementation specific properties. These are configured as comma
* separated name value pairs in ehcache.xml
* @return a constructed CacheExceptionHandler
*/
public abstract CacheExceptionHandler createExceptionHandler(Properties properties);
}
The factory creates a concrete implementation of the CacheExceptionHandler interface, which is reproduced below:
/**
* A handler which may be registered with an Ehcache, to handle exception on Cache operations.
* <p/>
* Handlers may be registered at configuration time in ehcache.xml, using a
* CacheExceptionHandlerFactory, or * set at runtime (a strategy).
* <p/>
* If an exception handler is registered, the default behaviour of throwing the exception
* will not occur. The handler * method <code>onException</code> will be called. Of course, if
* the handler decides to throw the exception, it will * propagate up through the call stack.
* If the handler does not, it won't.
* <p/>
* Some common Exceptions thrown, and which therefore should be considered when implementing
* this class are listed below:
* <ul>
* <li>{@link IllegalStateException} if the cache is not
* {@link net.sf.ehcache.Status#STATUS_ALIVE}
* <li>{@link IllegalArgumentException} if an attempt is made to put a null
* element into a cache
* <li>{@link net.sf.ehcache.distribution.RemoteCacheException} if an issue occurs
* in remote synchronous replication
* <li>
* <li>
* </ul>
*
* @author <a href="mailto:gluck@gregluck.com">Greg Luck</a>
* @version $Id: cache_exception_handlers.apt 1512 2009-12-11 02:15:16Z gluck $
*/
public interface CacheExceptionHandler {
/**
* Called if an Exception occurs in a Cache method. This method is not called
* if an <code>Error</code> occurs.
*
* @param Ehcache the cache in which the Exception occurred
* @param key the key used in the operation, or null if the operation does not use a
* key or the key was null
* @param exception the exception caught
*/
void onException(Ehcache ehcache, Object key, Exception exception);
}The implementations need to be placed in the classpath accessible to Ehcache.
See the chapter on Classloading for details on how classloading of these classes will be done.
The following example shows how to add exception handling to a cache then adding the cache back into cache manager so that all clients obtain the cache handling decoration.
CacheManager cacheManager = ...
Ehcache cache = cacheManger.getCache("exampleCache");
ExceptionHandler handler = new ExampleExceptionHandler(...);
cache.setCacheLoader(handler);
Ehcache proxiedCache = ExceptionHandlingDynamicCacheProxy.createProxy(cache);
cacheManager.replaceCacheWithDecoratedCache(cache, proxiedCache);--- Cache Extensions ---
CacheExtensions are a general purpose mechanism to allow generic extensions to a Cache.
CacheExtensions are tied into the Cache lifecycle. For that reason this interface has the lifecycle methods.
CacheExtensions are created using the CacheExtensionFactory which has a codecreateCacheCacheExtension()/code method which takes as a parameter a Cache and properties. It can thus call back into any public method on Cache, including, of course, the load methods.
CacheExtensions are suitable for timing services, where you want to create a timer to perform cache operations. The other way of adding Cache behaviour is to decorate a cache.
See @link net.sf.ehcache.constructs.blocking.BlockingCache for an example of how to do this.
Because a CacheExtension holds a reference to a Cache, the CacheExtension can do things such as registering a CacheEventListener or even a CacheManagerEventListener, all from within a CacheExtension, creating more opportunities for customisation.
Cache extension are configured per cache. Each cache can have zero or more.
A CacheExtension is configured by adding a cacheExceptionHandlerFactory element as shown in the following example:
<cache ...>
<cacheExtensionFactory class="com.example.FileWatchingCacheRefresherExtensionFactory"
properties="refreshIntervalMillis=18000, loaderTimeout=3000,
flushPeriod=whatever, someOtherProperty=someValue ..."/>
</cache>
CacheExtensionFactory is an abstract factory for creating cache extension. Implementers should provide their own concrete factory, extending this abstract factory. It can then be configured in ehcache.xml
The factory class needs to be a concrete subclass of the abstract factory class CacheExtensionFactory, which is reproduced below:
/**
* An abstract factory for creating <code>CacheExtension</code>s. Implementers should
* provide their own * concrete factory extending this factory. It can then be configured
* in ehcache.xml.
*
* @author <a href="mailto:gluck@gregluck.com">Greg Luck</a>
* @version $Id: cache_extensions.apt 1512 2009-12-11 02:15:16Z gluck $
*/
public abstract class CacheExtensionFactory {
/**
* @param cache the cache this extension should hold a reference to, and to whose
* lifecycle it should be bound.
* @param properties implementation specific properties configured as delimiter separated
* name value pairs in ehcache.xml
*/
public abstract CacheExtension createCacheExtension(Ehcache cache, Properties properties);
}
The factory creates a concrete implementation of the CacheExtension interface, which is reproduced below:
/**
* This is a general purpose mechanism to allow generic extensions to a Cache.
* <p/>
* CacheExtensions are tied into the Cache lifecycle. For that reason this interface has the
* lifecycle methods.
* <p/>
* CacheExtensions are created using the CacheExtensionFactory which has a
* <code>createCacheCacheExtension()</code> method which takes as a parameter a Cache and
* properties. It can thus call back into any public method on Cache, including, of course,
* the load methods.
* <p/>
* CacheExtensions are suitable for timing services, where you want to create a timer to
* perform cache operations. The other way of adding Cache behaviour is to decorate a cache.
* See {@link net.sf.ehcache.constructs.blocking.BlockingCache} for an example of how to do
* this.
* <p/>
* Because a CacheExtension holds a reference to a Cache, the CacheExtension can do things
* such as registering a CacheEventListener or even a CacheManagerEventListener, all from
* within a CacheExtension, creating more opportunities for customisation.
*
* @author <a href="mailto:gluck@gregluck.com">Greg Luck</a>
* @version $Id: cache_extensions.apt 1512 2009-12-11 02:15:16Z gluck $
*/
public interface CacheExtension {
/**
* Notifies providers to initialise themselves.
* <p/>
* This method is called during the Cache's initialise method after it has changed it's
* status to alive. Cache operations are legal in this method.
*
* @throws CacheException
*/
void init();
/**
* Providers may be doing all sorts of exotic things and need to be able to clean up on
* dispose.
* <p/>
* Cache operations are illegal when this method is called. The cache itself is partly
* disposed when this method is called.
*
* @throws CacheException
*/
void dispose() throws CacheException;
/**
* Creates a clone of this extension. This method will only be called by Ehcache before a
* cache is initialized.
* <p/>
* Implementations should throw CloneNotSupportedException if they do not support clone
* but that will stop them from being used with defaultCache.
*
* @return a clone
* @throws CloneNotSupportedException if the extension could not be cloned.
*/
public CacheExtension clone(Ehcache cache) throws CloneNotSupportedException;
/**
* @return the status of the extension
*/
public Status getStatus();
}
The implementations need to be placed in the classpath accessible to ehcache.
See the chapter on Classloading for details on how class loading of these classes will be done.
Cache Extensions may also be programmatically added to a Cache as shown.
TestCacheExtension testCacheExtension = new TestCacheExtension(cache, ...);
testCacheExtension.init();
cache.registerCacheExtension(testCacheExtension);--- Cache Server ---
Ehcache now comes with a Cache Server, available as a WAR for most web containers, or as a standalone server. The Cache Server has two APIs: RESTful resource oriented, and SOAP. Both support clients in any programming language.
(A Note on terminology: Leonard Richardson and Sam Ruby have done a great job of clarifying the different Web Services architectures and distinguishing them from each other. We use their taxonomy in describing web services. See http://www.oreilly.com/catalog/9780596529260/.)
Roy Fielding coined the acronym REST, denoting Representational State Transfer, in his PhD thesis.
The Ehcache implementation strictly follows the RESTful resource-oriented architecture style.
Specifically:
Roy is on the JSR311 expert group. JSR311 and Jersey, the reference implementation, are used to deliver RESTful web services in Ehcache server.
The Ehcache RESTFul Web Services API exposes the singleton CacheManager, which typically has been configured in ehcache.xml or an IoC container. Multiple CacheManagers are not supported.
Resources are identified using a URI template. The value in parentheses should be substituted with a literal to specify a resource.
Response codes and response headers strictly follow HTTP conventions.
Retrieves the WADL for describing the available CacheManager operations.
Lists the Caches in the CacheManager.
Retrieves the WADL describing the available Cache operations.
Retrieves the same metadata a GET would receive returned as HTTP headers. There is no body returned.
Gets a cache representation. This includes useful metadata such as the configuration and cache statistics.
Creates a Cache using the defaultCache configuration.
Deletes the Cache.
Retrieves the WADL describing the available Element operations.
Retrieves the same metadata a GET would receive returned as HTTP headers. There is no body returned.
Gets the element value.
Gets the element's metadata.
Puts an element into the Cache.
The time to live of new Elements defaults to that for the cache. This may be overridden by setting the HTTP request header ehcacheTimeToLiveSeconds. Values of 0 to 2147483647 are accepted. A value of 0 means eternal.
Deletes the element from the cache.
The resource representation for all elements is *. DELETE/{cache}/* will call <<<cache.removeAll().
We deal with resource representations rather than resources themselves.
When Elements are PUT into the cache, a MIME Type should be set in the request header. The MIME Type is preserved for later use.
The new MimeTypeByteArray is used to store the byte[] and the MimeType in the value field of Element.
Some common MIME Types which are expected to be used by clients are:
| text/plain | Plain text |
| text/xml | Extensible Markup Language. Defined in RFC 3023 |
| application/json | JavaScript Object Notation JSON. Defined in RFC 4627 |
| application/x-java-serialized-object | A serialized Java object |
Because Ehcache is a distributed Java cache, in some configurations the Cache server may contain Java objects that arrived at the Cache server via distributed replication. In this case no MIME Type will be set and the Element will be examined to determine its MIME Type.
Because anything that can be PUT into the cache server must be Serializable, it can also be distributed in a cache cluster i.e. it will be Serializable.
These are RESTful code samples in multiple languages.
These samples use the popular curl command line utility.
This example shows how calling OPTIONS causes Ehcache server to respond with the WADL for that resource
curl --request OPTIONS http://localhost:8080/ehcache/rest/sampleCache2/2
The server responds with:
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<application xmlns="http://research.sun.com/wadl/2006/10">
<resources base="http://localhost:8080/ehcache/rest/">
<resource path="sampleCache2/2">
<method name="HEAD"><response><representation mediaType="
...
</resource>
</resources>
</application>curl --head http://localhost:8080/ehcache/rest/sampleCache2/2
The server responds with:
HTTP/1.1 200 OK X-Powered-By: Servlet/2.5 Server: GlassFish/v3 Last-Modified: Sun, 27 Jul 2008 08:08:49 GMT ETag: "1217146129490" Content-Type: text/plain; charset=iso-8859-1 Content-Length: 157 Date: Sun, 27 Jul 2008 08:17:09 GMT
echo "Hello World" | curl -S -T - http://localhost:8080/ehcache/rest/sampleCache2/3
The server will put Hello World into sampleCache2 using key 3.
curl http://localhost:8080/ehcache/rest/sampleCache2/2
The server responds with:
<?xml version="1.0"?> <oldjoke> <burns>Say <quote>goodnight</quote>, Gracie.</burns> <allen><quote>Goodnight, Gracie.</quote></allen> <applause/>
require 'rubygems'
require 'open-uri'
require 'rexml/document'
response = open('http://localhost:8080/ehcache/rest/sampleCache2/2')
xml = response.read
puts xmlThe server responds with:
<?xml version="1.0"?> <oldjoke> <burns>Say <quote>goodnight</quote>, Gracie.</burns> <allen><quote>Goodnight, Gracie.</quote></allen> <applause/> </oldjoke>
import urllib2
f = urllib2.urlopen('http://localhost:8080/ehcache/rest/sampleCache2/2')
print f.read()The server responds with:
<?xml version="1.0"?> <oldjoke> <burns>Say <quote>goodnight</quote>, Gracie.</burns> <allen><quote>Goodnight, Gracie.</quote></allen> <applause/> </oldjoke>
package samples;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.HttpURLConnection;
import java.net.URL;
/**
* A simple example Java client which uses the built-in java.net.URLConnection.
*
* @author BryantR
* @author Greg Luck
*/
public class ExampleJavaClient {
private static String TABLE_COLUMN_BASE =
"http://localhost:8080/ehcache/rest/tableColumn";
private static String TABLE_COLUMN_ELEMENT =
"http://localhost:8080/ehcache/rest/tableColumn/1";
/**
* Creates a new instance of EHCacheREST
*/
public ExampleJavaClient() {
}
public static void main(String[] args) {
URL url;
HttpURLConnection connection = null;
InputStream is = null;
OutputStream os = null;
int result = 0;
try {
//create cache
URL u = new URL(TABLE_COLUMN_BASE);
HttpURLConnection urlConnection = (HttpURLConnection) u.openConnection();
urlConnection.setRequestMethod("PUT");
int status = urlConnection.getResponseCode();
System.out.println("Status: " + status);
urlConnection.disconnect();
//get cache
url = new URL(TABLE_COLUMN_BASE);
connection = (HttpURLConnection) url.openConnection();
connection.setRequestMethod("GET");
connection.connect();
is = connection.getInputStream();
byte[] response1 = new byte[4096];
result = is.read(response1);
while (result != -1) {
System.out.write(response1, 0, result);
result = is.read(response1);
}
if (is != null) try {
is.close();
} catch (Exception ignore) {
}
System.out.println("reading cache: " + connection.getResponseCode()
+ " " + connection.getResponseMessage());
if (connection != null) connection.disconnect();
//create entry
url = new URL(TABLE_COLUMN_ELEMENT);
connection = (HttpURLConnection) url.openConnection();
connection.setRequestProperty("Content-Type", "text/plain");
connection.setDoOutput(true);
connection.setRequestMethod("PUT");
connection.connect();
String sampleData = "Ehcache is way cool!!!";
byte[] sampleBytes = sampleData.getBytes();
os = connection.getOutputStream();
os.write(sampleBytes, 0, sampleBytes.length);
os.flush();
System.out.println("result=" + result);
System.out.println("creating entry: " + connection.getResponseCode()
+ " " + connection.getResponseMessage());
if (connection != null) connection.disconnect();
//get entry
url = new URL(TABLE_COLUMN_ELEMENT);
connection = (HttpURLConnection) url.openConnection();
connection.setRequestMethod("GET");
connection.connect();
is = connection.getInputStream();
byte[] response2 = new byte[4096];
result = is.read(response2);
while (result != -1) {
System.out.write(response2, 0, result);
result = is.read(response2);
}
if (is != null) try {
is.close();
} catch (Exception ignore) {
}
System.out.println("reading entry: " + connection.getResponseCode()
+ " " + connection.getResponseMessage());
if (connection != null) connection.disconnect();
} catch (Exception e) {
e.printStackTrace();
} finally {
if (os != null) try {
os.close();
} catch (Exception ignore) {
}
if (is != null) try {
is.close();
} catch (Exception ignore) {
}
if (connection != null) connection.disconnect();
}
}
} import java.net.URL
import scala.io.Source.fromInputStream
object ExampleScalaGet extends Application {
val url = new URL("http://localhost:8080/ehcache/rest/sampleCache2/2")
fromInputStream(url.openStream).getLines.foreach(print)
}Run it with:
scala -e ExampleScalaGet
The program outputs:
<?xml version="1.0"?>
<oldjoke>
<burns>Say <quote>goodnight</quote>,
Gracie.</burns>
<allen><quote>Goodnight,
Gracie.</quote></allen>
<applause/><?php $ch = curl_init(); curl_setopt ($ch, CURLOPT_URL, "http://localhost:8080/ehcache/rest/sampleCache2/3"); curl_setopt ($ch, CURLOPT_HEADER, 0); curl_exec ($ch); curl_close ($ch); ?>
The server responds with:
Hello Ingo
<?php
$url = "http://localhost:8080/ehcache/rest/sampleCache2/3";
$localfile = "localfile.txt";
$fp = fopen ($localfile, "r");
$ch = curl_init();
curl_setopt($ch, CURLOPT_VERBOSE, 1);
curl_setopt($ch, CURLOPT_URL, $url);
curl_setopt($ch, CURLOPT_PUT, 1);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
curl_setopt($ch, CURLOPT_INFILE, $fp);
curl_setopt($ch, CURLOPT_INFILESIZE, filesize($localfile));
$http_result = curl_exec($ch);
$error = curl_error($ch);
$http_code = curl_getinfo($ch ,CURLINFO_HTTP_CODE);
curl_close($ch);
fclose($fp);
print $http_code;
print "<br /><br />$http_result";
if ($error) {
print "<br /><br />$error";
}
?>The server responds with:
* About to connect() to localhost port 8080 (#0) * Trying ::1... * connected * Connected to localhost (::1) port 8080 (#0) > PUT /ehcache/rest/sampleCache2/3 HTTP/1.1 Host: localhost:8080 Accept: */* Content-Length: 11 Expect: 100-continue < HTTP/1.1 100 Continue < HTTP/1.1 201 Created < Location: http://localhost:8080/ehcache/rest/sampleCache2/3 < Content-Length: 0 < Server: Jetty(6.1.10) < * Connection #0 to host localhost left intact * Closing connection #0
The RESTful Ehcache Server is designed to achieve massive scaling using data partitioning - all from a RESTful interface. The largest Ehcache single instances run at around 20GB in memory. The largest disk stores run at 100Gb each. Add nodes together, with cache data partitioned across them, to get larger sizes. 50 nodes at 20GB gets you to 1 Terabyte.
Two deployment choices need to be made:
These choices can be mixed and matched with a number of different deployment topologies.

This topology is the simplest. It does not use a load balancer. Each node is accessed directly by the cache client using REST. No redundancy is provided.
The client can be implemented in any language because it is simply a HTTP client.
It must work out a partitioning scheme. Simple key hashing, as used by memcached, is sufficient.
Here is a Java code sample:
String[] cacheservers = new String[]{"cacheserver0.company.com", "cacheserver1.company.com",
"cacheserver2.company.com", "cacheserver3.company.com", "cacheserver4.company.com",
"cacheserver5.company.com"};
Object key = "123231";
int hash = Math.abs(key.hashCode());
int cacheserverIndex = hash % cacheservers.length;
String cacheserver = cacheservers[cacheserverIndex];
Redundancy is added as shown in the above diagram by: Replacing each node with a cluster of two nodes. One of the existing distributed caching options in Ehcache is used to form the cluster. Options in Ehcache 1.5 are RMI and JGroups-based clusters. Ehcache-1.6 will add JMS as a further option. Put each Ehcache cluster behind VIPs on a load balancer.

Many content-switching load balancers support URI routing using some form of regular expressions.
So, you could optionally skip the client-side hashing to achieve partitioning in the load balancer itself.
For example:
/ehcache/rest/sampleCache1/[a-h]* => cluster1 /ehcache/rest/sampleCache1/[i-z]* => cluster2
Things get much more sophisticated with F5 load balancers, which let you create iRules in the TCL language. So rather than regular expression URI routing, you could implement key hashing-based URI routing. Remember in Ehcache's RESTful server, the key forms the last part of the URI. e.g. In the URI http://cacheserver.company.com/ehcache/rest/sampleCache1/3432 , 3432 is the key.
You hash using the last part of the URI.
See http://devcentral.f5.com/Default.aspx?tabid=63&PageID=153&ArticleID=135&articleType=ArticleView for how to implment a URI hashing iRule on F5 load balancers.
The W3C (http://www.w3.org/ is a standards body that defines Web Services as
The World Wide Web is more and more used for application to application communication. The programmatic interfaces made available are referred to as Web services.
They provide a set of recommendations for achieving this. See http://www.w3.org/2002/ws/.
An interoperability organisation, WS-I http://www.ws-i.org/, seeks to achieve interoperabilty between W3C Web Services. The W3C specifications for SOAP and WSDL are required to meet the WS-I definition.
Ehcache is using Glassfish's libraries to provide it's W3C web services. The project known as Metro follows the WS-I definition.
Finally, OASIS (http://oasis-open.org), defines a Web Services Security specification for SOAP: WS-Security. The current version is 1.1. It provides three main security mechanisms: ability to send security tokens as part of a message, message integrity, and message confidentiality.
Ehcache's W3C Web Services support the stricter WS-I definition and use the SOAP and WSDL specfications.
Specifically:
The Ehcache RESTFul Web Services API exposes the singleton CacheManager, which typically has been configured in ehcache.xml or an IoC container. Multiple CacheManagers are not supported.
The API definition is as follows:
By default no security is configured. Because it is simply a Servlet 2.5 web application, it can be secured in all the usual ways by configuration in the web.xml.
In addition the cache server supports the use of XWSS 3.0 to secure the Web Service. See https://xwss.dev.java.net/. All required libraries are packaged in the war for XWSS 3.0.
A sample, commented out server_security_config.xml is provided in the WEB-INF directory. XWSS automatically looks for this configuration file.
A simple example, based on an XWSS example, net.sf.ehcache.server.soap.SecurityEnvironmentHandler, which looks for a password in a System property for a given username is included. This is not recommended for production use but is handy when you are getting started with XWSS.
To use XWSS:
Add configuration in accordance with XWSS to the server_security_config.xml file. Create a class which implements the CallbackHandler interface and provide its fully qualified path in the SecurityEnvironmentHandler element.
The integration test EhcacheWebServiceEndpoint test shows how to use the XWSS client side. On the client side, configuration must be provided in a file called client_security_config.xml must be in the root of the classpath.
To add client credentials into the SOAP request do:
cacheService = new EhcacheWebServiceEndpointService().getEhcacheWebServiceEndpointPort(); //add security credentials ((BindingProvider)cacheService).getRequestContext().put(BindingProvider.USERNAME_PROPERTY, "Ron"); ((BindingProvider)cacheService).getRequestContext().put(BindingProvider.PASSWORD_PROPERTY, "noR"); String result = cacheService.ping();
Java 5 or 6
The standalone server comes with its own embedded Glassfish web container.
The web container must support the Servlet 2.5 specification.
The following web container configuration have been tested:
The server is available as follows:
Download here.
There are two tarball archives in tar.gz format:
The Ehcache Server is in the central Maven repository packaged as type war. Use the following Maven pom snippet:
<dependency>
<groupId>net.sf.ehcache</groupId>
<artifactId>ehcache-server</artifactId>
<version>enter_version_here</version>
<type>war</type>
</dependency>It is also available as a jaronly version, which makes it easier to embed. This version excludes all META-INF and WEB-INF configuration files, and also excludes the ehcache.xml. You need to provide these in your maven project.
<dependency>
<groupId>net.sf.ehcache</groupId>
<artifactId>ehcache-server</artifactId>
<version>enter_version_here</version>
<type>jar</type>
<classifier>jaronly</classifier>
</dependency>Use your Web Container's instructions to install the WAR or include the WAR in your project with Maven's war plugin.
Web Container specific configuration is provided in the WAR as follows:
Tomcat V6 passes all integration tests. It does not require a specific configuration.
Expand the WAR.
Edit the web.xml.
Comment out the RESTful web service section.
Comment out the RESTful web service section.
The ehcache.xml configuration file is located in WEB-INF/classes/ehcache.xml.
Follow the instructions in this config file, or the core Ehcache instructions to configure.
The WAR also comes packaged with a standalone server, based on Glassfish V3 Embedded.
The quick start is:
Configuration is by editing the war/web.xml file as per the instructions for the WAR packaging.
jsvc creates a daemon which returns once the service is started. jsvc works on all common Unix-based operating systems including Linux, Solaris and Mac OS X.
It creates a pid file in the pid directory.
This is a Unix shell script that starts the server as a daemon.
To use jsvc you must install the native binary jsvc from the Apache Commons Daemon project. The source for this is distributed in the bin directory as jsvc.tar.gz. Untar it and follow the instructions for building it or download a binary from the Commons Daemon project.
Convenience shell scripts are provided as follows:
start - daemon_start.sh
stop - daemon_stop.sh
jsvc is designed to integrate with Unix System 5 initialization scripts. (/etc/rc.d)
You can also send Unix signals to it. Meaningful ones for the Ehcache Standalone Server are:
| No | Meaning |
| 1 | HUP |
| 2 | INT |
| 9 | KILL |
| 15 | TERM |
The server is also packaged as an executable jar for developer convenience which will work on all operating systems.
A convenience shell script is provided as follows:
start - startup.sh
From the bin directory you can also invoke the following command directly:
unix - java -jar ../lib/ehcache-standalone-server-0.7.jar 8080 ../war
windows - java -jar ..\lib\ehcache-standalone-server-0.7.jar 8080 ..\warThe CacheServer registers Ehcache MBeans with the platform MBeanServer.
Remote monitoring of the MBeanServer is the responsibility of the Web Container or Application Server vendor.
For example, some instructions for Tomcat are here: https://wiki.internet2.edu/confluence/display/CPD/Monitoring+Tomcat+with+JMX
See your Web Container documentation for how to do this for your web container.
The standalone server automatically exposes the MBeanServer on a port 1 higher than the HTTP listening port.
To connect with JConsole simply fire up JConsole, enter the host in the Remote field and portIn the above example that is
192.168.1.108:8686
Then click Connect.
To see the Ehcache MBeans, click on the Mbeans tab and expand the net.sf.ehcache tree node.
You will see something like the following.

CacheStatistics MBeans in JConsole
Of course, from there you can hook the Cache Server up to your monitoring tool of choice. See the chapter on JMX Management and Monitoring for more information.
Download the ehcache-standalone-server from http://sourceforge.net/projects/ehcache/files/ehcache-server. --- Explicit Locking API ---
This package contains an implementation of an Ehcache which provides for explicit locking, using READ and WRITE locks.
It is possible to get more control over Ehcache's locking behaviour.
This initial version works with Ehcache when used with the Terracotta Server Array.
In standalone ehcache core, there is no locking. The last write wins. This is akin to the READ_UNCOMMITTED isolation level.
In this case the cache is always coherent, akin to READ_COMMITTED isolation level. This package simply gives you more control over when locks are acquired and released. In regular Ehcache if you get an object to read or write it can be changed underneath you while you are performing your application level operations on the object. p/
With this module you can first get the lock for the key, then perform your app level operations preventing anyone else from writing to the object. When the app level operations are completed you put the Element back in the cache and release the lock so that others can now access it.
A READ lock does not prevent other READers from also acquiring a READ lock and reading. A READ lock cannot be obtained if there is an oustanding WRITE lock - it will queue.
A WRITE lock cannot be obtained while there are outstanding READ locks - it will queue.
In each case to avoid locking problems, the lock should be released after use. The lock release should be in a prefinally/pre block.
If before each read, you acquire a READ lock and then before each write you acquire a WRITE lock, then an isolation level akin to READ_COMMITTED is achieved.
Configuring each Hibernate instance with a standalone ehcache will dramatically improve performance. However most production applications use multiple application instances for redundancy and for scalability. Ideally applications are horizontally scalable, where adding more application instances linearly improves throughput.
With an application deployed on multiple nodes, using standalone Ehcache means that each instance holds its own data. On a cache miss on any node, Hibernate will hit the database. As each new node gets added database workload goes up. The solution is to turn on distributed caching.
Ehcache comes with replicated caching via RMI, JGroups or JMS. These replicate without locking and are suitable for databas offload. Generally session.refresh() should be used to check the cache against the database before performing a write that must be correct. Secondly, as each node stores all data, the cache size is limited to a comfortable storage size. Memory size is usually limited by garbage collection. Disk can also be used, but the graphs are serialized which adds overhead and results in duplication in the deserialized object graphs.
Ehcache is also the caching API to the Terracotta Server Array. Reads and writes use cluster wide locks, so when using read write Hibernate caches, the cache data on all nodes will be correct, and it is not necessary to call session.refresh().
Ehcache EX, using a single or redundant Terracotta Server Array server can comfortably store approximately 20GB per stripe. The maxElementsInMemory cache setting is used to apportion a percentage of that in process for added performance, it does not limit the size. Using striping which comes with Ehcache FX, terabyte sized caches are possible. It is possible to cache the entire database with a resulting large database offload.
These scaling decisions can be deferred. The plugin is the same regardless of how it is configured. The optimal deployment can thus be determined during performance testing or based on production experience. Finally a new application can scale as it's use grows without expensive re-architecting.
The Explicit Locking API is in the ehcache-explicitlocking module. Download here.
This feature currently only works with Terracotta Server Array. It needs ehcache-core and ehcache-terracotta. which can be downloaded here.
The
open source Terracotta Server Array kit (which includes ehcache-core and
ehcache-terracotta) can be downloaded
here.

--- Write-through and Write-behind Caching with the CacheWriter ---
Write-through caching is a caching pattern where writes to the
cache cause writes to an underlying resource. The cache acts as a facade to
the underlying resource. With this pattern, it often makes sense to read
through the cache too.
Write-behind caching uses the same client API, however the write happens asynchronously.
Ehcache-2.0 introduces write-through and write-behind caching.
While any resource can sit behind the facade of a w-t cache, such as a file system, or a web service client, the common one is a database. To simplify the discussion, we will use database as the example resource.
The big potential benefit of write-behind is database offload. This can be achieved in a number of ways:
These benefits must be weighed against the limitations and constraints imposed.
If the cache participates in a JTA transaction (ehcache-2.0 and higher) (i.e. it is an XAResource) then the Cache can be made consistent with the database as the write to the database and commit or rollback happens with the transaction boundary.
In write-behind, the write to the resource happens after the write to the cache. The transaction boundary is the write to the outstanding queue, not the write behind. In write-through mode, commit can get called and both the Cache and the underlying resource, e.g. the database can get committed at once.
Because the database is being written to outside of the transaction, there is always a risk that a failure on the eventual write will occur. While this can be mitigated with retry counts and delays, compensating actions may be required.
The obvious implication of asynchronous writes is that there is a delay between when the cache is updated and when the database is updated. This introduces an inconsistency between the cache and the database, where the cache holds the correct value and the database will be eventually consistent with the cache. The data passed into the CacheWriter methods is a snapshot of the cache entry at the time of the write to operation.
A read against the database will result in incorrect data being loaded.
The application must be tolerant of this inconsistency, as per the following are examples:
Note that in practice, if other applications are writing to the database, then a cache can often be inconsistent with the database.
Ideally node times should be synchronised. The write-behind queue is generally written to the underlying resource in timestamp order, based on the timestamp of the cache operation, although there is no guaranteed ordering.
The ordering will be more consistent if all nodes are using the same time. This can easily be achieved by configuring your system clock to synchronise with a time authority using Network Time Protocol.
The items on the write-behind queue are generally in order, but this isn't guaranteed. In certain situation and more particularly in clustered usage, the items can be processed out of order. Additionally, when batching is used, write and delete collections are aggregated separately and can be processed inside the CacheWriter in a different order that the order that was used by the queue.
Your application must of tolerant for item reordering or you need to compensate for this in your implementation of the CacheWriter. Possible examples here are:
For applications that are not tolerant of inconsistency, the simplest solution is for the application to always read through the same cache that it writes through. Provided all database writes are through the cache, consistency is guaranteed. And in the distributed caching scenario, using Terracotta clustering extends the same guarantee to the cluster.
If using transactions, the cache is the XAResource, and a commit is a commit to the cache.
The cache effectively becomes the System Of Record ("SOR"). Terracotta provides HA and durability and can easily act as the SOR. The database then becomes a backup to the SOR.
There are some practical problems that come up when using this approach: caching of a partial dataset and expiry and eviction limitations
The question arises: Does the entire data set need to be loaded in the cache on startup? The answer is no, because a read-through cache uses a CacheLoader which loads data into the cache on demand. In this way the cache be populated lazily.
If the entire dataset cannot fit in the cache, then some reads will miss the cache and fall through to the CacheLoader which will in turn hit the database. If a write has occurred but has not yet hit the database due to write-behind, then the database will be inconsistent.
The simplest solution is to ensure that the entire dataset is in the cache. This then places some implications on cache configuration in the areas of expiry and eviction.
Eviction occurs when the maximum elements for the cache have been exceeded. Ensure that the maxElementsInMemory and, if using the DiskStore or Terracotta clustering, the maxElementsOnDisk exceeds the required size, so that eviction does not not occur.
Even if all of the dataset can fit in the cache, it could be evicted if Elements expire. Accordingly, both timeToLive and timeToIdle should be set to eternal to prevent this from happening.
Both Ehcache standalone and with Terracotta Server Array (Ehcache EX and FX) are supported.
The write-behind queue is stored locally in memory. It supports all configuration options, but any data in the queue will be lost on JVM shutdown.
EX and FX when used with the Terracotta Server Array will store the queue on the Terracotta Server Array and can thus be configured for durability and HA. The data is still kept in the originating node for performance.
In a cluster each node will have a CacheWriter configured. These will process their local work, but if there is no local work, they will poll the other nodes to see if there is outstanding work and process part of that work.
This means that workload is balanced across the cluster, and that the write-behind queue will be serviced as long as there is one Ehcache L1 instance in the cluster.
There are many configuration options. See the CacheWriterConfiguration for properties that may be set and their effect.
Below is an example of how to configure the cache writer in XML:
<cache name="cacheName" eternal="false" maxElementsInMemory="1000" overflowToDisk="false">
<cacheWriter writeMode="write_behind" maxWriteDelay="8" rateLimitPerSecond="5"
writeCoalescing="true" writeBatching="true" writeBatchSize="20"
retryAttempts="2" retryAttemptDelaySeconds="2">
<cacheWriterFactory class="com.company.MyCacheWriterFactory"
properties="just.some.property=test; another.property=test2" propertySeparator=";"/>
</cacheWriter>
</cache>Further examples:
<cache name="writeThroughCache1" eternal="false" maxElementsInMemory="1000" overflowToDisk="false"/>
<cache name="writeThroughCache2" eternal="false" maxElementsInMemory="1000" overflowToDisk="false">
<cacheWriter/>
</cache>
<cache name="writeThroughCache3" eternal="false" maxElementsInMemory="1000" overflowToDisk="false">
<cacheWriter writeMode="write_through" notifyListenersOnException="true" maxWriteDelay="30"
rateLimitPerSecond="10" writeCoalescing="true" writeBatching="true" writeBatchSize="8"
retryAttempts="20" retryAttemptDelaySeconds="60"/>
</cache>
<cache name="writeThroughCache4" eternal="false" maxElementsInMemory="1000" overflowToDisk="false">
<cacheWriter writeMode="write_through" notifyListenersOnException="false" maxWriteDelay="0"
rateLimitPerSecond="0" writeCoalescing="false" writeBatching="false" writeBatchSize="1"
retryAttempts="0" retryAttemptDelaySeconds="0">
<cacheWriterFactory class="net.sf.ehcache.writer.WriteThroughTestCacheWriterFactory"/>
</cacheWriter>
</cache>
<cache name="writeBehindCache5" eternal="false" maxElementsInMemory="1000" overflowToDisk="false">
<cacheWriter writeMode="write-behind" notifyListenersOnException="true" maxWriteDelay="8" rateLimitPerSecond="5"
writeCoalescing="true" writeBatching="false" writeBatchSize="20"
retryAttempts="2" retryAttemptDelaySeconds="2">
<cacheWriterFactory class="net.sf.ehcache.writer.WriteThroughTestCacheWriterFactory"
properties="just.some.property=test; another.property=test2" propertySeparator=";"/>
</cacheWriter>
</cache>
This configuration can also be achieved through the Cache constructor in Java, like this:
Cache cache = new Cache(
new CacheConfiguration("cacheName", 10)
.cacheWriter(new CacheWriterConfiguration()
.writeMode(CacheWriterConfiguration.WriteMode.WRITE_BEHIND)
.maxWriteDelay(8)
.rateLimitPerSecond(5)
.writeCoalescing(true)
.writeBatching(true)
.writeBatchSize(20)
.retryAttempts(2)
.retryAttemptDelaySeconds(2)
.cacheWriterFactory(new CacheWriterConfiguration.CacheWriterFactoryConfiguration()
.className("com.company.MyCacheWriterFactory")
.properties("just.some.property=test; another.property=test2")
.propertySeparator(";"))));Instead of relying on a CacheWriterFactoryConfiguration>> to create a <<<CacheWriter, it's also possible to explicitly register a CacheWriter instance from within Java code. This allows you to refer to local resources like database connections or file handles.
Cache cache = manager.getCache("cacheName");
MyCacheWriter writer = new MyCacheWriter(jdbcConnection);
cache.registerCacheWriter(writer);The CacheWriterFactory supports the following attributes:
CacheLoaders are exposed for API use through the cache.getWithLoader(...) method. CacheWriters are exposed with cache.putWithWriter(...) and cache.removeWithWriter(...) methods.
For example, following is the method signature for cache.putWithWriter(...).
/**
* Put an element in the cache writing through a CacheWriter. If no CacheWriter has been
* set for the cache, then this method has the same effect as cache.put().
* <p/>
* Resets the access statistics on the element, which would be the case if it has previously
* been gotten from a cache, and is now being put back.
* <p/>
* Also notifies the CacheEventListener, if the writer operation succeeds, that:
* <ul>
* <li>the element was put, but only if the Element was actually put.
* <li>if the element exists in the cache, that an update has occurred, even if the element
* would be expired if it was requested
* </ul>
*
* @param element An object. If Serializable it can fully participate in replication and the
* DiskStore.
* @throws IllegalStateException if the cache is not {@link net.sf.ehcache.Status#STATUS_ALIVE}
* @throws IllegalArgumentException if the element is null
* @throws CacheException
*/
void putWithWriter(Element element) throws IllegalArgumentException, IllegalStateException,
CacheException;
See the Cache JavaDoc for the complete API.
The Ehcache write-through SPI is the CacheWriter interface. Implementers perform writes to the underlying resource in their implementation.
/**
* A CacheWriter is an interface used for write-through and write-behind caching to a
* underlying resource.
* <p/>
* If configured for a cache, CacheWriter's methods will be called on a cache operation.
* A cache put will cause a CacheWriter write
* and a cache remove will cause a writer delete.
* <p>
* Implementers should create an implementation which handles storing and deleting to an
* underlying resource.
* </p>
* <h4>Write-Through</h4>
* In write-through mode, the cache operation will occur and the writer operation will occur
* before CacheEventListeners are notified. If
* the write operation fails an exception will be thrown. This can result in a cache which
* is inconsistent with the underlying resource.
* To avoid this, the cache and the underlying resource should be configured to participate
* in a transaction. In the event of a failure
* a rollback can return all components to a consistent state.
* <p/>
* <h4>Write-Behind</h4>
* In write-behind mode, writes are written to a write-behind queue. They are written by a
* separate execution thread in a configurable
* way. When used with Terracotta Server Array, the queue is highly available. In addition
* any node in the cluster may perform the
* write-behind operations.
* <p/>
* <h4>Creation and Configuration</h4>
* CacheWriters can be created using the CacheWriterFactory.
* <p/>
* The manner upon which a CacheWriter is actually called is determined by the
* {@link net.sf.ehcache.config.CacheWriterConfiguration} that is set up for cache
* that is using the CacheWriter.
* <p/>
* See the CacheWriter chapter in the documentation for more information on how to use writers.
*
* @author Greg Luck
* @author Geert Bevin
* @version $Id: $
*/
public interface CacheWriter {
/**
* Creates a clone of this writer. This method will only be called by ehcache before a
* cache is initialized.
* <p/>
* Implementations should throw CloneNotSupportedException if they do not support clone
* but that will stop them from being used with defaultCache.
*
* @return a clone
* @throws CloneNotSupportedException if the extension could not be cloned.
*/
public CacheWriter clone(Ehcache cache) throws CloneNotSupportedException;
/**
* Notifies writer to initialise themselves.
* <p/>
* This method is called during the Cache's initialise method after it has changed it's
* status to alive. Cache operations are legal in this method.
*
* @throws net.sf.ehcache.CacheException
*/
void init();
/**
* Providers may be doing all sorts of exotic things and need to be able to clean up on
* dispose.
* <p/>
* Cache operations are illegal when this method is called. The cache itself is partly
* disposed when this method is called.
*/
void dispose() throws CacheException;
/**
* Write the specified value under the specified key to the underlying store.
* This method is intended to support both key/value creation and value update for a
* specific key.
*
* @param element the element to be written
*/
void write(Element element) throws CacheException;
/**
* Write the specified Elements to the underlying store. This method is intended to
* support both insert and update.
* If this operation fails (by throwing an exception) after a partial success,
* the convention is that entries which have been written successfully are to be removed
* from the specified mapEntries, indicating that the write operation for the entries left
* in the map has failed or has not been attempted.
*
* @param elements the Elements to be written
*/
void writeAll(Collection<Element> elements) throws CacheException;
/**
* Delete the cache entry from the store
*
* @param entry the cache entry that is used for the delete operation
*/
void delete(CacheEntry entry) throws CacheException;
/**
* Remove data and keys from the underlying store for the given collection of keys, if
* present. If this operation fails * (by throwing an exception) after a partial success,
* the convention is that keys which have been erased successfully are to be removed from
* the specified keys, indicating that the erase operation for the keys left in the collection
* has failed or has not been attempted.
*
* @param entries the entries that have been removed from the cache
*/
void deleteAll(Collection<CacheEntry> entries) throws CacheException;
}--- OpenJPA Caching Provider ---
Ehcache easily integrates with the OpenJPA persistence framework.
To use it, add a Maven dependency for ehcache-openjpa.
<groupId>net.sf.ehcache</groupId>
<artifactId>ehcache-openjpa</artifactId>
<version>0.1</version>or download from downloads.
Set OpenJPAÕs openjpa.QueryCache to ehcache and openjpa.DataCacheManager to ehcache. ThatÕs it!
See http://openjpa.apache.org/builds/1.0.2/apache-openjpa-1.0.2/docs/manual/ref_guide_caching.html for more on caching in OpenJPA.
As with Hibernate, Ehcache's OpenJPA module (from 0.2) uses the defaultCache configured in ehcache.xml to create caches.
For production, we recommend configuring a cache configuration in ehcache.xml for each cache, so that it may be correctly tuned.
--- Grails: Using Ehcache as a Second Level Caching Provider for Hibernate within Grails ---
Grails 1.2RC1 and higher use Ehcache as the default Hibernate second level cache. However earlier versions of Grails ship with the Ehcache library and are very simple to enable.
The following steps show how to configure Grails to use Ehcache. For 1.2RC1 and higher some of these steps are already done for you.
Edit DataSource.groovy as follows:
hibernate {
cache.use_second_level_cache=true
cache.use_query_cache=true
cache.provider_class='org.hibernate.cache.EhCacheProvider'
}As is usual with Hibernate, it will use the defaultCache configuration as a template to create new caches as required. For production use you often want to customise the cache configuration. To do so, add an ehcache.xml configuration file to the conf directory (the same directory that contains DataSource.groovy).
A sample ehcache.xml which works with the Book demo app and is good as a starter configuration for Grails is shown below:
<?xml version="1.0" encoding="UTF-8"?>
<ehcache xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:noNamespaceSchemaLocation="ehcache.xsd" >
<diskStore path="java.io.tmpdir"/>
<cacheManagerEventListenerFactory class="" properties=""/>
<defaultCache
maxElementsInMemory="10000"
eternal="false"
timeToLiveSeconds="120"
overflowToDisk="false"
diskPersistent="false"
/>
<cache name="Book"
maxElementsInMemory="10000"
timeToIdleSeconds="300"
/>
<cache name="org.hibernate.cache.UpdateTimestampsCache"
maxElementsInMemory="10000"
timeToIdleSeconds="300"
/>
<cache name="org.hibernate.cache.StandardQueryCache"
maxElementsInMemory="10000"
timeToIdleSeconds="300"
/>
</ehcache>For further information see the Hibernate chapter.
--- JSR107 (JCACHE) Support ---