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

New page:
== Handling events with action dispatcher ==

Struts is considered to be a simple request/response framework with no notion 
of events. This is not exactly true. It is possible to assign events to input 
elements of an HTML form or evnt to regular links, and to process these events 
in a uniform fashion by a single action class.

== Dispatch actions ==

Struts distribution includes several action classes that can accept several 
events and dispatch them to corresponding method handler. These actions are: 
!DispatchAction, !LookupDispatchAction and !MappingDispatchAction. These 
classes are not perfect though.

   * An action class must extend one of these classes to use dispatch features.
   * !DispatchAction requires submit button caption to be the same as handler 
method name.
   * !LookupDispatchAction uses reverse lookup to property file and requires 
button-to-method map; button caption cannot be changed without application 
restart.
   * !MappingDispatchAction can process only one event per action mapping 
definition, so you have one class but several action mappings and several URLs.

Thankfully, there is a better solution.

== Action Dispatcher ==
Struts 1.2.7+ distribution includes !ActionDispatcher class that combines 
features of all dispatch actions. It allows to select a particular behavior or 
flavor and, what is the most appealing, it allows to dispatch events to any 
action class.

!ActionDispatcher does not improve event-handling features of the three 
aforementioned dispatch classes, so it has been extended. The extended version 
is called [http://issues.apache.org/bugzilla/attachment.cgi?id=17724 
ParameterListActionDispatcher] and solves all known dispatch issues:

   * Any arbitrary action class can handle several events.
   * One action mapping can contain several event definitions.
   * Submit buttons can have any caption; caption can be changed in runtime.
   * No event-to-method map is needed.
   * Action method name can be either used directly on a web page, or can be 
aliased with an event name.
   * It is possible to define a default method if event is not recognized.
   * If event is not recognized and default method is not defined, the 
dispatcher invokes {{{unspecified}}} method.
   * Standard Cancel buttons is hooked up to {{{cancelled}}} method and does 
not have to be defined explicitly.

== Dispatching events using ParameterListActionDispatcher ==

Dispatching events is now easy. Usually, you will define two action classes: 
''submit action'' will handle all input events , while ''setup/render action'' 
will choose an appropriate page and display it. In some cases you can get by 
with only one action that handles events as well as renders a view. 

Below is shown how to use one action class to handle user event and to render a 
page. This is a simple case so it does not use redirection. Redirection is 
recommended for better use experience, but is not discussed here.

=== Action class ===

Follows is a full definition of an action class that handles user events. All 
handler methods have the same signature as {{{execute}}} method. Do not forget 
to define {{{unspecified}}} and {{{cancelled}}} methods.

{{{
package com.acme.dispatch;

import javax.servlet.ServletException;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpServletRequest;
import java.io.IOException;

import org.apache.struts.action.ActionForm;
import org.apache.struts.action.ActionMapping;
import org.apache.struts.action.ActionForward;
import org.apache.struts.action.Action;
import org.apache.struts.actions.ActionDispatcher;
import org.apache.struts.actions.ParameterListActionDispatcher;

public class DispatcherSampleAction extends Action {

  /**
   * Instantiate event dispatcher
   */
  protected ActionDispatcher dispatcher =
      new ParameterListActionDispatcher (this, false);

  /**
   * Use event dispatcher to call an appropriate event handler. 
   * By using a dispatcher an action class does not need 
   * to extend DispatchAction.
   */
  public ActionForward execute(ActionMapping mapping,
                               ActionForm form,
                               HttpServletRequest request,
                               HttpServletResponse response)
      throws Exception {
      return dispatcher.execute(mapping, form, request, response);
  }

  // Handler of Add button
  public ActionForward add(ActionMapping mapping,
                           ActionForm form,
                           HttpServletRequest request,
                           HttpServletResponse response)
          throws IOException, ServletException {
      return mapping.findForward("addpage");
  }

  // Handler of Delete button
  public ActionForward delete(ActionMapping mapping,
                              ActionForm form,
                              HttpServletRequest request,
                              HttpServletResponse response)
          throws IOException, ServletException {
      return mapping.findForward("deletepage");
  }

  // Handler of Login button
  public ActionForward login(ActionMapping mapping,
                             ActionForm form,
                             HttpServletRequest request,
                             HttpServletResponse response)
          throws IOException, ServletException {
      return mapping.findForward("loginpage");
  }

  // Handler of standard Cancel button
  public ActionForward cancelled(ActionMapping mapping,
                                 ActionForm form,
                                 HttpServletRequest request,
                                 HttpServletResponse response)
          throws IOException, ServletException {
      return mapping.findForward("cancelpage");
  }

  // Handler of button that is unknown
  public ActionForward unspecified(ActionMapping mapping,
                                   ActionForm form,
                                   HttpServletRequest request,
                                   HttpServletResponse response)
          throws IOException, ServletException {
      return mapping.findForward("unspecifiedpage");
  }
}
}}}

