net.jspcontrols.dialogs.actions
Class DialogAction

java.lang.Object
  extended byorg.apache.struts.action.Action
      extended byorg.apache.struts.actions.DispatchAction
          extended bynet.jspcontrols.dialogs.actions.SelectAction
              extended bynet.jspcontrols.dialogs.actions.DialogAction
All Implemented Interfaces:
IDialogAction, ISelectAction
Direct Known Subclasses:
CRUDAction, WizardAction

public class DialogAction
extends SelectAction
implements IDialogAction

An abstract Action that provides basic dialog functions, like accepting input data, dispatching submit event to a method, generating and storing error messages and rendering a view. DialogAction allows to create robust user inteface and provides simple event-based programming accounts.

DialogAction incorporates several innovative design decisions not previously used in Struts. Some of them are already implemented in other frameworks, like Ruby on Rails or JSF. Other features are unique to DialogAction.

Input/Output Separation

The cornerstone concept of DialogAction is separation of input and output processes. It solves several issues, related to HTML form input, like double submit problem, annoying POSTDATA messages, bad usability when Reload, Back and Forward buttons are used.

DialogAction defines three different modes of operation:

HTTP specification recommends to use POST request method for server state modification, and GET method for requests with no side effects. Therefore, input and output processes in DialogAction are cleanly separated by request method:

It must be understood, that redirection is an inherent part of this pattern. Redirection allows to split one solid "POST input data, respond with result page" process into two processes, which are completely independent from server standpoint.

Separation of input and output improves usability and user experience:

Event Handlers and View Renderer

Event handlers have the same signature, as execute method, and process POST events, usually from submit buttons of HTML form. An initialization event is one exception from this rule, and can be processed as either POST or GET request. Initialization event has a default key, DIALOG-EVENT.

After input event is processed, DialogAction redirects to itself and receives GET request from a browser. The same GET request is sent by the browser when a user reloads a page. In both cases, GET request is processed by getView method, which renders an output page.

"Rendering" is probably a too strong word to what getView method actually does. It simply chooses a mapping name of a JSP page corresponding to current dialog state, and returns this mapping to Struts in the same fashion as a regular action.

If a dialog action has only one page to render, then default getView implementation, which returns DIALOG-EVENT-VIEW key, is sufficient. The only thing you need to do is to define a forward element in the struts-config.xml file, which maps view key to a JSP page.

If a dialog action can render different pages depending on application state, it is called a web control. In this case getView method should be overriden, and a proper mapping should be returned.

Default keys and mappings

DialogAction uses several predefined keys and mappings, to correlate HTML buttons to handler methods, and to select result pages. These mappings are defined in DialogConstants class:

String DIALOG-VIEW-KEY = "DIALOG-VIEW";
This is a default view mapping, mandatory if a dialog action has only one page to render. If dialog can render different pages depending on application state, use action-specific mappings.

String DIALOG-RELOAD-KEY = "DIALOG-RELOAD";
This is a default reload mapping, optional. Can be omitted if a dialog action redirects to itself for view processing, which is a default behavior. It is possible to split input and output processing between two separate actions, in this case use this mapping to set the "view action" name.

String DIALOG-EVENT-KEY = "DIALOG-EVENT";
This is a default prefix for dialog events.

String DIALOG-EVENT = "DIALOG-EVENT";
This is a default name of initialization parameter.

Usage

DialogAction is supposed to be used for HTML forms, which are submitted using POST request method. When the form is submitted, DialogAction dispatches submit event to a handler method. For this to happed, automatic validation must be turned off. The hander should validate input data explicitly, and perform accounts update.

In case of error, the handler should save errors in the session and redirect to the same action, this is called action reloading. Would not this cause infinite loop? No, because request for data submission has POST type, while redirected request for action reloading has GET type. DialogAction processes requests differently, depending on their type. Action reloading can be performed automatically, see the example.

If no errors detected, control is usually handed over to another action. Redirection is a preferred way to hand over the control to prevent double submit issues.

When a user refreshes a page, action treats the request in the same way as for action reloading, and displays an appropriate view with current form bean values. This implies that application state must be stored on server with session or higher scope.

A special initializing request parameter must be used to initialize and reset DialogAction. This is necessary, because there is no other way to distinguish linking to DialogAction from other page, explicit refreshing of page corresponding to an action, or action reloading. Action data will not be cleared by simply navigating to DialogAction, instead current values will be shown.

Notes

Author:
Michael Jouravlev
See Also:
SelectAction, DialogConstants

Field Summary
 
Fields inherited from class net.jspcontrols.dialogs.actions.SelectAction
keyMethodMap
 
Fields inherited from class org.apache.struts.actions.DispatchAction
clazz, log, messages, methods, types
 
