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/StrutsManualActionClasses

------------------------------------------------------------------------------
  The goal of an Action class is to process a request and return an 
ActionForward object that identifies where control should be transferred (e.g. 
a JSP page, Tile definition, Velocity template, or another Action) to provide 
the appropriate response.
  
  == Action As Simple Service ==
+ In its simplest form Action class handles all incoming requests with one 
callback method, {{{execute()}}}. Two overloaded versions of this method are 
available. Choosing one or another depends on your servlet environment. A 
non-HTTP execute() method has been provided for applications that are not 
specifically geared towards the HTTP protocol, but most projects will only use 
the HTTP version since the majority of teams using the framework are focused on 
building web applications:
- When used in "servlet mode", an Action class handles all incoming requests in 
one callback method, execute(). Two versions of this method are available. 
Choosing one or another depends on your servlet environment.
- 
- A non-HTTP execute() method has been provided for applications that are not 
specifically geared towards the HTTP protocol, but most projects will only use 
the HTTP version since the majority of teams using the framework are focused on 
building web applications:
  
  {{{public ActionForward execute(ActionMapping mapping,
                               ActionForm form,
@@ -17, +15 @@

                               HttpServletResponse response)
                      throws Exception;}}}
                  
- Action class is stateless, it looks very much like a a fancy servlet or a web 
service. But in some ways Action class is more limited than a regular servlet. 
+ HTTP specification recommends to use POST for non-idempotent requests, and to 
use GET for requests that can be repeated several times with the same outcome. 
In simpler terms, POST requests should be generally used to modify application 
state, while GET requests should be used to render a view.
  
- A servlet can handle GET and POST requests in different manner by providing 
two separate methods, doGet() and doPost(). HTTP specification recommends to 
use POST request for non-idempotent requests, namely to modify application 
state. GET reqeust should not affect model state and should be used for 
requests that can be safely repeated more than one time.
+ An interactive web application implements the above HTTP requirements using a 
two-phase input/output protocol. On ''render phase'' (or output phase) the 
browser requests a view from the server. On ''input phase'' (or submit phase) 
the browser sends input data to an application, usually by submitting an HTML 
form.
  
- Action class provides only one method to deal with all incoming requests, 
therefore actions rarely distinguish a ''render request'' from a ''submit 
request''. This often leads to convoluted and unmaintable code that can break 
from an occasional page refresh or from clicking on a Back button.
+ In Struts the two-phase request/response approach is traditionally 
implemented with setup/submit pattern and two kinds of actions:
+  * setup action (pre-action, output action, render action) prepares output 
data before displaying a JSP page;
+  * submit action (post-action, input action, accept action) accepts user 
input.
+ 
+ This pattern is a de-facto standard, because unlike servlet, that processes 
GET and POST requests with {{{doGet()}}} and {{{doPost()}}} methods 
respectively, Action class handles all incoming requests with only one 
{{{execute()}}} method.
  
  inline:setup_submit.gif
  
- Despite its shortcomins, the "servlet mode" is one of more popular uses of 
Action class.A typical Action class will often implement logic like the 
following in its execute method:
+ A typical Setup Action will often implement logic like the following in its 
{{{execute}}} method:
  
-     * Validate the current state of the user's session (for example, checking 
that the user has successfully logged on). If the Action class finds that no 
logon exists, the request can be forwarded to the presentation page that 
displays the username and password prompts for logging on. This could occur 
because a user tried to enter an application "in the middle" (say, from a 
bookmark), or because the session has timed out, and the servlet container 
created a new one.
-     * If validation is not complete, validate the form bean properties as 
needed. If a problem is found, store the appropriate error message keys as a 
request attribute, and forward control back to the input form so that the 
errors can be corrected.
+  * Make sure that a user is allowed to see the content of a web page that 
corresponds to the action.
+  * Load needed data from database, set up an form bean or arbitrary request- 
or session-scoped objects.
+  * Return an appropriate ActionForward object that identifies the 
presentation page to be used to generate the response.
+ 
+ A typical Submit Action will often implement logic like the following in its 
{{{execute}}} method:
+ 
+  * Validate the form bean properties as needed. If a problem is found, store 
the appropriate error message keys as a request attribute, and forward control 
to the input form so that the errors can be corrected.
-     * Perform the processing required to deal with this request (such as 
saving a row into a database). This can be done by logic code embedded within 
the Action class itself, but should generally be performed by calling an 
appropriate method of a business logic bean.
+  * Perform the processing required to deal with this request (such as saving 
a row into a database). This can be done by logic code embedded within the 
Action class itself, but should generally be performed by calling an 
appropriate method of a business logic bean.
-     * Update the server-side objects that will be used to create the next 
page of the user interface (typically request scope or session scope beans, 
depending on how long you need to keep these items available).
+  * Update the server-side objects that will be used to create the next page 
of the user interface (typically request scope or session scope beans, 
depending on how long you need to keep these items 
-     * Return an appropriate ActionForward object that identifies the 
presentation page to be used to generate this response, based on the newly 
updated beans. Typically, you will acquire a reference to such an object by 
calling findForward on either the ActionMapping object you received (if you are 
using a logical name local to this mapping), or on the controller servlet 
itself (if you are using a logical name global to the application).
+  * Return an appropriate ActionForward object that identifies the 
presentation page to be used to generate this response, based on the newly 
updated beans. Typically, you will acquire a reference to such an object by 
calling findForward on either the ActionMapping object you received (if you are 
using a logical name local to this mapping), or on the controller servlet 
itself (if you are using a logical name global to the application).
+ 
+ It is common to have several actions of either kind for one logical business 
object. For example, if you deal with {{{Customer}}} object, you are likely to 
define two setup actions: {{{viewCustomer.do}}} and {{{editCustomer.do}}} and 
three submit actions: {{{addCustomer.do}}}, {{{updateCustomer.do}}} and 
{{{deleteCustomer.do}}}. 
+ 
+ Setup action loads data from database and queues it into one or more 
arbitrary objects located in the request or session scope. Submit action 
processes input data and redisplays the same data entry form if errors has been 
found in the input. If input does not contain errors, submit action forwards to 
a success page. 
+ 
+ This standard setup/submit pattern is not perfect:
+  * The focus is a page, not a web resource in general. 
+  * One Action deals with only one message, like {{{updateCustomer.do}}} deals 
with "Update Customer" event, {{{deleteCustomer.do}}} deals with "Delete 
Customer" event.
+  * One logical web resource is defined with several action mappings in the 
{{{struts-config.xml}}} file as well as with several Java classes.
+  * Output data is often scattered in an uncontrolled manner throughout 
request and session scope.
+  * In case of error the data entry form is redisplayed by a submit action; 
that opens a whole can of worms:
+   * If input data is invalid and autovalidation is turned on, a submit action 
class is never get called and cannot affect the workflow.
+   * One page is represented with two different URLs in the browser.
+   * An attempt to refresh a page after it has been redisplayed causes double 
submit.
+  * Success page often corresponds to a logically different resource, this 
leads to a spaghetti code both in Java code as well as in 
{{{struts-config.xml}}} file.
+ 
  
  == Action As Event Dispatcher ==
  
- Behavior object handles a group of related messages (events, commands). These 
messages often correspond to one business object, like classic Create, 
Retrieve, Update and Delete messages that identify basic operations on 
persistent objects in a database-driven application. Behavior object usually 
changes application state based on incoming message. Application state can be 
stored in database, flat file or in a scoped object like !HttpSession or 
!HttpServletRequest.
+ Event Dispatcher handles a group of related messages (events, commands). 
These messages often correspond to one business object, like classic Create, 
Retrieve, Update and Delete messages that identify basic operations on 
persistent objects in a database-driven application. Event Dispatcher usually 
changes application state based on incoming message. Application state can be 
stored in a database, a flat file or in a scoped object like !HttpSession or 
!HttpServletRequest.
  
- A behavior object has methods that correspond to incoming messages. Therefore 
an Action that manages a persistent object will likely have create(), 
retrieve(), update() and delete() methods. Each method is triggered with a 
specific parameter sent in a request.
+ An event dispatcher has methods that correspond to incoming messages. 
Therefore an Action that manages a persistent object will likely have 
{{{create}}}, {{{retrieve}}}, {{{update}}} and {{{delete}}} methods. Each 
method is triggered with a specific parameter sent in a request.
  
  inline:event_dispatcher.gif
  
- Struts Extras package allows to define behavior objects with one of 
subclasses of Action class: DispatchAction, LookupDispatchAction, 
MappingDispatchAction, EventDispatchAction. These subclasses decode an event 
from incoming request and dispatch it to a corresponding event handler. The 
exact way of defining events depends on specific Action subclass. 
+ Struts defines several dispatch classes like !DispatchAction, 
!LookupDispatchAction, !MappingDispatchAction, !EventDispatchAction. These 
subclasses decode an event from incoming request and dispatch it to a 
corresponding event handler. The exact way of defining events depends on 
specific Action subclass. 
  
- Starting from Struts 1.4 dispatching functionality is implemented into base 
Action class. Now there is a standard way of defining events for a behavioral 
Action by using <event> elements in an action mapping:
+ In an interactive application dispatch actions usually handle one I/O phase, 
either input events or render requests. Thus the task of handling input and 
output is conveniently split into separate Actions.
  
+ Automatic validation should be turned off in {{{struts-config.xml}}} file to 
ensure that a handler is always called for an incoming event.
- {{{<action path = "/loginSubmit"
-         type = "samples.login.LoginAction"
-         name = "loginform"
-         scope = "session"
-         validate  = "false">
-    <event name="loginEvent" handler="login"/>
-    <event name="logoutEvent" handler="logout"/>
-    <forward name = "render" path = "/loginRender.do" />
- </action>}}}
- 
- Behavior Actions usually handle submit requests only. To display a view they 
transfer control to a rendering Action. Thus the task of handling input and 
output is split into separate Actions.
  
  == Action As Web Resource Manager ==
+ 
+ Many Struts users think in terms of simple actions and pages. It may be 
beneficial to think it terms of more generic web resources. A ''web resource'' 
is a representation of a business object that an interactive application works 
with. For example, a Customer resource can be displayed in "View" and "Edit" 
modes, and can accept "New", "Edit", "Delete" and "Save" messages. Would not it 
be simpler to represent this entity with only one Action?
+ 
+ This is possible with a dispatching Action. You can differentiate input and 
render phases either by request type (GET vs. POST) or by presence of an event 
parameter in the request.
+ 
+ A Web Resource Manager does the following:
+  * handles different commands and events corresponding to a web resource 
(submit phase), and
+  * selects an appropriate view based on current state of web resource (render 
phase).
  
  inline:web_resource.gif
  
  
  == Action As Stateful Web Resource Manager ==
  
- In Microsoft parlance, a code-behind class implements the logic of one web 
resource. Since ASP.Net uses Page Controller paradigm, a web resource is 
usually a page. Struts web resources are not constrained by one page, one 
resource can have several corresponding views defined in one or in several JSP 
files.
+ A stateful web resource stores its data in a session scope, usually in a 
session-scoped form bean associated with Action. This allows to use redirection 
without losing the data. Redirection can be used to render a view: submit 
action redirects to setup action instead of forwarding to it.
  
- A code-behind Struts Action:
-  * handles different commands and events corresponding to a web resource 
(submit phase), and
-  * selects an appropriate view based on current state of web resource (render 
phase).
+ If you can live with session-scoped data, your web application will sport 
much cleaner and user-friendly interface:
+ 
+ * A web resource will have only one URL, the setup URL. Submit URL will be 
cleared by browser right after redirection.
+ * Navigating back and forward, as well as reloading a view is safe and does 
not cause resubmit.
+ * Several unsuccessful submit attempts to not accumulate in browser page 
history.
  
  inline:stateful_web_resource.gif
- 
- {{{<action path = "/login"
-         type = "samples.login.LoginAction"
-         name = "loginform"
-         scope = "session"
-         validate  = "false">
-    <event name="loginEvent" handler="login"/>
-    <event name="logoutEvent" handler="logout"/>
-    <forward name = "notloggedin" path = "/logint.jsp" />
-    <forward name = "loggedin" path = "/logout.jsp" />
- </action>}}}
  
  == Action As Web Component Manager ==
  

Reply via email to