9 posts

The problem at hand is that EclipseLink (great project lead by James Sutherland) does not use a query cache when dealing with ReadAll queries, i.e: all calls to getResultList() go to the database.  Some object-level caching is performed by avoiding construction of new objects based on the primary key values the database call returns.  EclipseLink compares the PK values returned by the getResultList() query to that in its identity cache and if matches are found, the cached objects are returned.  After running JProfiler, I determined that the saving weren't really significant at all as the query was being executed every time and only entity creation was avoided.  

I realize that caching calls from getResultList() can be dangerous as changes from other applications will not be reflected, and that is the argument I received on the mailing list.  The argument carries merit, but since the default behavior of EclipseLink is to maintain an identity cache as described in the previous paragraph, any outside changes to non-primary key values will not be reflected anyway, so I don't see what the big deal about caching ReadAll queries really is. EclipseLink can't cache native queries since they aren't mapped nicely to JPA @Entity objects.  Since I'm working on a legacy system with a database design that resembles spaghetti and meatballs which also happens to be heavily used, I desperately needed to cache some queries that I know return fairly static data.

Anyway, so I went about trying to implement a cache and thankfully, EclipseLink provides a great extension point through query redirectors.  Basically, specifying a QueryRedirector on a query will allow you to control the logic right before query execution.   The @QueryRedirectors annotation has a bug which forces you to specify all attributes so I went for a cleaner, programmatic solution.  

First, we must specify the a redirector for the query created using the EntityManager:

Query query = em.createQuery("getOrdersByCustomerLastName").setParameter("lastName", "Smith");
JpaHelper.getDatabaseQuery(query).setRedirector(new AggressiveCacheQueryRedirector());

EclipseLink's  JpaHelper.getDatabaseQuery() helper method provides access to the EclipseLink-specific DatabaseQuery object which contains the setRedirector() method.  The AggressiveCacheQueryRedirector class must implement the QueryRedirector interface.  Here's the complete implementation of the redirector:


public class AggressiveCacheQueryRedirector implements QueryRedirector {

