Chris Greenhalgh, 2007-02-02; last updated 2007-02-05
The tutorial includes an implementation of a simple active web
site/application. This is minimally specified in EQUIP2_WebApp_Tutorial_Application_Specification.html.
This document defines/describes the structure of the Website for the
game and the basic HTTP interactions it supports.
Note that this tutorial (and the application itself) is incomplete,
but it already has quite a lot of useful examples. E.g. player
registration, login, and custom form-based adding and editing of
dataspace objects.
The web pages are generated from JSPs in WEB-INF/jsp/publicweb/.
Simple HTML Cascading StyleSheet (CSS) for some page formatting; the
style file is site/publicweb.css
(i.e. outside WEB-INF/
and therefore served directly by Tomcat as a static file).
Web-related Java classes (form-backing beans and controllers) are in
Java package equip2.webapptutorial.publicweb.
The database classes are as already described in EQUIP2_WebApp_Defining_the_Dataspace.html.
The web functionality is organised with the path .../publicweb/... and is
handled by the Spring Dispatcher servlet 'publicweb', which is
configured by WEB-INF/publicweb-servlet.xml.
Messages from controllers (typically form rejection messages) are
specified in WEB-INF/classes/publicweb.properties
(as configured in the Servlet's message resolver).
The application relies on the identification of players as they use
the site. It further distinguishes between three main player types:
admin, trusted and untrusted.
The first element of the site/application is a new player
registration area. In the initial application a simple single-stage
registration is supported via the the URL http://.../publicweb/register.html.
This is generated from the JSP register_form.jsp
(the configured formView
of the controller, below), which in turn uses jsp:include actions to
generate the individual form elements from the JSP register_form_input.jsp.
Form submission is a HTTP POST to the same URL.
The form is handled by the form controller equip2.webapptutorial.publicweb.RegisterFormController,
and the form is backed by an instance of class equip2.webapptutorial.publicweb.RegisterFormBean.
This has properties name,
emailAddress, password and password2 (for password
confirmation). Form validation is currently performed in the
Controller's onSubmit
method rather than a separate validator and checks that:
If successful and new Player database ID is allocated using equip2.spring.db.IDAllocator (part of the equip2webapp equip2webdb.jar), a new Player object is created (instance of generated class equip2.webapptutorial.db.Player as defined in etc/equip2.webapptutorial.db.Player.xml), initialised, and added the dataspace (note that the controller is provided with reference to the dataspace via the Spring configuration of its dataspace property):
// begin dataspace session
ISession session = dataspace.getSession();
session.begin(ISession.READ_WRITE);
// check if email address is in use - query for Player with emailAddress = ...
QueryTemplate playerQuery = new QueryTemplate(Player.class);
playerQuery.addConstraintEq("emailAddress", registerBean.getEmailAddress());
// don't actually need the values (from match()), just if there are any
int count = session.count(playerQuery);
if (count>0)
errors.rejectValue("emailAddress", "in-use", "Registration emailAddress already in use (default message");
...
// create new Player
Player player = new Player();
// allocate ID of form 'P123', ensuring it is not already in use for a Player...
player.setID(IDAllocator.getNewID(session, Player.class, "P", null));
// other fields
player.setName(registerBean.getName());
// add to dataspace
session.add(player);
// dataspace stuff all done
session.end();
The registration controller also marks the new player as logged in
within the current session by placing an instance of equip2.webapptutorial.publicweb.LoginSessionBean
into the session as attribute LoginSessionBean.SESSION_ATTRIBUTE_NAME
('loginSessionBean').
The success view after registration is JSP register_ok.jsp.
Note the use of the JSP get_current_player.jsp,
which uses the Player ID in the LoginSessionBean
in the HTTP Session to fetch information about the current player.
Player log in/out is handled in the same way as documented in EQUIP2_WebApp_Login_and_Interceptors.html.
The log in form is login_form.jsp,
access via the URL http://.../publicweb/login.html.
This is modified compared to the login example to use the stylesheet
(site/publicweb.css) and register_form_input.jsp
for the individual inputs. It is backed by an instance of equip2.webapptutorial.publicweb.LoginFormBean
(with properties emailAddress
and password). The form
controller is equip2.webapptutorial.publicweb.LoginFormController.
This is based on the LoginFormController
from EQUIP2_WebApp_Login_and_Interceptors.html
but:
// open dataspace session - for read only (no changes here)
ISession session = dataspace.getSession();
session.begin(ISession.READ_ONLY);
// check if email address is in use - query for Player with emailAddress = ...
QueryTemplate playerQuery = new QueryTemplate(Player.class);
playerQuery.addConstraintEq("emailAddress", loginBean.getEmailAddress());
Object matches[] = session.match(playerQuery);
boolean authenticated = false;
Player player = null;
// there should only be zero or one!
if (matches.length>0) {
// coerce is safe from Query type
player = (Player)matches[0];
if (loginBean.getPassword().equals(player.getPassword()))
// matches!
authenticated = true;
}
// end of dataspace stuff
session.end();
The login interceptor, equip2.webapptutorial.publicweb.CheckLoginInterceptor,
is an unchanged copy of the one from EQUIP2_WebApp_Login_and_Interceptors.html,
configured to check for 'loginSessionBean'
in the session, or redirect on failure to the login page.
Log out is again directly based on the example, and uses the
controller equip2.webapptutorial.publicweb.LogoutController
and the configuration view logged_out.jsp
accessed via the URL http://.../publicweb/logout.html.
Player editing of their own information is handled via the request
URL http://.../publicweb/player_edit.html.
This has form view player_edit_form.jsp,
is backed by class equip2.webapptutorial.publicweb.RegisterFormBean
as 'player' (which
includes property 'oldPassword'
specifically for this purpose) and is handled by controller equip2.webapptutorial.publicweb.PlayerEditFormController.
Note that formBackingObject queries the dataspace while making the
initial form-backing object pulls information about the player from the
dataspace to populate it:
protected Object formBackingObject(HttpServletRequest request) throws Exception
{
RegisterFormBean formBean = new RegisterFormBean();
if (!this.isFormSubmission(request))
{
// on first access (not submission), copy information to form-backing bean
// get current player information from Http session
HttpSession httpSession = request.getSession();
LoginSessionBean lsb = (LoginSessionBean)httpSession.getAttribute(LoginSessionBean.SESSION_ATTRIBUTE_NAME);
// open dataspace session - for read
ISession session = dataspace.getSession();
session.begin(ISession.READ_WRITE);
// get current player details
Player player = (Player)session.get(Player.class, lsb.getUserId());
// done with dataspace
session.end();
formBean.setEmailAddress(player.getEmailAddress());
formBean.setName(player.getName());
}
return formBean;
}
On successful submission the form value(s) are pushed back to the
dataspace. In this situation be careful to consider possible concurrent
changes to these values (e.g. by other forms/user or threads within the
application).
A Topic is represented by an instance of class equip2.webapptutorial.db.Topic,
as generated from etc/equip2.webapptutorial.db.Topic.xml.
The generic DB forms can be used to create Topics, but typically only
by player with Tomcat operator access. In most applications a more
tailored form, integrated with the rest of the site will be required.
This is handled by the form with view add_topic_form.jsp,
backed by a equip2.webapptutorial.db.Topic
object directly, and with controller equip2.webapptutorial.publicweb.AddTopicFormController.
The controller:
Note that the success view, add_topic_ok.jsp,
simply returns a HTTP temporary redirect to the client, to cause the
browser to move on to (in this case) the index page for the newly added
topic:
<%-- redirect to topic_index.html?topic=ID (ID from request 'topic')
--%><% response.sendRedirect("topic_index.html?ID="+
((equip2.webapptutorial.db.Topic)(request.getAttribute("topic"))).getID()); %>
This is often a useful strategy to push from edit actions to
re-usable views, and gives the user immediate access to re-usable URLs
that can be copied or book-marked.
Topic views are provided by (both reasonable examples of EQUIP2 Taglib use) :
This is similar to editing a Player (above), but the topic to be
edited is identified by a request parameter (ID, the database ID), rather
than implicitly from the session, e.g. URL http://.../publicweb/topic_edit.html?ID=T502.
The topic editing form, topic_edit_form.jsp,
therefore also includes a (hidden) input to preserve this ID (called 'ID', of course).
The form backing object is a equip2.webapptutorial.db.Topic
object. In this case the controller, ,equip2.webapptutorial.publicweb.TopicEditFormController
gets it directly from the dataspace in formBackingObject:
...
if (!this.isFormSubmission(request)) {
String topicId = request.getParameter("ID");
// open dataspace session - for read
ISession session = dataspace.getSession();
session.begin(ISession.READ_WRITE);
// get current topic details
topic = (Topic)session.get(Topic.class, topicId);
// done with dataspace
session.end();
}
return topic;
[work in progress :-)]