Daily Archives: January 22, 2008

Showing a “Session Expired” Notice in Seaside

When a Seaside session expires, many of its links become invalid. Sure, you can use the hooks to make certain URLs bookmarkable, but most URLs are session-specific out of necessity. When you click on one after the session expires, Seaside kicks you back to the starting point for the application with no explanation whatsoever. It’d be more polite to tell the user why this happened.

Hat tip to Boris Popov for the initial implementation.

In Seaside, the class WAApplication (via its superclass, WARegistry) knows when an expired session is being accessed, so in order to implement a notice like this, you first have to make your own custom WAApplication subclass.

WAApplication subclass: #MyApplication
  instanceVariableNames: ''
  classVariableNames: ''
  poolDictionaries: ''
  category: 'MySeasideStuff'

When a session expires, the core handling happens in WARegistry. But it gives us a chance to specify the URL path we want to use when something expires. In this case, we’ll tack the keyword “expired” onto the end:

MyApplication>>expiryPathFor: aRequest
  ^aRequest url , '/expired'

Once this is done, you have to register your Seaside application as an instance of MyApplication instead of WAApplication. This is how I did it:

MyRootClass class>>applicationNamed: aString
  | application |
  application := MyApplication named: aString.
  application configuration addAncestor: WARenderLoopConfiguration new.
  application preferenceAt: #rootComponent put: self.

Then it’s just a matter of implementing the proper handling in your root component or one of its initial presenters. In my case, my root component holds a task, and the task calls a login component to prompt for username and password. The login component is already set up to display error messages, so we’ll use that here:

MyTask>>initialRequest: aRequest
  super initialRequest: aRequest.
  (aRequest url last: 7) = 'expired'
      [loginDialog error: 'Your session has expired. Please sign in again.']

This works the way we intend, but it has a side effect. Since we are using [self session expire] when a user clicks a “logout” link, even legitimate logouts look like a session expiration. We end up showing our expiration message every time somebody logs out, which is not what we want.

Instead, we need to force a redirect after a legitimate logout:

  self expire.
  self redirectTo: self currentRequest url.

Now we change our logout callbacks, and we’re done!

MyComponent>>renderContentOn: html
  (html anchor)
    callback: [self session logout];
    with: 'Logout'.

We can test this by logging into the application, clicking the logout link, and then using the back button to get back to an application screen. Clicking any link on the page takes us to the back to the initial screen with the new notice shown.

Dialog showing expired session message


Filed under Seaside