Tag Archives: Wicket

Simple form validation in Wicket

I used to add custom FormValidators to forms where multi-field validation was required (like checking if two copies of an entered password match.

However, this approach has some problems – I had to list the dependent components and if some of them were hidden at validation time, the validator didn’t work.

Reading around, I saw the recommendation to use the onValidate() method of the form to do validation and this seems a lot more straightforward.

Here’s a sample wicket form with some validation logic to check if the current password matches and if the two copies of the new password are the same.

final Form form = new Form("form", new CompoundPropertyModel(user)) {
	private static final long serialVersionUID = 1L;

	@Override
	protected void onValidate() {
		super.onValidate();

		User user = model.getObject();
		String current_password_entered = currentPasswordField.getConvertedInput();
		String new_password_entered = newPasswordField.getConvertedInput();
		String confirm_new_password_entered = confirmNewPasswordField.getConvertedInput();

		if (current_password_entered != null
		&& !User.encryptPassword(current_password_entered).equals(user.getPassword()))
			error(getString("current_password_not_correct"));

		if (new_password_entered != null && !new_password_entered.isEmpty()) {
			if (new_password_entered.equals(current_password_entered)) {
				error(getString("new_password_same_as_current_password"));
			} else {
				if (!new_password_entered.equals(confirm_new_password_entered))
					error(getString("new_passwords_dont_match"));
			}
		}
	}
};
add(form);

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.

Clustering wicket apps

After fooling around with other methods, we finally accepted the advice I got on the Wicket IRC channel and used Terracotta to cluster our Wicket-based apps running under Jetty. It turned out to be straightforward to implement.

The first thing to do was to add the Terracotta dependencies to our pom.xml.

<dependency>
	<groupId>org.terracotta.session</groupId>
	<artifactId>terracotta-session</artifactId>
	<version>1.1.1</version>
</dependency>

<dependency>
	<groupId>org.terracotta</groupId>
	<artifactId>terracotta-toolkit-1.1-runtime</artifactId>
	<version>2.0.0</version>
</dependency>

Then you just need to add a Terracotta filter to the jetty WebAppContext as follows:

FilterHolder tcFilterHolder = new FilterHolder(TerracottaJetty61xSessionFilter.class);
tcFilterHolder.setInitParameter("tcConfigUrl", "terracotta:9510,terracotta2:9510");
context.addFilter(tcFilterHolder, "/*", Handler.ALL);

That’s it. Terracotta will cluster the session (in the example we’re using two terracotta servers called “terracotta” and “terracotta2” – a main server and a standby).

We’re using a HAProxy load-balancer with session affinity to load-balance and failover the wicket apps. Note that we are only clustering the session and not the Wicket PageMapStore. This means that if the app fails over, the browser back-button will not work correctly after a failover. Since failover should only occur rarely, if ever, we don’t see the need to cluster the PageMapStore (although this is not hard either) and incur the network cost of replicating the PageMapStore.

Wicket and focus

Our first approach was to create a DefaultFocusBehavior (as described by Julian Sinai) and attach it to the component which should receive the focus. The problem with this is that after a validation error during a submit, you usually want the focus to jump to the first invalid field, so the user can easily correct his erroneous input. The problem with the DefaultFocusBehavior is that the component to which you added it still has it and will try to grab the focus again. We created two methods for handling focus in our BasePage class (from which all of our application pages are inherited) – setFocus and setFocusToFirstInvalidComponent. The first one is called during page initialization and the second on validation failure. They share enough class variables which allow them to ensure that only one component has the DefaultFocusBehavior at a time.

Using the HTML TBODY tag as a container for table rows

A common issue which Wicket developers face is the need for an AJAX update of the HTML output of a repeater (such as a ListView) which is part of a HTML table (where the repeating element is represented by a single <tr wicket:id=”mylist”> line in the table). The problem is that you can’t just use “target.addComponent(mylist)” – you need some kind of container around the repeater. Using a nested table or div as a container may interfere with your table layout.

The solution is to use a <tbody wicket:id=”mylistcontainer”> tag around the <tr> which you can add to your page with a WebMarkupContainer and then pass to target.addComponent. It provides you with a container around one or more table rows which you can address from Wicket without messing up your table layout.

A Wicket form validator for a list of email addresses

I needed to validate a list of email addresses entered into a Wicket text area (a cc: list of email addresses). To do this, I created a simple form validator which breaks up the list from the text area into individual email addresses and then uses the EmailAddressValidator to validate them individually. It illustrates a few Wicket techniques: (a) how to validate a field containing several values which need to be validated individually and (b) how to use a Validator against a string instead of a form component. Anyway, here’s the code in case its of use to anyone.

To use it, add it to the form as follows:

“label for” in wicket panels

Labels for checkboxes weren’t working as I expected in wicket panels (i.e. when I clicked the label, the checkbox didn’t react). Looking at the output html I saw that the id of the checkbox had been changed by wicket, so the “label for” was no longer associated with the checkbox. The solution was to use the label without the for (and nest the checkbox within the label tag).

Instead of:

use:

Annotated constraints

We were wondering how to use Hibernate annotations to automatically create constraints (HTML “maxlength”) and validators (required fields, string length validation). After searching around, I found a wicket behavior for this in wicket-stuff from Ryan Sonnek. It was in wicket-stuff 1.3 and apparently had been removed from 1.4. Anyway, I patched it up a bit to make it work in wicket 1.4 and here it is (I also took the liberty of renaming it to AnnotatedConstraintBehavior in case we wanted to use it for annotations other than hibernate):

To use it, you’ll need to have @Length(min=x,max=y) and/or @NotNull hibernate annotations on your objects. The behavior will find these in component models and react accordingly, adding the maxlength attributes to the markup, string validator and setting required.

Wicket PasswordTextField with Strength

I implemented a simple extension of the wicket PasswordTextField which provides you with an indication of the strength of the entered password (using regular expressions and returning “empty”, “weak”, “medium” or “strong”). Strong means at least 7 characters with mixed alphanumeric and non-alphanumeric characters. Medium means at least 6 characters with mixed alpha and non-alpha characters.

Originally I intended to make it a panel with a visual indicator (the usual spectrum from red through yellow to green), but then I figured that allowing the caller to make the styling decisions is better (if you want to display a spectrum, then add images to your styles and set the style on the component using an AttributeModifier – come to think of it, maybe I’ll do another post on how to do that…).

Anyway, here’s the component:

And here’s how to use it:

A sessionless login page for Wicket applications

We’re big fans of Apache Wicket, but as with most frameworks, sometimes the simplest things appear to be hard to do (or at least its hard to find out how to do them). Application session handling is great in Wicket, but I immediately ran into the problem that the problem that the login page of my application would timeout like any other page of the application. If the user logged out (at which point the login page is displayed), left the browser window open and then tried to use the same browser window to login again an hour later, he’d get a “sorry, your session has timed out, please login again”.  This message obviously makes no sense on the login page.

The solution (thanks Doug Donohue for the help on this) is to use a stateless form for the login page (which causes Wicket to only create a temporary session for the page) and when the user has successfully logged in, convert the session to a regular session.

The relevant code fragments are shown below:

Note however that you have to be very careful what components you use in a stateless page – otherwise you’ll suddenly find it to be stateful again (i.e. it will bind its session automatically and you’ll be back in the same situation). Basically anything which requires remembering a specific page instance (e.g. Ajax) will cause your page to become stateful.

There is some logic built into Wicket which should warn you when a page which you expect to be stateless becomes stateful, but it seems that in the latest versions of Wicket, these warnings are disabled. We ended up creating our own StatelessPage super-class which, in onBeforeRender, calls isPageStateless() and if that returns false, it runs through the components on the page and checks isStateless() for each and reports the wicket id for each component which is not stateless. That way, during development we can show a warning like “This page should be stateless, but isn’t because the following components are stateful: component1, component2…”