Tuesday, July 21, 2009

Using SelfPopulatingCache in Ehcache

Introduction
Often you can notice that Ehcache is used mostly like a tool that implements highly configurable maps. Sometimes developers configure time-to-live properties, or make use of disk-store functionality, but you can rarely meet someone who has cache population/eviction process that makes sense.

In the perfect world I would expect cache to be a universal pool. I request a value for a key and would like to get it whenever it is possible and as fast as possible with just one line of code. But in reality I usually can see huge cache population code on the application startup, daemon threads that update caches in eternal loop and numerous “ifs” around cache.get() calls.

In my strive to the perfect world I’ve discovered a SelfPopulatingCache class in Ehcache. In this article I will describe how using SelfPopulatingCache class one can implement a cache with self creating objects with optional auto-updating. In some way this example is an implementation of ideas mentioned in Ehcache documentation.

Example
What you will see down here:
  • A Reader that fetches an object from cache 5 times every 0.5 seconds.
  • Behind scenes cache will create a new object if there is no such object is there in cache for a key requested.
  • A daemon thread will trigger cache refresh every 2 seconds.
The most important class in this example is ExampleCacheProvider.



What it does is creating simple Ehcache (original cache) and wrapping it with SelfPopulatingCache (selfPopulatingCache). We can use this class the same way as CacheManager, so one can consider extending CacheManager, but to keep it simple here we'll stick to this kind of cache source.
While wrapping we specify updatingFactory, which can be set to one of two options: ExampleCacheEntryFactory (line 19) and ExampleUpdatingCacheEntryFactory(line 21). For the purposes of this example the choice between this two options is done based on the “com.blogspot.mikler.java.cache.factory” system property value. The difference between this two is that ExampleCacheEntryFactory implements CacheEntryFactory interface, while ExampleUpdatingCacheEntryFactory extends ExampleCacheEntryFactory and implements UpdatingCacheEntryFactory. The difference between using each of this options is explained later on. Meanwhile here is the code of both classes.



ExampleUpdatingCacheEntryFactory :



As you can see in this example as cache element’s key string used, while StringBuffer is used as a value. In createEntry() method in ExampleCacheEntryFactory StringBuffer is created with leading random number. While in updateEntryValue() method of ExampleUpdatingCacheEntryFactory existing StringBuffer length is appended to the buffer itself.

And finally, here goes our Reader main class. It fetches our wrapped cache, get’s value for “foo” key from it and stores it into final local variable fooOriginalBuffer, that is never changed late in Reader’s code. Then it starts doing 5 iterations of getting value for “foo” key from cache, displaying debug info and stats, and sleeping for one second. The code is simple as this.



Let’s run it with both updatingFactory options.
Output of running the Reader with ExampleCacheEntryFactory (-Dcom.blogspot.mikler.java.cache.factory=create)


And here how the output looks like while running Reader with ExampleUpdatingCacheEntryFactory as updatingFactory (-Dcom.blogspot.mikler.java.cache.factory=update)


Conclusion
As you can see the output is quite different and here are some conclusions we come to from analyzing it:
  • No NullPointerException is occurs while trying to get object from cache that is not there. It is being created in both cases.
  • If updatingFactory is instance of CacheEntryFactory (ExampleCacheEntryFactory in our case) when cache.refresh() is called each object in cache is being recreated.
  • Also when updatingFactory is instance of CacheEntryFactory final fooOriginalBuffer variable is not updated.
  • Meanwhile in case when updatingFactory is instance of CacheEntryFactory (UpdatingCacheEntryFactory in our case) when cache.refresh() is called each object in cache gets updated instead of being recreated.
  • And final fooOriginalBuffer variable value is updated as well. (Actually this variable itself is passed to updateEntryValue() method of ExampleUpdatingCacheEntryFactory)

Besides the above conclusion, one can notice that using SelfPopulatingCache reduces scattering and tangling (see my “WTF is AOP article”).

As usually, you can get source code for this post by running
svn co http://miklerjava.googlecode.com/svn/trunk/samples/SelfUpdatingEhCache SelfUpdatingEhCache

Friday, July 17, 2009

WTF is AOP?

When I first heard about AOP the story have unfolded pretty much the same way as when I’ve read about Spring framework for the first time. The issue with understanding what IoC is for was that it looks very interesting, but complicated. And probably one should have some sort of insight so see any benefits behind all the complexity he (she) is exposed to while reading the documentation.