Fields inherited from class org.apache.struts.action.Action
defaultLocale, servlet
 
Constructor Summary
DialogAction()
           
 
Method Summary
 void clearMessages(javax.servlet.http.HttpServletRequest request)
          Cleans messages stored in the session.
 org.apache.struts.action.ActionForward execute(org.apache.struts.action.ActionMapping mapping, org.apache.struts.action.ActionForm form, javax.servlet.http.HttpServletRequest request, javax.servlet.http.HttpServletResponse response)
          Process the specified HTTP request, and create the corresponding HTTP response (or forward to another web component that will create it).
 org.apache.struts.action.ActionForward execute(IDialogAction action, org.apache.struts.action.ActionMapping mapping, org.apache.struts.action.ActionForm form, javax.servlet.http.HttpServletRequest request, javax.servlet.http.HttpServletResponse response)
          Process the specified HTTP request, and create the corresponding HTTP response (or forward to another web component that will create it).
protected  java.lang.String getActionSuffix()
          Returns suffix, used for action mapping.
 org.apache.struts.action.ActionForward getDialogView(org.apache.struts.action.ActionMapping mapping, org.apache.struts.action.ActionForm form, javax.servlet.http.HttpServletRequest request, javax.servlet.http.HttpServletResponse response)
          Returns an ActionForward instance describing the View for current dialog state, usually a forward to a JSP page.
protected  java.util.Map getKeyMethodMap()
          Provides mapping between event names (keys) and handler methods (values).
protected  java.lang.String getMethodName(org.apache.struts.action.ActionMapping mapping, org.apache.struts.action.ActionForm form, javax.servlet.http.HttpServletRequest request, javax.servlet.http.HttpServletResponse response, java.lang.String parameter)
          Returns the method name, given a prefix and a request object.
 boolean isBogusGET(javax.servlet.http.HttpServletRequest request)
          Returns true, if GET request contains session ID both in cookie and in the URL itself.
 boolean isInit(javax.servlet.http.HttpServletRequest request)
          Returns true if request is considered "init" request.
 boolean isInput(javax.servlet.http.HttpServletRequest request)
          Returns true if request is considered "input" request.
 void saveDialogErrors(javax.servlet.http.HttpSession session, org.apache.struts.action.ActionMessages errors)
          Saves dialog errors in the session under Globals.ERROR_KEY key.
 void setNoCache(javax.servlet.http.HttpServletResponse response)
          Marks response as non-cachable.
 
Methods inherited from class net.jspcontrols.dialogs.actions.SelectAction
buildLookupMap, cancelled, execute, getCancelKey, getDefaultKey, getInitKey, getMethod, resolveEvents, unspecified
 
Methods inherited from class org.apache.struts.actions.DispatchAction
dispatchMethod, getMethod
 
Methods inherited from class org.apache.struts.action.Action
addErrors, addMessages, execute, generateToken, getDataSource, getDataSource, getErrors, getLocale, getMessages, getResources, getResources, getServlet, isCancelled, isTokenValid, isTokenValid, resetToken, saveErrors, saveErrors, saveErrors, saveMessages, saveMessages, saveToken, setLocale, setServlet
 
Methods inherited from class java.lang.Object
clone, equals, finalize, getClass, hashCode, notify, notifyAll, toString, wait, wait, wait
 
Methods inherited from interface net.jspcontrols.dialogs.actions.ISelectAction
cancelled, unspecified
 

Constructor Detail

DialogAction

public DialogAction()
Method Detail

clearMessages

public void clearMessages(javax.servlet.http.HttpServletRequest request)
Cleans messages stored in the session. Subclasses can override this method if error messages are stored differently, or under different key.

Parameters:
request - the HTTP request we are processing

saveDialogErrors

public void saveDialogErrors(javax.servlet.http.HttpSession session,
                             org.apache.struts.action.ActionMessages errors)
Saves dialog errors in the session under Globals.ERROR_KEY key.

Parameters:
session - HttpSession object
errors - error messages, accumulated while processing input
Since:
1.2

setNoCache

public void setNoCache(javax.servlet.http.HttpServletResponse response)
Marks response as non-cachable. Should be called before page content is written to response.

Parameters:
response - The HTTP response we are creating
Since:
1.2

getActionSuffix

protected java.lang.String getActionSuffix()
Returns suffix, used for action mapping. Default suffix is ".do" Needed to properly setup location for dialog reloading.


isInput

public boolean isInput(javax.servlet.http.HttpServletRequest request)
Returns true if request is considered "input" request. By convention dialog input is sent via POST, result page is loaded via GET.

Parameters:
request - The HTTP request we are processing

isInit

