18.3Customizing the Session for Login
We will now implement an extremely simple login facility to show how to use a custom session. We will enhance the miniInn
application we developed in Chapter 13 and add a login facility.
When a user interacts with a Seaside application for the first time, an instance of the application’s session class is created. The class WASession
is the default session class, but this can be changed for each application, allowing you to store key information on this class. Different parts of the system will then be able to take advantage of the information to offer different services to the user.
We will define our own session class and use it to store user login information. We will add login functionality to our existing component. The login functionality could also be supported by using a task and/or a specific login component. The principle is the same: you use the session to store some data that is accessible from everywhere within the current session.
In our application we want to store whether the user is logged in. Therefore we create a subclass called InnSession
of the class WASession
and we will associate such a new session class to our hotel application. We add the instance variable user
to the session to hold the identity of the user who is currently logged in.
WASession subclass: #InnSession
instanceVariableNames: 'user'
classVariableNames: ''
poolDictionaries: ''
category: 'SeasideBook'
We define some utility methods to query the user login information.
InnSession>>login: aString
user := aString
InnSession>>logout
user := nil
InnSession>>isLoggedIn
^ user isNil not
InnSession>>user
^ user
Now you need to associate the session we just created with your existing application; you can either use the configuration panel or register the new application setup programmatically.
Configuration Panel. To access the configuration panel of your application go to http://localhost:8080/config/. In the list select your application (probably called ‘miniinn’) and click on its associated configure link. You should get to the configuration panel which lists several things such as: the library your application uses (see Part V); and its general configuration such as its root component (see Chapter 23).
Click on the drop-down list by Session Class — if there is only text here, press the override link first . Among the choices you should find the class InnSession
. Select it and you should get the result shown in Figure 127. Now Save your changes.
Configuring the application programmatically. To change the associated session of an application, we can set the preference #sessionClass
using the message WASession>>preferencesAt:put:
. We can do that by redefining the class initialize
method of the application as follows. Since this method is invoked automatically only when the application is loaded, make sure that you evaluate it manually after changing it.
MiniInn class>>initialize
| application |
application := WAAdmin register: self asApplicationAt: 'miniInn'.
application preferenceAt: #sessionClass put: InnSession
To access the current session use the message WAComponent>>session
. We define the methods login
and logout
in our component.
MiniInn>>login
self session login: (self request: 'Enter your name:')
MiniInn>>logout
self session logout
Then we define the method renderLogin:
which, depending on the session state, offers the possibility to either login or logout.
MiniInn>>renderLogin: html
self session isLoggedIn
ifTrue: [
html text: 'Logged in as: ' , self session user , ' '.
html anchor
callback: [ self logout ];
with: 'Logout' ]
ifFalse: [
html anchor
callback: [ self login ];
with: 'Login']
We define a dummy method renderSpecialPrice:
to demonstrate behavior only available for users that are logged in.
MiniInn>>renderSpecialPrice: html
html text: 'Dear ' , self session user, ', you can benefit from our special prices!'
Then we redefine the method renderContentOn:
to present the new functionality.
MiniInn>>renderContentOn: html
self renderLogin: html.
html heading: 'Starting date'.
html render: calendar1.
startDate isNil
ifFalse: [ html text: 'Selected start: ' , startDate asString ].
html heading: 'Ending date'.
html render: calendar2.
(startDate isNil not and: [ endDate isNil not ]) ifTrue: [
html text: (endDate - startDate) days asString ,
' days from ', startDate asString, ' to ', endDate asString, ' ' ].
self session isLoggedIn "<-- Added"
ifTrue: [ self renderSpecialPrice: html ]
Figure 128, Figure 129 and Figure 130 illustrate the behavior we just implemented. The user may log in using the top level link. Once logged in, extra information is available to the user.