Dear Wiki user,

You have subscribed to a wiki page or wiki category on "Struts Wiki" for change 
notification.

The following page has been changed by MichaelJouravlev:
http://wiki.apache.org/struts/RolloverScope

The comment on the change is:
Rewrote the page.

------------------------------------------------------------------------------
  Attention! This page describes a feature that has not been implemented yet!
  
- = Rollover Scope for Struts 1.3.x =
+ = Rollover Scope for Struts 1.x =
  
- In addition to standard J2EE scope objects (request, session, applicaiton) 
Struts will support the ''rollover scope''. Ideally, for most uses and purposes 
this scope should be identical to request scope, but its content should be 
stored on the server until the next request comes in. Hence the name, the 
content of the scope rolls over to a next request.
+ Traditionally web applications have stored state information either in in the 
HTTP request or in the HTTP session. If request object is used, a common 
practice to preserve state between request is to save it into HTML FORM; in 
this case moving back and forward along page history changes the state. If 
session object is used, it may open a potential source of memory leak, because 
application has to explicitly remove user objects from session.
  
- One of the reasons for implementing rollover scope is automatic retaining of 
an !ActionForm, so its content to be displayed on a consecutive request 
(redirect-after-post pattern). Using session-scoped forms requires manual 
memory cleanup, which is tedious.
+ Caught between limitations of request object from the one hand and the 
necessity of laborious manual housekeeping of session object on another hand, 
developers rarely use redirection to split input and render tasks. This is 
unfortunate because Redirect-After-Post pattern is a simple and proven solution 
for creating user-friendly and error-resistant interfaces.
  
- == A high-level outline of a rollover scope ==
+ Starting from Struts 1.4 it will be possible to store data related to a 
multi-request conversation in the Rollover Scope.
  
- When an object is stored in rollover scope, the object is actually stored in 
the request scope. An additional reference to the object is stored in rollover 
scope container. If container does not exist, it is created and is stored 
itself in the request scope.
+ == Rollover scope in a nutshell ==
  
- When an object is accessed from rollover scope, the data is actually read 
from the request scope.
+ Physically, a rollover scope is a map stored within session scope. One 
session can have one or more associated rollover scopes. 
  
- Before returning the response to a client Struts verifies whether a rollover 
container exists in request scope. If yes, the container is saved into the 
session scope. On a next request, Struts checks whether the session contains a 
rollover container. If yes, its content is moved to the request scope and 
rollover container is disposed of.
+ Rollover scope can be used in the following ways:
+  * Directly from use code through methods of RolloverScope class. [not tested]
+  * Indirectly through saveXXX() and loadXXX() methods of Action class. [not 
implemented yet]
+  * By specifying action form scope in an action mapping of struts-config.xml 
file. [implemented]
  
- This approach allows to present rollover-scoped objects as request-scoped 
objects to an application in most cases. When an application accesses rollover 
scope, it actually accesses the request scope. Struts tags or JSTL tags 
automatically pick up data saved in rollover scope because this data has been 
copied back to request scope. Thus, no additional support is nesessary for tag 
libraries.
+ A rollover scope can be configured for automatic garbage collection. Two 
techniques are possible:
+  * Setting scope lifetime when the scope is created.
+  * Specifying a scope as a storage for an action form that corresponds to a 
multi-request conversation like a wizard.
  
- Without additional handling, the rollover-scoped object can be instantiated 
only once for a given session, because the rollover scope is stored in the 
session between requests. This is a limitation of the current implementation. 
The ways to overcome it are outlined further.
+ == Using rollover scope explicitly from application code ==
  
- == ActionForm and rollover scope ==
+ To obtain an instance of a rollover scope use {{{RolloverScope.getInstance}}} 
static method. If the scope you are accessing does not exist and "create" flag 
is true, new scope will be created.
  
