As I mentioned recently on this blog, I'm working in my spare time on HTTP response cache implementation using Ehcache. When all said and done this will be a part of the Ehcache's web module. At this point the work on this is far from over but treat this as a status update.
Motivation
Who are the users of such an implementation? There was a feature request or two from the teams implementing REST clients to use Ehcache on the client side for optionally caching the GET operations based on various headers and directives.
High-level Design
This design leverages Java's Response cache mechanism, introduced back in version 1.5. I've written about it in an earlier post. On a GET request, Java's URLConnection's getInputStream() method invokes appropriate protocol handler, which in turn interacts with the concrete implementation of the java.net.ResponseCache.
Java's mechanism does not provide any default cache implementation, but you can extend java.net.ResponseCache and write your own. EhcacheResponseCacheAdaptor extends ResponseCache and implements its get() and put() methods. Also, when an instance of EhcacheResponseCacheAdaptor is created it registers itself with the JVM as a default cache.
Whenever the system tries to load a URL (using URLConnection) via a protocol handler it first checks in the cache via get(). If the data is in the cache, it is returned if not a connection is made to the origin server to GET the content. After downloading the content the protocol handler then attempts to put it in the cache via put().
URI Mappings and Cache
The caller after creating a new instance of EhcacheResponseCacheAdaptor calls its addMapping() method to register a specific URI pattern to a cache that is defined in the ehcache config file. For example:
EhcacheResponseCacheAdaptor responseCache =
new EhcacheResponseCacheAdaptor(new CacheManager(););
responseCache.addMapping("http://somedomain.com:9000/rest/customers/",
"sampleCache1");
An instance of Ehcache's CacheManager is passed to the constructor of the adaptor. And then one or more URIs can be mapped to the caches.
Cache elements
If you used or using Ehcache you know that Element needs a key and its value. Adaptor implementation parses the URI, matches that to a cache and the rest of the URI is treated as a key. So if a request is made for http://somedomain.com:9000/rest/customers/12887876320, system identifies that the user intends to use sampleCache1 as the cache, and the remaining part of the URI that is not a part of the mapping is used as the key. In this example 12887876320 is used as the key.
Cacheability
Cacheability determination is made based based on Cache-control (no-cache, max-age=0) and/or Pragma headers, supporting both HTTP 1.0 and 1.1.
Invalidation
Time-to-live (TTL) calculation is made using Cache-control (max-age, min-fresh) and/or Expires headers. TTL is assigned to the element directly. If the required headers are not provided it uses the values provided from the cache configuration.
Conditional GET
One of the important directives of conditional GET is only-if-cached (of Cache-control header). With this directive the client indicates to the system to fetch the value only from the cache if present, and not to request from the origin server. I've looked briefly into the protocol handler implementation and that seemed to be handling this scenario and perhaps I don't have to do much here.
From the User's point of view
For the end-user once they create the adaptor and add the mappings (as described above) not much is there to be done. They would perform the actions without any specific knowledge of this ResponseCache implementation. Following code would do just fine ..
URL url = new URL("http://somedomain.com:9000/rest/customers/12887876320");
URLConnection urlConnection = url.openConnection();
urlConnection.setDefaultUseCaches(true);
InputStream inputStream = urlConnection.getInputStream();
...
Next Steps
There are still quite a few loose ends in the implementation which need some tightening. The challenge is to provide support for as many HTTP headers from RFC-2616 as reasonable, Etag is one of them that I still have to take a look. More soon ...

Follow on Twitter
Surya Suravarapu Reply:
June 5th, 2009 at 6:32 am
I’m not entirely clear on your question, can you please elaborate it further. This specific effort is for client-side caching using Ehcache.
Note: This functionality is not yet available for public use.
[Reply]
Paul Reply:
June 5th, 2009 at 8:17 am
Using java 1.4, Ehcache 1.5
I am calling an external url which returns a xml data. I need to cache this call to the url for subsequent requests. this xml contains image urls as well on the external web site.
http://www.abcd.com/data?param=val1
http://www.abcd.com/data?param=val2
these 2 are separate calls and need to be cached for 30 min. and after 30 min it needs to be refreshed. the query string will change and needs to be cached for each unique query.
hope i got it clear now…
[Reply]
Surya Suravarapu Reply:
June 8th, 2009 at 8:36 pm
Sorry Paul, for some reason your comment was stuck in spam. Had to retrieve it from there.
In your example:
1. Decide on a cache name first. If it makes sense something like
abcd.com/datawill be the name of the cache.2. Query parameters can become keys to the cache elements. Obviously, the page content is the value of the cache element.
3. Time to expire (30 minutes you mentioned) can be specified at the cache level or at an individual element level using Ehcache.
Hope I have answered your question, let me know if something is not clear.
As I said, this client-side functionality is still in the works. I’m hoping to get some good chunk of time soon to finish it.
[Reply]
Paul Reply:
June 9th, 2009 at 9:04 am
Thanks for the reply…
Would the code look something like this?
private static String MY_URL = “http://www.abcd.com/data?param=val1″ ;
// Will be got dynamically from URL
String queryString = “param=val1″ ;
Element key = null ;
String xmlData = null ;
key = cache.get(queryString) ;
if ( key == null )
{
// Make the URL call
URL u = new URL(MY_URL);
…
…
//Get the Data
xmlData = ….
// store in cache
key = new Element(queryString, xmlData );
cache.put(key);
}
else
{
// Get the data from cache
xmlData = (String) key.getValue() ;
}
So what is the use of having this filter in the web.xml. does this help in any ways?
SimplePageCachingFilter
net.sf.ehcache.constructs.web.filter.SimplePageCachingFilter
SimplePageCachingFilter
/data
[Reply]