[[ Old comment, sent by email on Thu, 31 Aug 2006 14:00:53 -0700 ]]
Ok, I have implemented a first draft.
First, the name. I chose the one that I think is a pretty good one:
Rollover Scope. Meaning that request-scoped data rolls over to a next
request. The name is final, no alternative names please The name
describes the functionality and at the same time does not give a wrong
impression that it somehow related to wizards, dialogs, flow, etc. On
the other hand, a wizard that uses rollover scope for its ActionForm
works pretty well
Now the functionality. The rollover scope can be accessed from Action
with a member method, it can also be accessed by reading an object
from HttpServletRequest keyed as ROLLOVER_KEY.
Everything written to rollover scope is written to the request object
too, everything read from rollover scope is looked up in request
object first, then if not found, it is looked up in rollover object
itself. This way rollover data is presented to other parts of
application including JSP tags as regular request-scoped data.
Rollover scope is implemented in the new composable request processor
both for commands and actions. Rollover scope is supported for action
mappings as well, so an action mapping can use scope="rollover". Here
is an example of a login component implemented with two action
mappings and two corresponding actions.
<action path = "/logininputaction"
type = "com.acme.LoginInputAction"
name = "loginform"
scope = "rollover"
validate = "false"
parameter = "initEvent=init,loginEvent=login,logoutEvent=logout">
<forward name = "render" path = "/loginrenderaction.do" redirect = "true"/>
<action path = "/loginrenderaction"
type = "com.acme.LoginRenderAction"
name = "loginform"
scope = "request"
validate = "false">
<forward name = "notloggedin" path = "/pages/login.jsp"/>
<forward name = "loggedin" path = "/pages/logout.jsp"/>
Login component is normally accessed with "loginrenderaction" URL.
When a user navigates to this location, LoginRenderAction checks
current user stored in the session, and displays either login.jsp page
if no one is logged in, or logout.jsp if there is a logged in user.
login.jsp contains a login form that submits to "logininputaction",
LoginInputAction uses loginform to store username (password is not
stored) in case it has to be redisplayed when credentials are not
correct. When a user submits a form for the first time, Struts checks
whether the loginform exists, it does not, so it creates a form in
rollover scope. After username/password are checked, a user is either
logged in or not, but in both cases he is redirected to
loginrenderaction that either redisplays a login page or shows current
login status. Before the redirection, the loginform is pushed from
request to session because it is defined in rollover scope for
On the next request the form is pulled from the session into the
request, but not into the rollover scope. "loginrenderaction"
redisplays the login page along with error message and shows the login
name entered on previous attempt. Because loginrenderaction defines
the form as request-scoped (see mapping above), the loginform is not
stored in rollover scope, now it is a regular request-scoped form. So
when a user hits "refresh", the form is automatically recreated by
Struts, so the entered username is gone. To prevent this, the form
should be defined with scope="rollover" in both input and render
mappings, this way it will always be saved in the session when request
comes. This allows to refresh the page without losing data.
At the same time, if a user navigates to another page and then comes
back to login page, the entered username will be lost because the
loginform will be recreated. I think this is acceptable for cases like
Now I am going to add temporary cookies that will identify a rollover
scope, this way one will be able to have as many rollover scopes as
many browser windows are open. The cookie is chosen instead of a
request parameter (like in Stripes) because I want to preserve the URL
intact, it may matter if a developer cares about browser page history.
Thanks Antonio for the tips on storing rollover scope in the request
and on using cookies.