With AOP the story is the same. “What are my benefits?” – is the very first question I’m asking any book or article that is telling me about Aspect, Advises and Joint-points. And usually I have to patiently read through several more boring definitions when the author gets to the point. So I’m going to save you some of your precious time. Let me try to explain what AOP is and how you can benefit from it, putting it as simple as possible.

When you write your code, besides main functionality, you usually need to do auxiliary things, like logging, security stuff (or put it nerdy: authentication and authorization), and you might need something like transaction handling. Without AOP you most likely will end up doing this things right next to your “important code”. And there are several issues with this:
Methods containing your “important code” will be overloaded with auxiliary code and will be harder to read and understand.

  1. If you change the way you control user’s access to the system or the way you do logging or transaction handling, you’ll have to change it in each and every place you are doing that.
  2. When and if you start reading on about AOP you will see such words as scattering and tangling, which also refer to such “bad” functionality.

So AOP is aimed to reduce your pain while dealing with the issues mentioned. The idea is that any kind of auxiliary functionality is extracted into separate code which is going to be applied to any existing model, so that code that is already in that model doing the same things can be removed. And this extracted code is called Advice (don’t ask me why).

Then you define where you want to call this Advise from. I.e. you might want to write logging messages before a specific method call. This place will be called Pointcut. And all together with Advice this will form Aspect.
You can see how it works with logging in my previous post “Using Spring AOP to trace invocations”.

Thursday, July 9, 2009

Using Spring AOP to trace invocations

How often do you write something like this?

public void foo(){
logger.debug("entering foo");
....
logger.debug("leaving foo");
}


If your answer is "often enough", then you should consider the following info. Anyone using Spring framework can seamlessly integrate trace logging into his application, just with slight modification to their spring context configs. In this post I will describe how to trace your code using DebugInterceptor (or any other interceptor of your choice).

The idea behind the proposed solution is to wrap the bean, which invocations you are going to trace, with a proxy that has SimpleTraceInterceptor or DebugInterceptor in the interceptorNames property. The interceptors mentioned are implementations of around advice that will write all the invocations' details to some logger (the way we choose our logger is discussed later on). This Interceptors are provided with Spring core library along with CustomizableTraceInterceptor, PerformanceMonitorInterceptor and few others. I guess, an example is the best way to show how it works.

Consider this simple program: two beans, one Spring context config, and one entry-point class, that just calls the first bean's method( so it is omitted on this page).

Bean1:


Bean2:


The Spring Context:



Running this code we get the following output:

23:13:04,348 TRACE [com.blogspot.mikler.java.Bean1] - Entering method 'entryPoint' of class [com.blogspot.mikler.java.Bean1]
23:13:04,349 TRACE [com.blogspot.mikler.java.Bean2] - Entering method 'importantMethod' of class [com.blogspot.mikler.java.Bean2]
23:13:04,349 INFO [com.blogspot.mikler.java.Bean2] - Doing job for 3 seconds
23:13:07,349 TRACE [com.blogspot.mikler.java.Bean2] - Exiting method 'importantMethod' of class [com.blogspot.mikler.java.Bean2]
23:13:07,350 TRACE [com.blogspot.mikler.java.Bean2] - Entering method 'doSomethingQuick' of class [com.blogspot.mikler.java.Bean2]
23:13:07,351 INFO [com.blogspot.mikler.java.Bean2] - doing something quick with param = a job
23:13:07,351 TRACE [com.blogspot.mikler.java.Bean2] - Exiting method 'doSomethingQuick' of class [com.blogspot.mikler.java.Bean2]
23:13:07,351 INFO [com.blogspot.mikler.java.Bean1] - All jobs done
23:13:07,351 TRACE [com.blogspot.mikler.java.Bean1] - Exiting method 'entryPoint' of class [com.blogspot.mikler.java.Bean1]


I hope the source code tells the story.

Several points that should be stressed:
  • One should decide to use Dynamic Logger or not (see useDynamicLogger property of the DebugInterceptor). If the dynamic logger is used, then invocations' log messages will be written to the logger of respective bean class (log4j.logger.com.blogspot.mikler.java.* loggers in our case). Otherwise the logger of the respective Interceptor will be used, one for all of the beans.
  • Make sure you enable the trace level for the selected logger. Because for optimization purposes the Interceptors don't make any job, saving your operation time, if this logging level for the logger they look up is not enabled.
To try yourself you can checkout sourcecode of this sample by running
svn co http://miklerjava.googlecode.com/svn/trunk/samples/SpringTracing springtracingsample