<?xml version="1.0"?>
<!--
    $Id: dispatchValidator.xml 481833 2006-12-03 17:32:52Z niallp $

    Licensed to the Apache Software Foundation (ASF) under one or more
    contributor license agreements.  See the NOTICE file distributed with
    this work for additional information regarding copyright ownership.
    The ASF licenses this file to You under the Apache License, Version 2.0
    (the "License"); you may not use this file except in compliance with
    the License.  You may obtain a copy of the License at
   
         http://www.apache.org/licenses/LICENSE-2.0
   
    Unless required by applicable law or agreed to in writing, software
    distributed under the License is distributed on an "AS IS" BASIS,
    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    See the License for the specific language governing permissions and
    limitations under the License.
-->
<!--
// ======================================================================== 78
-->
<document>

    <properties>
        <title>Creating a Multipage Wizard with DispatchAction and Validator</title>
    </properties>

    <body>

        <section name="Creating a Multipage Wizard with DispatchAction and Validator">


                <p>
                    This is simple example to illustrate how to build a
                    multi-page
                    wizard that utilizes both the
                    <code>DispatchAction</code>
                    and Commons Validator.
                    Using the
                    <code>DispatchAction</code>
                    helps to minimize the number of action classes
                    while the Validator supports the declarative
                    (non-programmatic) specification of
                    form field validations.
                </p>


            <subsection name="Using the DispatchAction">

                <p>
                    The example used is a simple two page wizard. The first
                    page prompts
                    for a name, while the second for an address.
                    The application URL has the form
                </p>

                <source><![CDATA[
http://localhost:8080/howto/name.do?submitName=enterName
]]></source>
                <p>
                    where the
                    <code>submitName</code>
                    parameter is used to specify the name
                    of the method in the action class that will be called to
                    process the request. In the action mapping the value of
                    the
                    <code>parameter</code>
                    attribute specifies the name of the dispatch request
                    parameter (i.e.
                    <code>parameter="submitName"</code>
                    ).
                </p>

                <source><![CDATA[
<action path="/name"
        type="com.acme.AcmeAction"
        name="acmeForm"
        scope="session"
        input="/pages/name.jsp"
        parameter="submitName">
    <forward name="name"
             path="/pages/name.jsp"/>
    <forward name="address"
            path="/pages/address.jsp"/>
</action>
]]></source>

                <p>
                The method
                <code>enterName</code>
                simply forwards to the first page.
                </p>

                <source><![CDATA[
public ActionForward enterName(ActionMapping mapping,
                               ActionForm form,
                               HttpServletRequest request,
                               HttpServletResponse response)
       throws Exception {

    return mapping.findForward("name");

}
]]></source>

                <p>
                On the page
                <code>name.jsp</code>
                is a hidden field for the
                <code>submitName</code>
                parameter.

                Submitting the name page calls method
                <code>enterAddress</code>
                by using
                Javascript to set the
                <code>submitName</code>
                parameter
                </p>


                <source><![CDATA[
<html:submit onclick="this.form.submitName.value='enterAddress'"/>
]]></source>

                <p>
                The
                <code>enterAddress</code>
                method then forwards to the address page.
                </p>

                <source><![CDATA[
public ActionForward enterAddress(ActionMapping mapping,
                                  ActionForm form,
                                  HttpServletRequest request,
                                  HttpServletResponse response)
      throws Exception {

    return mapping.findForward("address");
}
]]></source>

                <p>
                On the
                <code>adddress.jsp</code>
                page, we again dynamically set the
                <code>submitName</code>
                parameter.
                </p>

                <source><![CDATA[
<html:submit value="submit" onclick="this.form.submitName.value='submitAddress'"/>
]]></source>

                <p>
                And the action path that is submitted is
                </p>

                <source><![CDATA[
    <html:form action="/address">
]]></source>

                <p>
                The action mapping for
                <code>/address</code>
                is
                </p>

                <source><![CDATA[
<action path="/address"
        type="com.acme.AcmeAction"
        name="acmeForm"
        scope="session"
        input="/pages/address.jsp"
        parameter="submitName">

        <forward name="previous"
                 path="/pages/name.jsp"/>

        <forward name="done"
                 path="/pages/done.jsp"/>

</action>
]]></source>

                <p>
                Note that two action mappings are required to handle the page
                flow (we'll discuss why
                in the next section).
                </p>

            </subsection>

            <subsection name="Validations">

                <p>
                Let's now add some validations to require input fields using
                the
                Validator. In validation.xml, there's a
                <code>formset</code>
                definition
                that specifies two field validations for the form bean
                named
                <code>acmeForm.</code>
                </p>

                <source><![CDATA[
<formset>
   <form name="acmeForm">
      <field property="firstName" page="1" depends="required">
          <arg0 key="prompt.name"/>
      </field>
       <field property="streetAddress" page="2" depends="required">
          <arg0 key="prompt.address"/>
      </field>
    </form>
  </formset>
]]></source>

                <p>
                We need to identify the page where the input field resides so
                that
                we can control which validations are triggered for a given
                form
                submission. Without using the page property, any request that
                involves the
                <code>acmeForm</code>
                would trigger all of the validations
                associated with
                <code>acmeForm</code>
                (even validations for fields that the user
                has not seen yet).
                </p>
                <p>
                On each of the pages, a hidden field is used to identify
                the page number.
                </p>
                <p>
                In
                <code>name.jsp</code>
                </p>

                <source><![CDATA[
<html:hidden property="page" value="1"/>
]]></source>

                <p>
                In
                <code>address.jsp</code>
                </p>

                <source><![CDATA[
<html:hidden property="page" value="2"/>
]]></source>

                <p>
                The Validator will use the value of the page property in
                determining which validations to run.
                </p>
                <p>                
                Now let's revisit the reason for having two action mappings.
                An action mapping
                is required for each page since the
                <code>input</code>
                attribute specifies the page to forward
                to in case validation fails. Therefore we need to define an
                action mapping for each page
                that could be displayed after a validation fails.
                </p>

            </subsection>

            <subsection name="Cancel and Previous">

                <p>
                The tricky part is how to setup Previous and Cancel buttons
                for each of the pages. If the user clicks Previous then
                the validations for the currrent page should not be triggered.
                For Cancel, none of the validations should be triggered.
                </p>
                <p>
                The solution for Previous is to set the page number property
                to the number of the previous page, effectively circumventing
                the validations associated with the current page.
                </p>

                <source><![CDATA[
   <html:submit value="previous"
          onclick="this.form.submitName.value='previous'; this.form.page.value='1'"/>
]]></source>
                <p>
                For cancel, there are two options. We could use the Struts
                Taglib
                Cancel button or create an action specifically designed to
                process
                a cancel request. The
                <code>cancel</code>
                action has no associated validations.
                </p>

                <source><![CDATA[
<action path="/cancel"
        type="com.acme.CancelAction">

    <forward name="cancel"
             path="/pages/cancel.jsp"/>

</action>
]]></source>

                <p>
                And the Cancel button submits to the
                <code>/cancel</code>
                action path.
                </p>

                <source><![CDATA[
<html:submit value="cancel" onclick="this.form.action='/acme/cancel.do'"/>
]]></source>

                <p>
                The full example is
                <a href="dispatchValidator.zip">available for download.</a>
                </p>

            </subsection>

        </section>
    </body>

</document>
