Tuesday, March 27, 2012

Apache Wicket: Stateless to Stateful

For a brand new Wicket application, it starts as Stateless.
After you add your first page to it, you can see that it is Stateless (the URL does not have any
?0, ?1, etc. in it.)
There are other posts about cookies and ;jsessionid, how Tomcat always start by passing both, url rewriting with Tuckey urlrewrite, etc.

However, most page components are Stateful so the moment you add any of these components to your page, the whole page turns Stateful and you start to see ?0, ?1, etc. in your URL.

To keep the page Stateless, you cannot use anything that records state: Ajax, Modal window, etc. can no longer be used. Instead of Form, you use StatelessForm.
But if you add any Stateful component to the StatelessForm, it turns Stateful.
Wicket-extensions add components such as StatelessAjaxFallbackLink, etc. to help but not all components could be made Stateless.

If your page is Stateless, the whole session created by Wicket is marked as temporary:
getSession().isTemporary() will return true.

To record custom session information, the standard way is to extend your own Session:

public class CustomSession extends WebSession {

private UserInfo user;
public CustomSession(Request request) {
super(request);
}

// Java 1.5 Covariance
public static CustomSession get() {
return (CustomSession) Session.get();
}

... getter and setter for user
}

In your WebApplication, you override newSession()

@Override
public Session newSession(Request request, Response response) {
return new CustomSession(request);
}

and in your code, you do

CustomeSession mySession = CustomSession.get();

Stateless page is useful.
For example, it makes sense that a Login page should be Stateless.

But if the page is Stateless, since the session will be marked temporary,
a new session is always re-created whenever you go to the next page.
You will lose your custom information with a Stateless page.

You want to switch from Stateless to Stateful before you navigate to the next page.

In your code, you can do this:

// User authenticated
if (getSession().isTemporary()) {
getSession().bind();
}
and then you start passing custom information around:
CustomSession.get().setUser(user);