programming

Object oriented supremacy

Good article right here. I tend to agree with most of the article. I can’t say where the industry is going, but I’m definitely getting ready. I just received Real World Haskell by the mail today, so I’ll be digging in soon.

The pain he describes in the article, I’m currently going through right now. Is FP, or a combination of OO and FP the solution, we’ll see.

We’ve led ourselves down the wrong path. Or, to be more precise, we followed a single, very good path, but we didn’t know when to take a different path.

Good quotes

Some of my favorites found here.

  • Some people, when confronted with a problem, think “I know, I’ll use regular expressions.” Now they have two problems – Jamie Zawinski

  • Always code as if the guy who ends up maintaining your code will be a violent psychopath who knows where you live. – Rick Osborne
  • The most exciting phrase to hear in science, the one that heralds new discoveries, is not ‘Eureka!’ but ‘That’s funny…’ – Isaac Asimov
  • There are two ways of constructing a software design: One way is to make it so simple that there are obviously no deficiencies, and the other way is to make it so complicated that there are no obvious deficiencies. The first method is far more difficult

Unit testing ehcache (Take #2)

My solution works, but there was something smelly in there. I wasn’t satisfied with the way I was checking to ensure that the cache had actually been accessed. Given that the notification interface doesn’t define a method to find that out, I had sort of tricked it ….

Well, I obviously couldn’t leave it at that. So the solution to a better smelling cache unit test lies below (tip: use the Statistics information that’s right there on the cache, but I hadn’t noticed)

import junit.framework.Assert;

@Test
public void testCache() throws Exception {
    ApplicationContext context = new ClassPathXmlApplicationContext("spring-context.xml");
    DataFacade dataFacade = (DataFacade) context.getBean("cacheInjectedDataFacade");

    TestCacheListener listener = new TestCacheListener();
    Cache cache = dataFacade.getCache();
    cache.getCacheEventNotificationService().registerListener(listener);

    dataFacade.getData();
    Assert.assertEquals(ListenerStatus.ELEMENT_ADDED, listener.getLastStatus());
    Assert.assertNotNull(cache.get(DataFacade.CACHE_KEY));

    listener.resetLastStatus();
    Assert.assertEquals(listener.getLastStatus(), ListenerStatus.RESET);

    dataFacade.getData();
    Assert.assertEquals(1, cache.getStatistics().getCacheHits());

    Thread.sleep(2500);
    dataFacade.getData();
    Assert.assertEquals(ListenerStatus.ELEMENT_ADDED, listener.getLastStatus());
}

Also, remember to reset your cache through cache.removeAll() between tests (through the @BeforeTest) or else your cache hits won’t jive.

Unit testing ehcache

I just had to write some unit tests to make sure my caching mechanism was working properly. Obviously, there are better ways to do this, but for what I needed, it was ample. Any suggestions are definitely welcome.

Setup

We’ll start with a simple service class in which all caching manipulations are done from. The class is kept simple so as to not obfuscate what I’m really trying to show.

import net.sf.ehcache.Cache;
import net.sf.ehcache.Element;

public class DataFacade {
    private static final String CACHE_KEY = "mykey";

    private Cache cache;

    public String getData() {
        Element element = cache.get(CACHE_KEY);
        if (element != null && element.getValue() != null) {
            return (String) element.getValue();
        } else {
            String data = "lama";
            cache.put(new Element(CACHE_KEY, data));
            return data;
        }
    }

    public Cache getCache() {
        return cache;
    }

    public void setCache(Cache cache) {
        this.cache = cache;
    }
}

Spring Setup

Now, we need to write a test to ensure that the cache is being hit and expired properly. To do this, we’ll need to setup a test listener that will be injected into the Cache object used by the service class. Using spring, this is pretty easy, but we can also hand code it.

We’ll need a spring context configuration file somewhere in the classpath.

<?xml version="1.0" encoding="UTF-8"?>
<beans>
    <bean id="cacheInjectedDataFacade" class="org.mikem.DataFacade">
        <property name="cache" ref="cache"/>
    </bean>

    <bean id="cacheManager"  
          class="org.springframework.cache.ehcache.EhCacheManagerFactoryBean">
        <property name="configLocation" value="classpath:ehcache-config.xml"/>
    </bean>

    <bean id="cache" class="org.springframework.cache.ehcache.EhCacheFactoryBean">
        <property name="cacheManager">
            <ref local="cacheManager"/>
        </property>
        <property name="timeToIdle" value="2"/>
        <property name="timeToLive" value="2"/>
        <property name="eternal" value="false"/>
        <property name="diskPersistent" value="false"/>
        <property name="cacheName" value="org.mikem.lamacache"/>
    </bean>
</beans>

The things to watch out for here are:

  • We’re not using a ehcache.xml confguration file. All config is done through spring.
  • The package names should be changed to reflect where your own DataFacade is
  • Notice the timeToIdel and timeToExpire properties on the cache bean. More on that later

Unit test and the cache event listener

Now we’re ready to write the unit test related code. We’ll first need an implementation of the net.sf.ehcache.event.CacheEventListener interface. That implementation should look like the following:

public class TestCacheListener implements CacheEventListener {
    public static enum ListenerStatus {
         RESET,
         DISPOSED, ELEMENT_EVICTED, ELEMENT_EXPIRED, ELEMENT_ADDED,
         ELEMENT_REMOVED, ELEMENT_UPDATED, REMOVED_ALL,
    };

    public ListenerStatus lastStatus;

    public ListenerStatus getLastStatus() {
        return this.lastStatus;
    }

    public void resetLastStatus() {
       this.lastStatus = ListenerStatus.RESET;
    }

    public void dispose() {
        this.lastStatus = ListenerStatus.DISPOSED;
    }

    public void notifyElementEvicted(Ehcache arg0, Element arg1) {
       this.lastStatus = ListenerStatus.ELEMENT_EVICTED;
    }

    public void notifyElementExpired(Ehcache arg0, Element arg1) {
        this.lastStatus = ListenerStatus.ELEMENT_EXPIRED;
    }

    public void notifyElementPut(Ehcache arg0, Element arg1) throws CacheException {
        this.lastStatus = ListenerStatus.ELEMENT_ADDED;
    }

    public void notifyElementRemoved(Ehcache arg0, Element arg1) throws CacheException {
          this.lastStatus = ListenerStatus.ELEMENT_REMOVED;
    }

    public void notifyElementUpdated(Ehcache arg0, Element arg1) throws CacheException {
         this.lastStatus = ListenerStatus.ELEMENT_UPDATED;
    }

    public void notifyRemoveAll(Ehcache arg0) {
         this.lastStatus = ListenerStatus.REMOVED_ALL;
    }
}

What this gives us is a listener class which we’ll inject into the cache. On each cache event, the last status member will be updated.

Now for the finale:

import junit.framework.Assert;
import net.sf.ehcache.Cache;

import org.junit.Test;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

import com.stw.sandbox.TestCacheListener.ListenerStatus;

public class TestDataFacade {

@Test
public void testCache() throws Exception {
    ApplicationContext context = new ClassPathXmlApplicationContext("spring-context.xml");
    DataFacade dataFacade = (DataFacade) context.getBean("cacheInjectedDataFacade");

    TestCacheListener listener = new TestCacheListener();
    Cache cache = dataFacade.getCache();
    cache.getCacheEventNotificationService().registerListener(listener);

    dataFacade.getData();
    Assert.assertEquals(ListenerStatus.ELEMENT_ADDED, listener.getLastStatus());
    Assert.assertNotNull(cache.get(DataFacade.CACHE_KEY));

    listener.resetLastStatus();
    Assert.assertEquals(listener.getLastStatus(), ListenerStatus.RESET);

    dataFacade.getData();
    Assert.assertEquals(ListenerStatus.RESET, listener.getLastStatus());

    Thread.sleep(2500);
    dataFacade.getData();
    Assert.assertEquals(ListenerStatus.ELEMENT_ADDED, listener.getLastStatus());
}
}

Explanation:

  • Lines 14 and 15 are the spring access and retrieval of the DataFacade instance
  • Lines 17 through 19 take care of creating a new instance of the TestCacheListener and injecting it into the data facade instance
  • Line 21 runs the method where we have some cache access going on
  • Line 22: Because our last line actually put something in the cache, our cache listeners status will have changed. Here we’re making sure the status has been changed accordingly.
  • Line 23: Make sure we have data in the cache (we could also check that the content is right)
  • Line 25: Reset the last status on the listener
  • Line 28: Fetch the data once again. At this point, the listeners last status will remain to RESET since it won’t have been put into the cache anew.
  • Line 31: Because we configured our timeToIdle and timeToExpire to 2 seconds (see the spring config), we know that by sleeping 2.5 seconds, the next hit to our method will force a renewal of the cache content

Voila! Obviously, you could and should expand on this, but it’s start.

[EDIT] I’ve posted an update, mainly about how to access cache hits.