Category Archives: Wicket

Abbreviated component paths in wicket tester

Wicket tester combined with Mockito is fantastic for unit testing your web application. However, developing the tests is harder than it should be because you have to refer to components by their path rather than their id.

For example, to clock the OK button on a page, I need something like:

tester.executeAjaxEvent(“border:form:pagetitlecontainer:ok”. “onclick”);

i.e. instead of “ok”, I must refer to the button by its full path “border:form:pagetitlecontainer:ok”. This seems tedious – if I know that I only have one component on the page with the id “ok”, why can’t I just use “ok”. Wicket tester should notice that the component is not available and traverse the component hierarchy for it. If its ambiguous then it can complain, but if not, then it should be OK.

To get around this limitation, we override the getComponentFromLastRenderedPage method of the WicketTester class as follows:

@Override
public Component getComponentFromLastRenderedPage(final String path) {
	// first check if we can find the component with the specified path - if not, check if its an abbreviated path
	String fullPath = lookupPath(getLastRenderedPage(), path);
	if (fullPath == null)
		return null;

	return super.getComponentFromLastRenderedPage(fullPath);
}

public String lookupPath(final MarkupContainer markupContainer, final String path) {
	// try to look it up directly
	if (markupContainer.get(path) != null)
		return path;

	// if that fails, traverse the component hierarchy looking for it
	final List<component> candidates = new ArrayList<component>();
	markupContainer.visitChildren(new IVisitor<component>() {
		private static final long serialVersionUID = 1L;

		Set<component> visited = new HashSet<component>();

		@Override
		public Object component(Component c) {
			if (!visited.contains(c)) {
				visited.add(c);

				if (c.getId().equals(path))
					candidates.add(c);
			}
			return IVisitor.CONTINUE_TRAVERSAL;
		}
	});
	// if its unambiguous, then return the full path
	if (candidates.isEmpty()) {
		fail("path: '" + path + "' not found for " +
				Classes.simpleName(markupContainer.getClass()));
		return null;
	} else if (candidates.size() == 1) {
		String pathToContainer = markupContainer.getPath();
		String pathToComponent = candidates.get(0).getPath();
		return pathToComponent.replaceFirst(pathToContainer + ":", "");
	} else {
		String message = "path: '" + path + "' is ambiguous for " + Classes.simpleName(markupContainer.getClass()) + ". Possible candidates are: ";
		for (Component c : candidates) {
			message += "[" + c.getPath() + "]";
		}
		fail(message);
		return null;
	}
}

Wicket needs a component catalog

I’m a big fan of Apache Wicket, but there’s an urgent need for a better-organized component-ecosystem around Wicket. To write a real web application you need a framework (that’s Wicket) and visual components (that’s JQuery, YUI, Recaptcha etc) and you need the two to work together smoothly.

A newcomer to Wicket should be impressed by the clean, component-oriented approach to producing the GUI for his application, but a production web application needs more than just HTML. So, inevitably, the next step is to try to find the stuff which will make your web-application look like all those other web 2.0 sites out there. However, very few of the Wicket components referenced from the Wicket home pages are “best-of-breed” and a certain amount of disappointment soon sets in.

Take the wicket example captcha implementation for example. There are two problems here: (a) the implementation produces a captcha image which is not only difficult for robots to read, but also pretty impossible for humans and (b) everybody else is already using recaptcha so why even bother distracting developers with yet-another home-spun implementation.

The Wicket community might react by saying “well, there are enough blogs describing how to use recaptcha with Wicket, so where’s the problem?”. Well the problem is that these blogs typically provide their description in a way which reflects their own expertise rather than that of the reader, which means that a novice Wicket programmer may or may not be able to follow the instructions to successfully integrate recaptcha into his application.

Or to put it another way, developers blogs are not a substitute for organized, tested and documented component libraries.

What could help, on the other hand, is a catalog of components, with ratings and a compatibility matrix indicating tested interoperability with other components/browsers etc.

By the way what prompted me to write this post was that yesterday I finally used a few of the Visural Wicket components (based on JQuery) and they are fantastic – well thought out APIs, styling etc. What I don’t understand is that mediocre-to-lousy versions of equivalent components (such as the Wicket extensions modal window or the wicketstuff lightbox) feature much more prominently on the Wicket sites, so the novice programmer is far more likely to use them (and be bitterly disappointed) than to use Visural Wicket (and be delighted).

Wicket adoption would likely be accelerated if the end-to-end experience of producing the first production web application involved a bit less trial-and-error and a bit more delight.

Wicket 1.4 and browser tabs

We had an amazingly annoying problem in a Wicket application. A specific user was continuously having problems with ajax controls on pages (search fields, auto-complete fields etc). The problems were caused by PageExpiredExceptions. We couldn’t understand why only this one user had these problems. This went on for ages, until today I found out that Wicket 1.4 sets a default limit of 5 page maps per session. This specific user typically worked with multiple browser tabs on the application and once he went over 5, some of the page maps got evicted and the ajax stuff started failing.

The solution was to call “getSessionSettings().setMaxPageMaps(100)” to allow up to 100 page maps per session.