December 19, 2009

Adapter pattern revised

In my article about adapter pattern I have written an adapter that allows to access Ehcache cache instances through a simple Map interface. The basic idea was to write a Map implementation that actually, behind the scenes, was wrapping and hitting Ehcache. Everything looked great but Zach Bailey found a bug in my implementation – or more precisely – lack of functionality. He even provided a test case proving he is right. And sadly, he was ;-). Thank you Zach!

The problem was with three map methods: keySet(), entrySet() and values(). If you read carefully their API you’ll find out that all these methods should return an "interactive" view backed by the underlying map so that changing the view is automatically reflected in the map that returned that view and vice-versa. For example, if you remove an item from the set returned by keySet(), corresponding map entry with this key value should be also removed. Unfortunately, in my implementation these methods simply returned independent copies holding current state (snapshots) of the map. To make matters worse, those were not immutable collections (see Collections#unmodifiableSet) so when user modified them, no errors were issued but also source map remained untouched, effectively hiding the bug.

As I said, I already have a unit test failing on my Map implementation. I extended the test case and created more complex test set (but still not complete!) Look at the signatures, I hope they are self-describing:


package com.blogspot.nurkiewicz.ehcache;

import java.util.Iterator;
import java.util.Map;
import java.util.Set;

import org.junit.Before;
import org.junit.Test;

import static org.hamcrest.CoreMatchers.equalTo;
import static org.hamcrest.CoreMatchers.not;
import static org.hamcrest.MatcherAssert.assertThat;
import static org.hamcrest.Matchers.hasItem;
import static org.hamcrest.collection.IsMapContaining.hasEntry;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertNull;
import static org.junit.Assert.assertTrue;

public class MapTest {

private Map<String, String> map;

@Before
public void setupTestMap() {
map = //...
}

@Test public void emptyMapShouldReturnEmptyKeySet() {/**/}
@Test public void mapWithSingleEntryShouldReturnKeySetWithSingleItem() {/**/}
@Test public void mapWithMultipleEntriesShouldReturnKeySetWithMultipleItems() {/**/}
@Test public void removingOnlyItemFromKeySetShouldRemoveFromMap() {/**/}
@Test public void removingOnlyItemFromKeySetUsingIteratorShouldRemoveFromMap() {/**/}
@Test public void removingOneOfItemsFromKeySetShouldRemoveFromMap() {/**/}
@Test public void removingOneOfItemsFromKeySetUsingIteratorShouldRemoveFromMap() {/**/}
@Test public void removingNotExistingItemFromKeySetShouldNotChangeMap() {/**/}
@Test public void removingOnlyEntryFromMapShouldRemoveItemFromKeySet() {/**/}
@Test public void removingOnlyEntryFromMapUsingIteratorShouldRemoveFromKeySet() {/**/}
@Test public void removingOneOfEntriesFromMapShouldRemoveFromKeySet() {/**/}
@Test public void removingOneOfEntriesFromMapUsingIteratorShouldRemoveFromKeySet() {/**/}
@Test public void removingNotExistingEntryFromMapShouldNotChangeKeySet() {/**/}
@Test public void addingEntryToMapShouldAddItemToKeySet() {/**/}
}


But before we move on and examine our original implementation against this test let us think for a while how to set up this test case? I could simply write in setupTestMap():

final Ehcache cache = CacheManager.getInstance().getEhcache("com.blogspot.nurkiewicz.ehcache.TEST");
map = new EhcacheMapAdapter<String, String>(cache);


But then I decided to test my unit tests (sic!) by running them on standard Java Map implementations: HashMap, TreeMap and ConcurrentHashMap. This is a common scenario, where you have more than one implementation of an interface and you would like to test all the implementations at once. In an ideal world (luckily, this article describes one), unit test should not depend upon particular implementation of the interface, it should rather verify whether the interface contract is satisfied, no matter which implementation is used. We want to write a single test case and pass different implementations to test them one at a time. How to do this in JUnit without copy-pasting the same tests (don’t repeat yourself!) over and over? This is my real setup code:

public abstract class MapTest {

private Map<String, String> map;

@Before
public void setupTestMap() {
map = createTestMap();
assertNotNull(map);
}

protected abstract Map<String, String> createTestMap();

//...
}


Have you noticed test case class being abstract? JUnit runners (both maven-surefire-plugin and IntelliJ IDEA built in runner) are smart enough to ignore abstract test cases and run only concrete subclasses. But more importantly, when they run MapTest subclasses they include test methods (annotated with @Test) defined in abstract base class. Don’t get the idea? Look at the rest of the code:

public class HashMapTest extends MapTest {

@Override
public Map<String, String> createTestMap() {
return new HashMap<String, String>();
}
}


public class ConcurrentHashMapTest extends MapTest {

@Override
public Map<String, String> createTestMap() {
return new ConcurrentHashMap<String, String>();
}
}


public class TreeMapTest extends MapTest {

@Override
public Map<String, String> createTestMap() {
return new TreeMap<String, String>();
}
}


public class EhcacheMapAdapterTest extends MapTest {

@Override
public Map<String, String> createTestMap() {
final Ehcache cache = CacheManager.getInstance().getEhcache("com.blogspot.nurkiewicz.ehcache.TEST");
cache.removeAll();
return new EhcacheMapAdapter<String, String>(cache);
}
}


Each MapTest subclass inherits test methods from abstract base class, but providing concrete Map implementation. EhcacheMapAdapterTest is the one of our interest. BTW we’ve actually introduced Template Method design pattern! In this pattern the majority of work (algorithm) is implemented in abstract base classes, but some steps are left intentionally as abstract methods. When using this class, almost everything is done already, all you need to provide are (typically simple) implementations of abstract methods. In our case all the logic (unit tests) are gathered in base class MapTest, but the user must subclass it and implement Map factory method createTestMap(). But more on this pattern maybe later.

Going back to bug-fixing. Since we have the tests, lets run them to see where are we starting:



As you can see, all the tests passed in standard JDK implementations, but my EhcacheMapAdapter has lots to be ashamed of...

It is not even test driven development. It is rather test driven bug-fixing – somebody reports you a bug and the first thing to do is to write a unit test (since we probably missed one) that fails because of the bug. That’s the best way to reproduce the bug. When we know what is wrong, we are bug-fixing until that (and all existing) test succeeds. This has another benefit – if few months later some developer sees your code, existing unit test will help him to understand why this bug-fix has been applied and prevent from removing it.

After an hour or two all my tests were green, so I had a good starting point for optimizations or refactorings. Code is good, but making it even better won’t break anything. But I must disappoint you – or rather: give you an opportunity to enrich your test driven experiences! In the first article you have a starting code, below is the full test case source:


public abstract class MapTest {

private Map<String, String> map;

@Before
public void setupTestMap() {
map = createTestMap();
assertNotNull(map);
}

protected abstract Map<String, String> createTestMap();

@Test
public void emptyMapShouldReturnEmptyKeySet() {
//given

//when
final Set<String> set = map.keySet();

//then
assertThat(set.size(), equalTo(0));
}

@Test
public void mapWithSingleEntryShouldReturnKeySetWithSingleItem() {
//given
map.put("zero", "0");

//when
final Set<String> set = map.keySet();

//then
assertThat(set.size(), equalTo(1));
assertThat(set, hasItem("zero"));
}

@Test
public void mapWithMultipleEntriesShouldReturnKeySetWithMultipleItems() {
//given
map.put("zero", "0");
map.put("ten", "10");
map.put("hundred", "100");

//when
final Set<String> set = map.keySet();

//then
assertThat(set.size(), equalTo(3));
assertThat(set, hasItem("zero"));
assertThat(set, hasItem("ten"));
assertThat(set, hasItem("hundred"));
}

@Test
public void removingOnlyItemFromKeySetShouldRemoveFromMap() {
//given
map.put("one", "1");
assertThat(map.size(), equalTo(1));
assertThat(map, hasEntry("one", "1"));

//when
Set<String> set = map.keySet();
final boolean result = set.remove("one");

//then
assertTrue(result);
assertTrue(set.isEmpty());
assertTrue(map.isEmpty());

}

@Test
public void removingOnlyItemFromKeySetUsingIteratorShouldRemoveFromMap() {
//given
map.put("one", "1");
assertThat(map.size(), equalTo(1));
assertThat(map, hasEntry("one", "1"));

//when
Set<String> set = map.keySet();
final Iterator<String> iterator = set.iterator();
iterator.next();
iterator.remove();

//then
assertTrue(set.isEmpty());
assertTrue(map.isEmpty());

}

@Test
public void removingOneOfItemsFromKeySetShouldRemoveFromMap() {
//given
map.put("three", "3");
map.put("two", "2");
assertThat(map.size(), equalTo(2));
assertThat(map, hasEntry("two", "2"));
assertThat(map, hasEntry("three", "3"));

//when
Set<String> set = map.keySet();
final boolean resultOfRemovingOne = set.remove("one");
final boolean resultOfRemovingTwo = set.remove("two");

//then
assertFalse(resultOfRemovingOne);
assertTrue(resultOfRemovingTwo);

assertThat(set.size(), equalTo(1));
assertThat(set, not(hasItem("two")));
assertThat(set, hasItem("three"));

assertThat(map.size(), equalTo(1));
assertThat(map, not(hasEntry("two", "2")));
assertThat(map, hasEntry("three", "3"));
}

@Test
public void removingOneOfItemsFromKeySetUsingIteratorShouldRemoveFromMap() {
//given
map.put("three", "3");
map.put("two", "2");
assertThat(map.size(), equalTo(2));
assertThat(map, hasEntry("two", "2"));
assertThat(map, hasEntry("three", "3"));

//when
Set<String> set = map.keySet();
final Iterator<String> iterator = set.iterator();
final String removedKey = iterator.next();
iterator.remove();

//then
assertThat(set.size(), equalTo(1));
assertThat(set, not(hasItem(removedKey)));
assertThat(map.size(), equalTo(1));
}

@Test
public void removingNotExistingItemFromKeySetShouldNotChangeMap() {
//given
map.put("four", "4");
assertThat(map.size(), equalTo(1));
assertThat(map, hasEntry("four", "4"));

//when
Set<String> set = map.keySet();
final boolean result = set.remove("five");

//then
assertFalse(result);

assertThat(set.size(), equalTo(1));
assertThat(set, hasItem("four"));

assertThat(map.size(), equalTo(1));
assertThat(map, hasEntry("four", "4"));
}

@Test
public void removingOnlyEntryFromMapShouldRemoveItemFromKeySet() {
//given
map.put("one", "1");
assertThat(map.size(), equalTo(1));
assertThat(map, hasEntry("one", "1"));

//when
Set<String> set = map.keySet();
final String previousValue = map.remove("one");

//then
assertThat(previousValue, equalTo("1"));
assertTrue(set.isEmpty());

}

@Test
public void removingOnlyEntryFromMapUsingIteratorShouldRemoveFromKeySet() {
//given
map.put("one", "1");
assertThat(map.size(), equalTo(1));
assertThat(map, hasEntry("one", "1"));

//when
Set<String> set = map.keySet();
final Iterator<Map.Entry<String, String>> iterator = map.entrySet().iterator();
iterator.next();
iterator.remove();

//then
assertTrue(set.isEmpty());

}

@Test
public void removingOneOfEntriesFromMapShouldRemoveFromKeySet() {
//given
map.put("three", "3");
map.put("two", "2");
assertThat(map.size(), equalTo(2));
assertThat(map, hasEntry("two", "2"));
assertThat(map, hasEntry("three", "3"));

//when
Set<String> set = map.keySet();
final String previousValueForKeyOne = map.remove("one");
final String previousValueForKeyTwo = map.remove("two");

//then
assertNull(previousValueForKeyOne);
assertNotNull(previousValueForKeyTwo);

assertThat(set.size(), equalTo(1));
assertThat(set, not(hasItem("two")));
assertThat(set, hasItem("three"));
}

@Test
public void removingOneOfEntriesFromMapUsingIteratorShouldRemoveFromKeySet() {
//given
map.put("three", "3");
map.put("two", "2");
assertThat(map.size(), equalTo(2));
assertThat(map, hasEntry("two", "2"));
assertThat(map, hasEntry("three", "3"));

//when
Set<String> set = map.keySet();
final Iterator<Map.Entry<String, String>> iterator = map.entrySet().iterator();
final Map.Entry<String, String> entry = iterator.next();
iterator.remove();

//then
assertThat(set.size(), equalTo(1));
assertThat(set, not(hasItem(entry.getKey())));
}

@Test
public void removingNotExistingEntryFromMapShouldNotChangeKeySet() {
//given
map.put("four", "4");
assertThat(map.size(), equalTo(1));
assertThat(map, hasEntry("four", "4"));

//when
Set<String> set = map.keySet();
final String previousValueForKeyFive = map.remove("five");

//then
assertNull(previousValueForKeyFive);

assertThat(set.size(), equalTo(1));
assertThat(set, hasItem("four"));
}

@Test
public void addingEntryToMapShouldAddItemToKeySet() {
//given
assertThat(map.size(), equalTo(0));

//when
Set<String> set = map.keySet();
map.put("two", "2");

//then
assertThat(set.size(), equalTo(1));
assertThat(set, hasItem("two"));
}

}



Try a little of TDB (test driven bug-fixing) and see how great bug-fixing can be, when unit tests tell you exactly, if you’ve done your job correctly. Happy coding!

December 1, 2009

Chain of responsibility pattern meets Spring, JPA, Wicket and Apache CXF part 2/2

In the first part of this article I have shown a semi-real life example of the Chain of responsibility pattern (also mentioning about Iterator, Adapter and DTO). This behavioral design pattern has been used to control the process of registering a car, consisting of several steps. Everything worked es expected but modifying the chain configuration required application restart. Also not everyone might enjoy editing Spring context XML files. We will address this issues and make our application more dynamic.

If not storing the chain configuration in Spring file directly, then where? Of course in the database, preferably using JPA. This is the JPA entity that will serve as a single handler configuration:

public class RegistrationChainHandlerConfig implements Serializable {
private int id;
private String handlerName;
private int priority;
private boolean enabled;
/* getters/setters */
}


Each handler configured as a Spring bean is going to have a corresponding RegistrationChainHandlerConfig instance (and database row as well). handlerName is a Spring bean name, priority is simply used to control the order of handlers. The bigger priority, the sooner this handler will be executed. Also enabled attribute has been introduced – instead of decreasing the priority (probably moving the handler after CatchAllHandler) it can be simply disabled and temporarily ignored.

The configuration is moved to the database, but how this particular table is going to be populated? We can provide SQL script and update it every time new handler is added or removed from the application. But it is cumbersome and easy to miss when updating the application. We could also provide web user interface to provide CRUD functionality on this table. Actually we will, but with a functionality limited to modifying existing entities (-RU-). So how is the data going to be initially populated with handlers configuration? Well, we are going to discover all available handlers at application startup and keep them in sync without any user or administrator attention! Thanks to this brilliant mechanism whenever developer adds any new Spring bean implementing RegistrationChainHandler, it is going to be picked up and ready to serve in chain. So let’s go!

The first step and a sad part already: Spring does not have a built-in support for running code (preferably given method of arbitrary Spring bean) after the context has successfully started. You can use init-method attribute, @PostContruct [1] or InitializingBean to perform some logic after particular bean is created. But, as far as I know, no such option exist to run some logic after whole context is set up. Luckily, all you need (except love of course) to work around this problem is to subclass ContextLoaderListener and override contextInitialized() with a very awkward code:

public class CarRegistrationContextLoaderListener extends ContextLoaderListener {

@Override
public void contextInitialized(ServletContextEvent event) {
super.contextInitialized(event);
ApplicationContext context = WebApplicationContextUtils.getRequiredWebApplicationContext(event.getServletContext());

refreshRegistrationChainHandlers(context);
}

private void refreshRegistrationChainHandlers(ApplicationContext context) {
RegistrationChainRefresher refresher = (RegistrationChainRefresher) context.getBean("databaseRegistrationChainProvider");
refresher.refreshHandlers();
}
}


This is horrible for two reasons: first is using awkward WebApplicationContextUtils and obtaining bean by name. The second reason is that running super() in overridden method is actually an anti-pattern. But I hope this tremendous code is justified by the fact, that I am only working around featureless Spring. If you know a better way, please enlighten me! Oh, you must of course point newly created class in web.xml:

<listener>
<listener-class>com.blogspot.nurkiewicz.cars.CarRegistrationContextLoaderListener</listener-class>
</listener>


You probably wonder how does the implementation of RegistrationChainRefresher look like. Everything for you, my dearest Reader:


public class DatabaseRegistrationChainProvider implements RegistrationChainRefresher {

@Resource
private RegistrationChainDao registrationChainDao;

@Resource
private ListableBeanFactory beanFactory;

@Override
@Transactional
public void refreshHandlers() {
List<String> existingHandlers = registrationChainDao.getAllHandlersNames();
Map<String, Object> handlersMap = beanFactory.getBeansOfType(RegistrationChainHandler.class);
List<String> availableHandlers = new ArrayList<String>(handlersMap.keySet());
removeNotAvailableHandlers(existingHandlers, availableHandlers);
addNewAvailableHandlers(existingHandlers, availableHandlers);
}
/* ... */
}


The code is not so sophisticated as it sounded, although I skipped logging and huge part of logic, but core has left. As you can see first we load all the handlers in the database (existingHandlers) – this list is empty when running for the first time. Then we obtain all Spring beans which implement RegistrationChainHandler (availableHandlers). This sounds complicated but is actually very simple since Spring provides utility for that. Simply inject ListableBeanFactory or implement BeanFactoryAware.

I hope that names removeNotAvailableHandlers() and addNewAvailableHandlers() are descriptive enough and speak for themselves. First one scans through the handlers already found in the database and removes those, which are no longer present in Spring application context. The second one does the opposite: it goes through all Spring beans implementing handler interface and, if they yet do not exist in the database, adding them with default configuration. The defaults are: biggest priority (beginning of the chain) but disabled.

If you wonder why not simply clear the database table and repopulate it each time the application is started, the answer is very simple. When this process adds new handler, it puts it at the beginning of the chain. But since the order in which Spring beans are processed is undetermined, you end up with some random chain configuration. It is up to user (by using the GUI which is just about to be implemented) to customize the chain and persist it. If the database was cleared every time, the user would have to configure the chain all over.

I skipped lots of code here, but before we see it in action, there is one important thing left: constructing the chain. In the first approach chain (called handlersList) was just a list of Spring beans constructed by the Spring framework. Now we have a database table holding bean names. It can be retrieved using the following EJB QL query:


<named-query name="RegistrationChainHandlerConfig.handlerChain">
<query><![CDATA[
SELECT config.handlerName
FROM RegistrationChainHandlerConfig config
WHERE config.enabled = true
ORDER BY config.priority DESC
]]></query>
</named-query>



This query returns Spring bean names every time new request (car) is handled by the web service and needs to be handled by our chain. Being familiar with BeanFactory interface, we can load the actual bean instances based on their Spring symbolic names:

private List<RegistrationChainHandler> resolveHandlersByName(List<String> handlersNames) {
List<RegistrationChainHandler> handlers = new ArrayList<RegistrationChainHandler>(handlersNames.size());
for (String handlerName : handlersNames)
handlers.add((RegistrationChainHandler) beanFactory.getBean(handlerName, RegistrationChainHandler.class));
return handlers;
}


BTW the same code using Groovy, aren’t closures great?

private List<RegistrationChainHandler> resolveHandlersByName(List<String> handlersNames) {
handlersNames.collect { beanFactory.getBean(it, RegistrationChainHandler) }
}


Having all this we run the application and see what’s in the database. This time I used H2 database because I didn’t want to install any full-fledged relational database on my old laptop. H2 not only can be used within JUnit in in-memory mode, but also can be run as a stand-alone, transactional (ACID!), persistent data store with its own web interface. Look how easy it is:

<bean id="h2Server" class="org.h2.tools.Server" factory-method="createTcpServer" init-method="start" destroy-method="stop" depends-on="h2WebServer">
<constructor-arg value="-tcp,-tcpAllowOthers,true,-tcpPort,9092,-baseDir,~/.cars/db"/>
</bean>
<bean id="h2WebServer" class="org.h2.tools.Server" factory-method="createWebServer" init-method="start" destroy-method="stop">
<constructor-arg value="-web,-webAllowOthers,true,-webPort,8082"/>
</bean>

<bean id="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource" destroy-method="close" depends-on="h2Server">
<property name="driverClass" value="org.h2.Driver"/>
<property name="jdbcUrl" value="jdbc:h2:tcp://localhost:9092/cars"/>
<property name="user" value="sa"/>
<property name="acquireRetryAttempts" value="1"/>
</bean>


This is enough to:
  • start the database that listens on 9092 TCP port
  • start embedded web server on 8082 port (interactive web console with auto-completion!)
  • create a DataSource using this database

Database is embedded within the application (it starts and stops together with Spring application context) and stores data in specified directory (/cars/db in current user home directory). Despite that, it works like a charm, see for youself:




Also you can see the random chain configuration. If we were to run our SoapUI functional test prepared in previous article, familiar error message would appear that the end of chain has been reached. Actually, the request road wasn’t so long – since all handlers are disabled by default, no handler has been executed before reaching the end.

Although we could actually configure the chain now using SquirrelSQL or H2 web UI manually, we will develop web interface in Wicket in just a moment. First please take a look at two handlers which were not mentioned in the first part of this article:


public class FakeHandler implements RegistrationChainHandler {

@Override
public long handle(Car car, RegistrationChain chain) throws Exception {
car.setId(RandomUtils.nextLong());
return car.getId();
}
}


This is a solution for a common problem in my job: during functional or load-testing some external systems which we integrate with are too hard to configure or simply unavailable. Because the tests must go on, we build fakes and mocks that mimic the behavior of external, third-party system and work on them as long as the real system is not available. Sometimes we even build several fakes, some with hardcoded data while others are configured from a flat file. But the biggest problem is switching the implementations back and forth. Even when both fake and real implementations have the same abstract interface (so switching the implementation has no impact on the rest of the code), the application must somehow discover which implementation to use at the moment (Spring context XML, properties file, JNDI property, etc.) Using the chain of responsibility pattern makes this usage scenario very clear and easy to develop. When you want to use fake, simply enable its handler (and make sure it comes before the real implementation handler). But when the real implementation should be used, disable fakeHandler and let the control pass through to the right handlers. You might even develop few fake handlers and enable/disable/arrange them in any way you want.

The second new handler is just a demonstration of Java/Spring/Groovy integration and it implements the retry-after-failure behavior:

public class GroovyHandler implements RegistrationChainHandler {

private static final Logger log = LoggerFactory.getLogger(GroovyHandler.class);

int count = 5

public long handle(Car car, RegistrationChain chain) {
def ex
for (int attemptNo = 1; attemptNo <= count; ++attemptNo)
try {
log.trace "Running next handler attempt $attemptNo/$count"
return chain.proceed(car)
} catch (Exception e) {
log.warn "Attempt $attemptNo/$count failed", e
car.id = 0
car.registrationNo = 0
ex = e
}
throw new CarRegistrationException("Car registration failed after $count attempts. Last error: $ex", ex);
}

}


Not much is saved thanks to Groovy, but this is just a example. Declaring Spring bean based on this source code is as follows (note the count property being injected by Spring):

<lang:groovy id="groovyHandler" script-source="classpath: GroovyHandler.groovy">
<lang:property name="count" value="2"/>
</lang:groovy>



Now the promised web interface in Wicket. The idea is to allow system/business administrator to alter the car registration chain configuration by moving handlers and enabling/disabling them straight from user-friendly, web-based interface. This also happens to be my first (but certainly not last!) Wicket web application. We start by creating HTML view. That’s right, no JSP, EL, JSTL, Taglibs, scriptles, templates, tag files, etc. Pure HTML:

<?xml version="1.0" encoding="UTF-8"?><!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "DTD/xhtml1-strict.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
<head>
<title>Car registration handlers chain configuration</title>
<style type="text/css"><!-- --></style>
</head>
<body>
<table>
<thead>
<tr>
<th>Id</th>
<th>Handler name</th>
<th>Priority</th>
<th>Enabled?</th>
<th>Actions</th>
</tr>
</thead>
<span wicket:id="handlersList">
<tr>
<td><span wicket:id="id">1</span></td>
<td><span wicket:id="handlerName">fakeHandler</span></td>
<td><span wicket:id="priority">8</span></td>
<td><span wicket:id="enabled">yes </span> (<a href="#" wicket:id="disableLink">disable</a><a href="#" wicket:id="enableLink">enable</a>)</td>
<td><a href="#" wicket:id="upLink">up</a> <a href="#" wicket:id="downLink">down</a></td>
</tr>
</span>
</table>
</body>
</html>


Nothing fancy. Now the corresponding page implementation:


public class RegistrationChainConfigPage extends WebPage {

private List<RegistrationChainHandlerConfig> handlersConfig = new ArrayList<RegistrationChainHandlerConfig>();

@SpringBean
private RegistrationChainConfiguration chainConfigration;
private final HandlersListView handlersListView;

public RegistrationChainConfigPage() {
handlersListView = new HandlersListView();
loadConfigs();
add(handlersListView);
}

private void loadConfigs() {
handlersConfig = chainConfigration.getAllHandlersConfig();
handlersListView.setModelObject(handlersConfig);
}

private class HandlersListView extends ListView<RegistrationChainHandlerConfig> {

public HandlersListView() {
super("handlersList", handlersConfig);
}

@Override
protected void populateItem(ListItem<RegistrationChainHandlerConfig> item) {
RegistrationChainHandlerConfig config = item.getModelObject();
item.add(new Label("id", new Model<Integer>(config.getId())));
item.add(new Label("handlerName", config.getHandlerName()));
item.add(new Label("priority", new Model<Integer>(config.getPriority())));
item.add(new Label("enabled", BooleanUtils.toStringYesNo(config.isEnabled())));
item.add(new EnableDisableLink(config, true));
item.add(new EnableDisableLink(config, false));
item.add(new SwitchPriorityLink(item.getIndex(), true));
item.add(new SwitchPriorityLink(item.getIndex(), false));
}

private class EnableDisableLink extends Link {

private final RegistrationChainHandlerConfig config;

public EnableDisableLink(RegistrationChainHandlerConfig config, boolean enable) {
super(enable ? "enableLink" : "disableLink");
this.config = config;
setVisible(config.isEnabled() && !enable || !config.isEnabled() && enable);
}

@Override
public void onClick() {
config.setEnabled(!config.isEnabled());
chainConfigration.update(config);
}
}

private class SwitchPriorityLink extends Link {

RegistrationChainHandlerConfig first;
RegistrationChainHandlerConfig second;

public SwitchPriorityLink(int index, boolean up) {
super(up ? "upLink" : "downLink");
first = handlersConfig.get(index);
if (up) {
if (index > 0)
second = handlersConfig.get(index - 1);
else
setVisible(false);
} else {
if (index + 1 < handlersConfig.size())
second = handlersConfig.get(index + 1);
else
setVisible(false);
}
}

@Override
public void onClick() {
chainConfigration.switchPriorities(first, second);
loadConfigs();
}
}

}
}


So much has been said lately about Wicket that explaining this code is pointless. Actually, it is rather easy to read and understand, especially read together with corresponding HTML (focus on wicket:id attributes). Enough to say is that this page displays database-backed table with a few links controlling each handlers’ position and availability.

In about 100 lines of Java code (service layer RegistrationChainConfiguration class has been skipped ) and a pure HTML I have created web page from scratch, implementing two use cases. And all that with tiny Wicket background. I am starting to shiver when thinking about the same task in Struts 2...

Finally! Here is the result and the final chain configuration few clicks later:




Was it all worth it? All this logic, DAO, web interface – since all we had to do was to implement a simple business process with few steps? Well, stories that you can turn logging and validation on and off at runtime might not convince you. Also the ability to change the order of some operations might not be sufficient. But what about this scenario? A new team member has been given a task of implementing another step in car registration process: if the car has been manufactured more than 20 years ago, the registration should fail immediately. If the car is between 10 and 20 years, registration should succeed, but JMS message containing newly registered car must be sent for further validation.

In a traditional approach a new developer would find some place in web service implementation and inject his or her code in a reasonably looking place. This is not only complicated, because lots of existing code must be studied, but also error-prone, very likely breaking existing functionality. But when using chain of responsibility pattern, each handler is decoupled from the others, so the developer only focuses on the handler he or she creates. The handler can be easily unit tested, without worrying about other handlers behavior.

So the developer sat for a day or two, quickly discovered how RegistrationChainHandler interface work and wrote new handler:



@Service
public class DateManufacturedValidatorHandler implements RegistrationChainHandler {

private int warnIfOlderThanYears = 10;
private int failIfOlderThanYears = 20;

@Resource
private JmsTemplate jmsTemplate;

public long handle(Car car, RegistrationChain chain) throws Exception {
failIfTooOld(car);
chain.proceed(car);
warnIfTooOld(car);
return car.getId();
}

private void failIfTooOld(Car car) {
if (beforeGivenYearsToPresent(car.getDateManufactued(), failIfOlderThanYears))
throw new CarRegistrationException("Car has been manufactured more than " + failIfOlderThanYears + " years ago");
}

private void warnIfTooOld(final Car car) {
if (beforeGivenYearsToPresent(car.getDateManufactued(), warnIfOlderThanYears))
jmsTemplate.send(car);
}

private static boolean beforeGivenYearsToPresent(Calendar date, int years) {
Calendar beforeDate = Calendar.getInstance();
beforeDate.add(Calendar.YEAR, -years);
return date.before(beforeDate);
}
}


Pretty straightforward. Developer showed this class to his/her boss and asked how to plug this handler to existing ones, having no idea about this whole auto-discovery, database-backed, web controlled process. The boss just smiled, built the application with a single new a class and run it. No existing classes were changed, not even a single XML line not mentioning the database. But the new handler has been picked up after application restart, ready to be configured and serve:


The boss put the new handler between transactionalHandler and storeCarHandler and enabled it. Few days later he changed his mind, moving dateManufacturedValidatorHandler before transactionalHandler, as it does not have to participate in a transaction (just one click in user interface). Unfortunately, after going on production administrators discovered JMS connection leak. Sending JMS messages must have been temporarily disabled. Guess how? Are you still not convinced? You must admit the concept is tempting...