=== Action mapping ===

Action mapping defines possible events. Notice that {{{delete}}} is both an 
event and a method name, it is not aliased. On the other hand, {{{add}}} and 
{{{login}}} methods are aliased with {{{addEvent}}} and {{{loginEvent}}} 
events. 

{{{
<action path = "/sampleactiondispatcher"
  type = "com.acme.dispatch.DispatcherSampleAction"
  parameter = "addEvent=add,delete,loginEvent=login,default=unspecified"
  validate = "false">

  <forward name = "addpage" path = "/actiondispatcher/selectadd.html"/>
  <forward name = "deletepage" path = "/actiondispatcher/selectdelete.html"/>
  <forward name = "loginpage" path = "/actiondispatcher/selectlogin.html"/>
  <forward name = "cancelpage" path = "/actiondispatcher/selectcancel.html"/>
  <forward name = "unspecifiedpage" path = 
"/actiondispatcher/selectunspecified.html"/>
</action>
}}}

=== Input page ===
Events are sent as a request key, or is specifed as a "name" attribute for a 
submit element in HTML form. 

{{{
<html>
  <form action="sampleactiondispatcher.do" method="post">
    <p>Image button works too.</p>
    <input type="image" name="loginEvent" src="login.gif" value="Log In"><hr>

    <p>Button and link that invoke "add" handler.</p>
    <input type="submit" name="addEvent" value="Add button" />
    <a href="sampleactiondispatcher.do?addEvent=true">Add link</a><hr>

    <p>Button and link that invoke "delete" handler.</p>
    <input type="submit" name="delete" value="Delete button fancy caption" />
    <a href="sampleactiondispatcher.do?delete=true">Delete link</a><hr>

    <p>Button and link that invoke "unspecified" handler.</p>
    <input type="submit" name="anythingGoes" value="No handler" />
    <a href="sampleactiondispatcher.do?anythingGoes=true">No handler</a><hr>

    <p>This is a standard <code>&lt;html:cancel/></code> button; 
       it is autowired to <code>cancelled</code> method.
       Link works as well, but client validator will not be disabled, 
       because bCancel is not set to true.</p>
    <input type="submit" name="org.apache.struts.taglib.html.CANCEL" 
           value="Standard Cancel button works too" onclick="bCancel=true;">
    <a 
href="sampleactiondispatcher.do?org.apache.struts.taglib.html.CANCEL=true">
       Standard Cancel handler works for links</a>
  </form>
</html>
}}}

The events assigned to links have value of "true". This is a dummy value just 
to ensure that request parameter is processed correctly and not lost. The code 
above is pure HTML. Of course, you can use Struts tags as well. For 
<html:submit> tag specify event in "property" attribute. For Cancel button just 
use <html:cancel> tag.

---------------------------------------------------------------------
To unsubscribe, e-mail: [EMAIL PROTECTED]
For additional commands, e-mail: [EMAIL PROTECTED]

Reply via email to