- An !ActionForm can be configured to be stored in the rollover scope using 
{{{scope="rollover"}}} in an action mapping configuration, for example:
+ To store data in a scope or to read data from a scope use appropriate methods 
of Map interface. Rollover scope is just an enhanced Map.
+ 
+ To remove rollover scope from the session object use 
{{{RolloverScope.remove}}} method.
+ 
+ == Using rollover scope to store an action form ==
+ 
+ In a Struts application a rollover scope can be used just as any other J2EE 
scope, including action mappings. To declare a rollover scope for an action 
form use scope="rollover" in action mapping definition. Below is an example of 
a standard redirect-after-post pattern: one mapping for submitting user data 
from browser, another mapping for rendering a web page. An implicit rollover 
scope is used to store form bean in between requests.
+ 
+ The sample config below employs dual-action approach: one action for input, 
another for rendering. The input action inherits from !EventDispatchAction and 
is used as event processor. Render action uses login/logout state to render an 
appropriate view.
+ 
+ Events are defined in 'parameter' attribute. Notice that 'scope' has 
'rollover' value. The rollover scope has request-based removal strategy with 
lifetime of one request - perfect for redirect-after-post pattern. Besides 
automatic removal based on removal strategy, a rollover scope can be removed 
based on action outcome. In the sample below, if an input action chooses 
'cancel' or 'userhome' outcomes, then rollover scope is removed before request 
is redirected to render action.
  
  {{{<action path = "/logininputaction"
-        type = "com.acme.LoginInputAction"
+         type = "org.apache.struts.samples.login.LoginInputAction"
-        name = "loginform"
+         name = "loginform"
-        scope = "rollover"
+         scope = "rollover"
-        validate = "false"
+         validate = "false"
-        parameter = "initEvent=init,loginEvent=login,logoutEvent=logout">
+         parameter = 
"initEvent=init,loginEvent=login,cancelEvent=cancel,logoutEvent=logout">
+ 
+         <set-property key="rolloverStrategy" value="rcount" />
+         <set-property key="rolloverLimit" value="1" />
+         <set-property key="rolloverRelease" value="cancel,userhome" />
+ 
-  <forward name = "render" path = "/loginrenderaction.do" redirect = "true"/>
+         <forward name = "render" path = "/loginrenderaction.do" redirect = 
"true"/>
+         <forward name = "userhome" path = "/userhome.do" redirect = "true"/>
+         <forward name = "cancel" path = "/main.do" redirect = "true"/>
  </action>
  
  <action path = "/loginrenderaction"
-        type = "com.acme.LoginRenderAction"
+         type = "org.apache.struts.samples.login.LoginRenderAction"
-        name = "loginform"
+         name = "loginform"
-        scope = "rollover"
+         scope = "rollover"
-        validate = "false">
+         validate  = "false">
+ 
+         <set-property key="rolloverStrategy" value="rcount" />
+         <set-property key="rolloverLimit" value="1" />
+         <set-property key="rolloverRelease" value="loggedin" />
+ 
-  <forward name = "notloggedin" path = "/pages/login.jsp"/>
+         <forward name = "notloggedin" path = 
"/logindialog/logincomponent-login.jsp"/>
-  <forward name = "loggedin" path = "/pages/logout.jsp"/>
+         <forward name = "loggedin" path = 
"/logindialog/logincomponent-logout.jsp"/>
  </action>}}}
  
- == 1.2 and 1.3 compatibility ==
+ == Changes to Struts core classes ==
+ Several core classes have been updated to accommodate usage of rollover 
scope. Two new commands have been added to default chain.
  
- Currently the rollover scope is implemented for 1.3-style Command chain only. 
The DTD is updated.
+ === New: org.apache.struts.scope.RolloverScope ===
+ Instances of this class store rollover-scoped data; the class implements Map. 
Static methods of this class obtain/create /remove a rollover scope instance. 
  
- == Implementation details ==
+ === New: org.apache.struts.chain.commands.LoadRolloverData ===
+ This command must be specified in chain config file before !CreateActionForm 
command; it matures all rollover scopes corresponding to current session, 
removes aged scopes, looks up for a rollover scope corresponding to an action 
mapping and loads rollover data into request scope to ensure that JSP tags 
perform properly.
  