     * Returns a cached result if applicable, otherwise invokes query
     * @param query query to execute
     * @param arguments arguments
     * @param session session
     * @return cached result or query results
    public Object invokeQuery(DatabaseQuery query, Record arguments, Session session) {

        // In order to avoid loop, stop redirecting once execution finishes

        // Caching read-all queries
        if (query.isReadAllQuery()) {

            // Find or create the cache based on class descriptor
            EhCacheWrapper cacheWrapper = EhCacheWrapper.getInstance();
            Cache cache = cacheWrapper.findOrCreateCache(query.getDescriptor());

            // Create a key for the cache and query it
            CacheKey key = new CacheKey(query.getName(), arguments.values().toArray());
            Element element;

            // Return cached result
            if ((element = cache.get(key)) != null) {
                return element.getValue();

            // Execute query and store result in cache
            } else {
                Object object = query.execute((AbstractSession)session, (AbstractRecord) arguments);
                if (object != null) {
                    cache.put(new Element(key, object));
                return object;
         // Execute query as-is, no caching is done
        } else {
            return query.execute((AbstractSession)session, (AbstractRecord) arguments);

It's fairly simple, all it's doing is checking EhCache before deciding whether to execute the query.  The query name and argument values are the keys of the cache, with the values being the results returned by the query upon execution.  The EhCacheWrapper class is just that, a wrapper for EhCache specific functions.  A plain implementation is given below.  Of note is the @AggressiveCache annotation which I created to denote entities that need to be cached using EhCache.  It has two attributes, the cache duration in seconds and the size of the cache, corresponding to the setExpiryInSeconds and setMaxElementsInMemory of the EhCache's Cache object.

public class EhCacheWrapper {

    private static EhCacheWrapper ehCacheWrapper;

     * Static create method
     * @return The singleton instance of EhCacheWrapper
    public static EhCacheWrapper getInstance() {
        if (ehCacheWrapper == null) {
            ehCacheWrapper = new EhCacheWrapper();
        return ehCacheWrapper;

    /** CacheManager singleton instance **/
    private CacheManager singletonManager;

     * Private constructor which initializes CacheManager
    private EhCacheWrapper() {
        try {
            singletonManager = new CacheManager(new ClassPathResource("ehcache.xml").getURL());
        } catch (IOException e) {
            throw new RuntimeException();

     * Returns a cache if one exists, otherwise creates one
     * @param descriptor EclipseLink class descriptor
     * @return A newly created on pre-existing Cache
    public Cache findOrCreateCache(ClassDescriptor descriptor) {
        String cacheName = descriptor.getJavaClass().getSimpleName();
        Cache cache = singletonManager.cacheExists(cacheName) ? singletonManager.getCache(cacheName) : null;
        if (cache == null) {
            Cache newCache = createCache(descriptor);
            return newCache;
        } else {
            return cache;

     * Creates a cache either by calling createCacheFromCacheAnnotation() or createDefaultCache()
     * @param descriptor EclipseLink class descriptor
     * @return A newly created Cache
    private Cache createCache(ClassDescriptor descriptor) {
        AggressiveCache annotation = (AggressiveCache) descriptor.getJavaClass().getAnnotation(AggressiveCache.class);
        CacheConfiguration config = new CacheConfiguration();
        return new Cache(config);

Here's the @AggressiveCache annotation.

public @interface AggressiveCache {

     * Corresponds to EhCache's Cache.setMaxElementsInMemory
     * @return EhCache's Cache.setMaxElementsInMemory
    int size() default 1000;

     * Corresponds to EhCache's Cache.setTimeToLiveSeconds
     * @return EhCache's Cache.setTimeToLiveSeconds
    int expiryInSeconds() default 60000;


For completeness, here's the CacheKey class which stores the query name and the argument values.

public class CacheKey {

    private String queryName;
    private Object[] arguments;

     * Store the query name and its argument as the key
     * @param queryName Name of query
     * @param arguments Arguments of query
    public CacheKey(String queryName, Object[] arguments) {
        this.queryName = queryName;
        this.arguments = arguments;

    public boolean equals(Object o) {
        if (this == o) return true;
        if (o == null || getClass() != o.getClass()) return false;

        CacheKey cacheKey = (CacheKey) o;

        if (!Arrays.equals(arguments, cacheKey.arguments)) return false;
        if (queryName != null ? !queryName.equals(cacheKey.queryName) : cacheKey.queryName != null) return false;

        return true;

    public int hashCode() {
        int result = queryName != null ? queryName.hashCode() : 0;
        result = 31 * result + (arguments != null ? Arrays.hashCode(arguments) : 0);
        return result;

Are JSPs dead? Blog

Posted by zarar Apr 17, 2007
The people I work for have rewarded my countless hours of hard labor by approving my application to go to's Java Symposium.  This comes a year after I attended JavaOne in San Francisco.  So why did I choose TSS Java Symposium over Java One?  I'm sure you give a rats ass about my opinion but here it comes anyways.  JavaOne is too big: It's f***ing huge! There's like 10,000 people there and although you might argue that the size of people attending is proportional to the quality of the presentations, you're wrong.  I did attend a couple nice sessions last year but there were more than a few crappy ones (Spring Web Flow, Composite Applications etc.) which tells me (keeping proportions in mind) that there are many crappy ones.  The rooms are huge which takes away from the learning environment that it should be; it feels like a first year chemistry class rather than a conference where you're supposed to quickly pick up stuff while having some fun at the same time. The Commercialism: Everyone's trying to sell you something and as soon as you tell them you don't have any purchasing power in your company, they throw sharp pointed objects at you.  I talked to the guy from Terracotta last year for about 15 minutes asking him all kinds of questions and at the end he asked me what I did at my company and when I said I was a measly developer, he gave me one of those I-can't-believe-I-wasted-20-f***ing-minutes-on-this-guy look. Bad Food: Just horrible and awful.  I was scared to touch it, let alone eat it.  But when I finally mustered up the courage to eat it, I regretted it after two bites.  I threw the sandwich away and gave my warm soda to what appeared to be a homeless developer. Repetition: There were around four different sessions on Java Persistence API which covered the same subject matter.  I made the mistake of attending two of them only to realize they're talking about the exact same thing, they just labeled the sessions differently just so everybody on the expert group had their crack at impressing the bored audience how they copied Hibernate. Bad Party: Any party where the ratio of men to women is 6:1 is never going to be good but you can make up for it by actually providing accessible food and drink.  When you shove 10,000 people in one big room and setup 4 stations where you can get drinks and food from, your appetite will force you to exit the premises and the lack of women will only motivate you to do so quickly.  I scampered off to the Marriot nearby and admired San Francisco from towering heights.  Also, chugging T-Shirts out of a cannon is not entertainment. Long lines at sessions: Again, the size issue.  The Gestapo regime that is the event staff forces you to lineup before every session and swipe your conference card.  The lineups are long and painful and if you're in the line, you'll often here more than a few people muttering "I don't believe this shit".  Don't believe me? Ask anyone who attended last year. Spam after you come back: Here's a tip to anyone attending this year, give a fake phone and email address in your JavaOne registration form.  You'll thank me as you're laughing at your friends for having to deal with daily spam and intruding phone calls imploring you to buy some product from Quest Software and pay for training courses from Sun.  These people have a knack of bothering you during lunch hour which is a double whammy.  Every moment you're in the pavilion, somebody's begging to swipe your conference card like they were get paid by the swipe.  They probably are. No Networking Opportunities: Aside from the BOF's which you may or may not be interested in, there are really no parties or events that will allow you to network with other people.  Given how most IT folks are socially inward and scared of light, the task of networking at JavaOne is a little tough.  The best time I had last year was at the Geronimo party, although I've never even used Geronimo, I sure enjoyed the free food and drinks provided by IBM etc.  Side note: Again, aside from the waitresses, no women at this party either.  I actually exchanged a few business cards with some fine folk; more of these events would only help JavaOne. Now I've never been to TSS Java Symposium before but from what I can gather from the session descriptions, they seem to cater more to my line of work: enterprise development.  I read some horror stories about TSS last year but it's time I take a look and judge for myself. Since I write about other stuff besides just Java, I primarily use a wordpress blog:  I'll be talking and reviewing the sessions at TSS Java Symposium over there.  If anybody cares.

Sneaky, sneaky Log4J Blog

Posted by zarar Nov 14, 2005

So I found myself wanting to know if I could print the enclosing method of the current line of code being executed.  A quick look at the reflection API didn't yield much.  A little reflective thinking later, I came to the conclusion that it's impossible for the reflection API to tell me this since it explores binary files at the class level.

Thats when it struck me that Log4J does exactly what I want to do.  It can print out the method and line number of the code for each log.debug(..) call.  So of I went digging into Log4J code looking for an answer.  I found it.

What Log4J ends up doing is that for each debug(..) call, it creates an instance of Throwable which takes a snapshot of the runtime stack.  It then proceeds to parse the stack to yield the current line of code being executed along with class and method information.

Keep in mind that constructing stack traces is a fairly expensive operation. When an Exception is created, the JVM needs to literally pause the processing and so it can get a good glimpse of the entire runtime stack - this includes classes, methods, line numbers etc - starting from all the way till the creation of Throwable.  From the runtime's point of view, this is acceptable since it's not designed for great Exception handling but to run as fast as possible. 

However, in the logging scenario, the culprit is the call to the Throwable.fillInStackTrace() method in the Throwable constructor which gets invoked on each debug(..), info(..) and other logging calls. This is the only way to retrieve the logging information requested via the PatternLayout class.  Give Log4J credit since they only create the Throwable instance when the specific PatternLayout is specified; plus they have the decency to warn you about using the l, L and other expensive options. 

Although descriptive logging can provide good roll-back mechanisms in production code, the cost incurred by specifying method and line numbers when logging is simply too high.  It seems like the pain of typing out the method name when logging is unavoidable.

To some, this might come as old news but to many it'll make them change their

Although I've been a core developer for a significant part of my career, I do often come in contact with the business-types who drone on about requirements while the eager-to-please IT shop keeps saying yes to even the most unfathomable requests.  After all the yes's have been nodded and all the necessary hands shaken, the Project Manager brings a steep pile of 8.5 x 11's to the developers along with a pat on the back and a confidence inspiring wink.  Boo Yeah! The project has started. A meeting is held by all parties involved only to be cut short by 12:00 PM and the ensuing two hour lunch break.  The developers are left figuring what this stack of paper is trying to say.  The front page is pretty clear, "Inventory Management System" it says.  On the second page there's something about Java being a requirement.  There's also a due date.  They start working. Fast forward to five months later.  The stack of paper has a lot of writing on it. Lines have been scribbled and crossed out.  Along with bits and pieces of scribble, you'll also find pepperoni stains and some fluids which can best be ascribed to coke spills.  Lots of code has been written, some of it has even been tested.  The programmers are feeling fairly confident, the PM has his ass covered, anything goes wrong, and he

Filter Blog

By date: