struts-commits mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From Apache Wiki <wikidi...@apache.org>
Subject [Struts Wiki] Update of "StrutsManualActionClasses" by MichaelJouravlev
Date Sun, 25 Jun 2006 22:53:48 GMT
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 ==
  

Mime
View raw message