- === Core files ===
+ === New: org.apache.struts.chain.commands.ReleaseRolloverData ===
+ This command must be specified in chain config after !ExecuteCommand and 
!ExecuteAction commands; it immediately releases current rollover scope if 
current action is configured so with "rolloverRelease" property.
  
+ === Updated: org.apache.struts.chain.contexts.ActionContext ===
+ Added {{{getRolloverScope}}} method along with "rollover" literal to be used 
in action mapping definition.
- org.apache.struts.chain.context.!ActionContextBase is enhanced so 
getScope(String scopeName) accepts rollover context name.
- org.apache.struts.chain.context.!ActionContext interface is enhanced with 
getRolloverScope() method.
- org.apache.struts.chain.context.!WebActionContext class is enhanced with 
getRolloverScope() method.
- org.apache.struts.chain.commands.servlet.!ExecuteAction class is enhanced to 
store rollover scope in the session after an action class is executed.
- org.apache.struts.chain.commands.!ExecuteCommand class is enhanced to store 
rollover scope in the session after an command is executed.
  
- === Reading rollover data from the session ===
- The base request chain is augmented with {{{ObtainRolloverData}}} class 
placed before actions, commands or actionforms are looked up and instantiated:
+ === Updated: org.apache.struts.chain.contexts.ActionContextBase ===
+ Method {{{getScope}}} now looks up for rollover scope along with standard 
J2EE scopes. 
  
+ === Updated: org.apache.struts.chain.contexts.WebActionContext ===
+ Defines getRolloverScope method, which obtains/creates rollover scope based 
on current webcontext and request scope. This method is used by 
{{{ActionContextBase.getScope}}} method.
- {{{<command 
className="org.apache.struts.chain.commands.servlet.SetContentType"/>
- <command className="org.apache.struts.chain.commands.ObtainRolloverData"/>
- <command 
className="org.apache.struts.chain.commands.RemoveCachedMessages"/>}}}
  
- When a request is received, Struts checks whether the session contains a 
rollover container. If yes, its content is moved to the request scope and 
rollover container is disposed of.
+ === Updated: struts-config_1_3.dtd ===
+ !RequestScope enity now allows "rollover" value along with "request" and 
"session".
  
- === Executing a command or an action ===
+ == Source code and samples ==
+ The changes related to rollover scope have not been committed to main Struts 
1.x codebase yet. You can try a simple example of rollover scope usage by 
downloading this sample application. Source code is included.
  
- After either an action or a command has executed by !ExecuteAction or 
!ExecuteCommand respectively, but before the response is sent to a browser, a 
new rollover container is created if needed and is stored in the session. This 
container will be checked on a next request.
- 
- == Limitations and other approaches ==
- 
- Current implementation allows to store only one session-wide instance of an 
object, so in a way rollover scope works like a session scope with automatic 
cleanup when next request comes. Obviously this is not how actual 
request-scoped objects behave. Below are the knows options for improvement.
- 
- === Use a URL parameter ===
- 
- Stripes generates a URL parameter that allows to locate a proper rollover 
container object, called a !FlashScope in Stripes. The drawbacks:
-    * URL is mangled, which may not be desirable for some (like me).
-    * Must redirect to stick the parameter into URL. Redirection is needed for 
render requests too, like: render(URL)->redirect->render(URL+param).
- 
- === Use a hidden form field ===
- It is possible to generate a hidden form field with rollover container ID, 
the drawbacks:
-    * all pages must contain forms
-    * what if a page contains several forms?
- 
- === Use a temporary cookie ===
-    The drawbacks:
-    * If cookies are turned off on a browser, would have to use URL parameters
-    * It is not possible (as far as I know) to send one cookie from one 
browser window and another from another window; all cookies are shared by all 
windows in a browser session.
- 
- == Conclusion ==
- 
- Currently rollover scope is implemented in its simplest and allows only one 
session-scoped instance of an object to be rolled over.
- 

Reply via email to