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:

final StatelessForm form = new StatelessForm("loginForm", new CompoundPropertyModel(this)) {
 private static final long serialVersionUID = 1L;

 @Override
 protected void onSubmit() {
  try {
   validateUser(userid_or_email, password);
   if (getSession().isTemporary()) getSession().bind();
   // this makes the temporary session used by the stateless login page permanent
   ...
  }
  catch (Exception e) {
   error(e.getMessage());
  }
 }
};

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…”

public class MyStatelessPage extends BasePage {

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

		if (Settings.isOperatingModeDevelopment())
			checkIfPageStateless(this);
	}

	private void checkIfPageStateless(Page p) {
		if (!p.isPageStateless()) {
			// find out why
			final List statefulComponents = new ArrayList();
			p.visitChildren(Component.class, new IVisitor() {
				public Object component(Component component) {
					if (!component.isStateless())
						statefulComponents.add(component);
					return CONTINUE_TRAVERSAL;
				}
			});

			String message = "Whoops! this page is no longer stateless";
			if (statefulComponents.size() > 0) {
				message += " - the reason is that it contains the following stateful components: ";
				for (Component c : statefulComponents) {
					message += Settings.getNewLine() + c.getMarkupId();
				}
			}
			p.warn(message);
		}
	}
}

Leave a Reply

Your email address will not be published.

This site uses Akismet to reduce spam. Learn how your comment data is processed.