public boolean isInit(javax.servlet.http.HttpServletRequest request)
Returns true if request is considered "init" request. DialogAction uses a special request parameter to initialize action, because it is impossible to distinguish a page refresh from navigating to an action via a link, both use GET request method.

Initialization parameter must be defined in a concrete subclass.

Parameters:
request - The HTTP request we are processing

isBogusGET

public boolean isBogusGET(javax.servlet.http.HttpServletRequest request)
Returns true, if GET request contains session ID both in cookie and in the URL itself. This combination identifies the first request after session has been established, with browser which supports cookies.

DialogAction tries to keep GET requests clean to encourage browser to keep its page history from growing. When DialogAction detects bogus request, it redirects to itself to ensure clean URL. This time it will be clean, because session ID will be contained in cookie only.

Parameters:
request - The HTTP request we are processing

getMethodName

protected java.lang.String getMethodName(org.apache.struts.action.ActionMapping mapping,
                                         org.apache.struts.action.ActionForm form,
                                         javax.servlet.http.HttpServletRequest request,
                                         javax.servlet.http.HttpServletResponse response,
                                         java.lang.String parameter)
                                  throws java.lang.Exception
Returns the method name, given a prefix and a request object. This is a helper method, which should not normally be redefined by a subclass.

Overrides:
getMethodName in class SelectAction
Parameters:
mapping - The ActionMapping used to select this instance
form - The optional ActionForm bean for this request (if any)
request - The HTTP request we are processing
response - The HTTP response we are creating
parameter - The ActionMapping parameter's name Contains prefix of submit button names, or several prefixes separated by comma or semicolon.
Returns:
The handler method name.
Throws:
java.lang.Exception

getKeyMethodMap

protected java.util.Map getKeyMethodMap()
Provides mapping between event names (keys) and handler methods (values). This method may be overriden by a subclass. Important: if you define action mappings using new syntax (with "component" element), then if "event" subelements are defined for a component, getKeyMethodMap will not be called.

In other words, define the event-to-method mapping either in struts-config.xml file, or in the code using getKeyMethodMap method.

Specified by:
getKeyMethodMap in class SelectAction
Returns:
Map, containing association between event names (keys) and handler methods (values).

execute

public org.apache.struts.action.ActionForward execute(org.apache.struts.action.ActionMapping mapping,
                                                      org.apache.struts.action.ActionForm form,
                                                      javax.servlet.http.HttpServletRequest request,
                                                      javax.servlet.http.HttpServletResponse response)
                                               throws java.lang.Exception
Process the specified HTTP request, and create the corresponding HTTP response (or forward to another web component that will create it). Return an ActionForward instance describing where and how control should be forwarded, or null if the response has already been completed.

Overrides:
execute in class SelectAction
Parameters:
mapping - The ActionMapping used to select this instance
form - The optional ActionForm bean for this request (if any)
request - The HTTP request we are processing
response - The HTTP response we are creating
Throws:
java.lang.Exception - if an exception occurs

execute

public org.apache.struts.action.ActionForward execute(IDialogAction action,
                                                      org.apache.struts.action.ActionMapping mapping,
                                                      org.apache.struts.action.ActionForm form,
                                                      javax.servlet.http.HttpServletRequest request,
                                                      javax.servlet.http.HttpServletResponse response)
                                               throws java.lang.Exception
Process the specified HTTP request, and create the corresponding HTTP response (or forward to another web component that will create it). Return an ActionForward instance describing where and how control should be forwarded, or null if the response has already been completed.

Parameters:
mapping - The ActionMapping used to select this instance
form - The optional ActionForm bean for this request (if any)
request - The HTTP request we are processing
response - The HTTP response we are creating
Throws:
java.lang.Exception - if an exception occurs
Since:
1.24

getDialogView

public org.apache.struts.action.ActionForward getDialogView(org.apache.struts.action.ActionMapping mapping,
                                                            org.apache.struts.action.ActionForm form,
                                                            javax.servlet.http.HttpServletRequest request,
                                                            javax.servlet.http.HttpServletResponse response)
                                                     throws java.lang.Exception
Returns an ActionForward instance describing the View for current dialog state, usually a forward to a JSP page.

If you want to use the default implementation, define the View under "DIALOG-VIEW" name in <forward> element of your action mapping.

To use different mapping name, define the view in <forward> element of your action mapping, and override this method to return ActionForward object for your mapping name.

Specified by:
getDialogView in interface IDialogAction
Parameters:
mapping - The ActionMapping used to select this instance
form - The optional ActionForm bean for this request (if any)
request - The HTTP request we are processing
response - The HTTP response we are creating
Returns:
ActionForward instance describing the View for dialog state
Throws:
java.lang.Exception - if an exception occurs