Author: husted
Date: Sat Dec 10 19:59:35 2005
New Revision: 355892

URL: http://svn.apache.org/viewcvs?rev=355892&view=rev
Log:
MailReader tour 
* Additional interim changes
* The final pass will have to wait for the hackathon :)

Modified:
    struts/apps/trunk/mailreader/src/webapp/tour.html

Modified: struts/apps/trunk/mailreader/src/webapp/tour.html
URL: 
http://svn.apache.org/viewcvs/struts/apps/trunk/mailreader/src/webapp/tour.html?rev=355892&r1=355891&r2=355892&view=diff
==============================================================================
--- struts/apps/trunk/mailreader/src/webapp/tour.html (original)
+++ struts/apps/trunk/mailreader/src/webapp/tour.html Sat Dec 10 19:59:35 2005
@@ -1279,13 +1279,41 @@
 
     <p>
         The same thing will happen for the other markers.
-        The ActionForm name becomes "RegsiterForm".
-        The nsame of the Success server page becomes "Register.jsp".
+        The ActionForm name becomes "RegisterForm".
+        The name of the "Success" server page becomes "Register.jsp".
     </p>
 
     <p>
-        In any event, when either the Welcome page or MainMenu page link to 
"EditRegistration",
-        the framework invokes the Edit method of the RegistrationAction class.
+        The <strong>RegisterForm</strong> is a DynaActionForm, much like the 
LoginForm.
+    </p>
+
+    <hr />
+    <h5>The RegistrationForm form-bean element</h5>
+<pre><code>    &lt;!-- RegistrationAction form bean -->
+    &lt;form-bean
+            name="RegistrationForm"
+            extends="BaseForm">
+    &lt;form-property
+            name="fromAddress"
+            type="java.lang.String"/>
+    &lt;form-property
+            name="fullName"
+            type="java.lang.String"/>
+    &lt;form-property
+            name="password2"
+            type="java.lang.String"/>
+    &lt;form-property
+            name="replyToAddress"
+            type="java.lang.String"/>
+    &lt;/form-bean></code></pre>
+    <hr />
+
+    <p>
+        The <strong>RegistrationForm</strong> extends the BaseForm and adds 
properties peculiar to the Registration
+        action.
+        When either the Welcome page or MainMenu page link to 
"EditRegistration",
+        the framework creates the RegistrationForm, autopopulates the 
form-bean properties from any matching attributes
+        in the request, and invokes the Edit method of the RegistrationAction 
class.
     </p>
 
     <hr />
@@ -1438,223 +1466,407 @@
 
     <p>
         After the token has been saved,
-        Edit calls doFindSuccess and control flows to the Registration page.
+        Edit calls "doFindSuccess and" control flows to the Registration page.
     </p>
 
     <h3><a name="Registration.jsp" id="Registration.jsp">Registration 
page</a></h3>
 
     <p>
-        If you follow the "Edit your user registration profile" link from the 
mainMenu,
-        we will finally reach the heart of the Example application: the 
Registration, or "Profile", page.
-        This page displays everything the Example application knows about you 
(or at least your login),
-        while demonstrating several interesting techniques.
+        If you follow the "Edit your user registration profile" link from the 
Main Menu page,
+        we will finally reach the heart of the MailReader application: the 
Registration, or "Profile", page.
+        This page displays everything MailReader knows about you (or at least 
your login),
+        while utilizing several interesting techniques.
     </p>
 
     <p>
-        registation.jsp continues to use logic tags throughout the page so 
that a single JSP can be used to
-        perform more than one task.
-        For example, if you are editing the form (action == "Edit"),
+        To do double duty as the "Create" registration page and the "Edit" 
registration,
+        the Registation.jsp makes good use of logic tags throughout the page,
+        to make it appears as though there are two distinct pages.
+        For example, if you are editing the form (task == "Edit"),
         the page inserts your username from the RegistrationForm bean.
-        If you are new user (action == "Create"), the page creates an empty 
field, so you can pick your username.</p>
+        If you are new user (task == "Create"), the page creates an empty 
field, so you can pick your username.
+    </p>
 
+    <hr/>
+    <h5>Note:</h5>
     <blockquote>
-      <p><i>The Struts logic tags are a very convenient way to express 
application logic within your pages. This prevents user error and reduces the 
number of JSPs your application needs to maintain, among other benefits.</i></p>
+      <p><font class="hint">
+          <strong>Presention Logic</strong> -
+          The Struts logic tags are a convenient way to express presentation 
logic within your pages.
+          Customized pages help to prevent user error,
+          and dynamic customization reduces the number of JSPs your 
application needs to maintain,
+          among other benefits.
+      </font></p>
     </blockquote>
+    <hr/>
 
-    <p>The page also uses logic tags to display a list of subscriptions for 
the given user. If the user enters this page with an edit action in the request 
context, the lower part of the page listing the subscriptions is exposed by 
this logic tag:</p>
+    <p>
+        The page also uses logic tags to display a list of subscriptions for 
the given user.
+        If the RegistrationForm has task set to "Edit",
+        the lower part of the page lists the subscriptions is exposed.
+    </p>
 
-    <blockquote>
-      <p><code>&lt;logic:equal<br />
-      name="RegistrationForm"<br />
-      property="action"<br />
-      scope="request"<br />
-      value="Edit"<br />
-      &gt;</code></p>
-    </blockquote>
+    <hr />
+    <h5></h5>
+<pre><code>&lt;logic:equal name="RegistrationForm" property="task"
+            scope="request" value="Edit">
+    &lt;h3>&lt;bean:message key="heading.subscriptions"/>&lt;/h3>
+    &lt;!-- ... -->
+    &lt;html:link action="/EditSubscription">
+      &lt;bean:message key="registration.addSubscription"/>
+    &lt;/html:link>
+&lt;/logic:equal></code></pre>
+    <hr />
 
-    <p>Otherwise, the page just contains the top portion -- a blank data-entry 
form for creating the user's registration.</p>
+    <p>
+        Otherwise, the page just contains the top portion --
+        a blank data-entry form for creating the user's registration.
+    </p>
 
     <h4><a name="logic:iterate" id="logic:iterate">logic:iterate</a></h4>
 
-    <p>Beside making the usual conditional tests, you can also use logic tags 
to forward control to other actions, to redirect control to another path, and 
to iterate over collections. The registration page includes a good example of 
using the logic:iterate tag to display the user's subscriptions.</p>
+    <p>
+        Beside making the usual conditional tests,
+        you can also use logic tags to forward control to other actions,
+        to redirect control to another path, and to iterate over collections.
+        The registration page includes a good example of using the 
logic:iterate tag to display the user's subscriptions.
+    </p>
 
-    <p>The subscriptions are stored in a hashtable object, which is in turn 
stored in the user object. So to display each subscription, we have to reach 
into the user object, and loop through the members of the subscription 
collection. Using the iterate tag, this couldn't be easier.</p>
+    <p>
+        The subscriptions are stored in a hashtable object, which is in turn 
stored in the user object.
+        So to display each subscription, we have to reach into the user object,
+        and loop through the members of the subscription collection.
+        Using the iterate tag, you can code it the way it sounds.
+    </p>
 
-    <blockquote>
-      <p>&lt;logic:iterate name="user" property="subscriptions" 
id="subscription"&gt;<br />
-      &lt;!-- block to repeat --&gt;<br />
-      &lt;/logic:iterate&gt;</p>
-    </blockquote>
+    <hr />
+    <h5>Using logic:iterate to list the Subscriptions</h5>
+<pre><code>    &lt;logic:iterate <strong>name</strong>="user" 
<strong>property</strong>="subscriptions" <strong>id</strong>="subscription">
+      &lt;tr>
+        &lt;td align="left">
+          &lt;bean:write name="subscription" property="host"/>
+        &lt;/td>
+        &lt;td align="left">
+          &lt;bean:write name="subscription" property="username"/>
+        &lt;/td>
+        &lt;td align="center">
+          &lt;bean:write name="subscription" property="type"/>
+        &lt;/td>
+        &lt;td align="center">
+          &lt;bean:write name="subscription" property="autoConnect"/>
+        &lt;/td>
+        &lt;td align="center">
+          &lt;html:link action="/DeleteSubscription"
+           <strong>paramName</strong>="subscription" 
<strong>paramProperty</strong>="host" <strong>paramId</strong>="host">
+            &lt;bean:message key="registration.deleteSubscription"/>
+          &lt;/html:link>
+            &nbsp;
+          &lt;html:link action="/EditSubscription"
+           paramName="subscription" paramProperty="host" paramId="host">
+            &lt;bean:message key="registration.editSubscription"/>
+          &lt;/html:link>
+        &lt;/td>
+      &lt;/tr>
+    &lt;/logic:iterate></code></pre>
+    <hr />
 
-    <p>The three parameters to the iterate tag ( name, property, and id) tell 
it to</p>
+    <p>
+        The three parameters to the iterate tag (name, property, and id) tell 
it to
+    </p>
 
     <ol>
-      <li>Check this context for an attribute (e.g. object) named "user",</li>
-
-      <li>Snag the property of user named "subscriptions",</li>
-
-      <li>In the block to iterate, use "subscription" (singular) as the name 
for each member of the collection.</li>
+      <li>
+          <em>name</em> - Check this context for an attribute (e.g. object) 
named <strong>user</strong>,
+      </li>
+
+      <li>
+          <em>property</em> - Snag the property of user named 
<strong>subscriptions</strong>,
+      </li>
+
+      <li>
+          <em>id</em> - In the block to iterate,
+          use <strong>subscription</strong> (singular) as the name for each 
member of the collection.
+      </li>
     </ol>
 
-    <p>So, to list the host for each subscription in a HTML unordered list, we 
could write:</p>
-
-    <blockquote>
-      <p><code>&lt;ul&gt;<br />
-      &lt;logic:iterate name="user" property="subscriptions" 
id="subscription"&gt;<br />
-      &lt;li&gt;<br />
-      &lt;bean:write name="subscription" property="host" filter="true" 
/&gt;<br />
-      &lt;/li&gt;<br />
-      &lt;/logic:iterate&gt;<br />
-      &lt;/ul&gt;</code></p>
+    <p>
+        Next to each entry in the subscripotion list are links to Delete and 
Edit commands.
+        These links use the same name/property/id trinity as the interator,
+        except that the attributes are used to create a hyperlink with a 
single parameter.
+        (Multiple parameters are possible too, but if the code is 
well-factored,
+        most often one is sufficient.)
+    </p>
 
-      <p><i>This is another good example of how Struts works with the standard 
JSP tags, like bean. The filter option says to use convert HTML commands to 
their character entity. So a &lt; would be output in the HTML as 
&amp;lt;.</i></p>
-    </blockquote>
+    <p>
+        Given a subscription to "mail.yahoo.com",
+        the command links would translate to HTML links like these:
+    </p>
 
-    <p>In registration.jsp, iterate is used to create a menu of subscriptions, 
each linked with an edit and delete action.</p>
+    <hr />
+    <h5>The Delete and Edit links for mail.yahoo.com</h5>
+<pre><code>      &lt;a 
href="/struts-mailreader/DeleteSubscription.do?host=mail.yahoo.com">Delete&lt;/a>
+        &nbsp;
+      &lt;a 
href="/struts-mailreader/EditSubscription.do?host=mail.yahoo.com">Edit&lt;/a></code></pre>
+    <hr />
 
-    <blockquote>
-      <p><code>&lt;logic:iterate id="subscription" name="user" 
property="subscriptions"&gt;<br />
-      &lt;tr&gt;<br />
-      &lt;td align="left"&gt;<br />
-      &lt;bean:write name="subscription" property="host" filter="true"/&gt;<br 
/>
-      &lt;/td&gt;<br />
-      &lt;td align="left"&gt;<br />
-      &lt;bean:write name="subscription" property="username" 
filter="true"/&gt;<br />
-      &lt;/td&gt;<br />
-      &lt;td align="center"&gt;<br />
-      &lt;bean:write name="subscription" property="type" filter="true"/&gt;<br 
/>
-      &lt;/td&gt;<br />
-      &lt;td align="center"&gt;<br />
-      &lt;bean:write name="subscription" property="autoConnect"/&gt;<br />
-      &lt;/td&gt;<br />
-      &lt;td align="center"&gt;<br />
-      &lt;app:linkSubscription 
page="/EditSubscription.do?action=Delete"&gt;<br />
-      &lt;bean:message key="registration.deleteSubscription"/&gt;<br />
-      &lt;/app:linkSubscription&gt;<br />
-      &lt;app:linkSubscription page="/EditSubscription.do?action=Edit"&gt;<br 
/>
-      &lt;bean:message key="registration.EditSubscription"/&gt;<br />
-      &lt;/app:linkSubscription&gt;<br />
-      &lt;/td&gt;<br />
-      &lt;/tr&gt;<br />
-      &lt;/logic:iterate&gt;</code></p>
+    <p>
+        At the foot of the Register page is a link for adding a subscription.
+        Let's wind up the tour by following the Add link and then logging off.
+        Like the link for creating a Registration, Add  points to an "Edit" 
action,
+        namely "EditSubscription".
+    </p>
 
-      <p><i>The collection in an iterate tag can be any of the following: an 
array of objects, an Iterator, a Collection (which includes Lists, Sets and 
Vectors), or a Map (which includes Hashtables) whose elements will be iterated 
over.</i></p>
-    </blockquote>
+    <h4>
+        <a name="EditSubscriptionAction.java" 
id="EditSubscriptionAction.java">EditSubscriptionAction.java</a>
+    </h4>
 
-    <p>You'll note that the hyperlinks to the edit and delete action for each 
subscription are written with another custom tag, app:linkSubscription. Writing 
a hyperlink to an action is not difficult, but it can be ugly, and makes an 
excellent case for encapsulation. If you trace through the app.tld, you will 
find that the source code for the linkSubscription tag lives in (<i>come on, 
take a guess</i>) LinkSubscriptionTag.java.</p>
+    <p>
+        The EditSubscription links reuses the Wildcard "/Edit*" link used by 
EditRegistration,
+        so there nothing new to show there.
+        As before, in the case of "Edit<em>Subscription</em>",
+        the "{1}Form" attribute maps to <strong>SubscriptionForm</strong>.
+    </p>
 
-    <h4><a name="LinkSubscriptionTag.java" 
id="LinkSubscriptionTag.java">LinkSubscriptionTag.java</a></h4>
+    <hr />
+    <h5>The SubscriptionAction form-bean element</h5>
+<pre><code>        &lt;form-bean
+            name="SubscriptionForm"
+            extends="BaseForm">
+            &lt;form-property
+                    name="autoConnect"
+                    <strong>type="java.lang.Boolean"
+                    initial="FALSE"
+                    reset="true"</strong>/>
+            &lt;form-property
+                    name="host"
+                    type="java.lang.String" />
+            &lt;form-property
+                    name="type"
+                    type="java.lang.String" />
+        &lt;/form-bean></code></pre>
+    <hr />
 
-    <p>The Example application uses a subscription's host name (e.g. 
yahoo.com) as a primary key, which means you can only have one subscription for 
each host. It also means that to edit a subscription, all you need to know is 
the user and host. In fact, the EditSubscription action is designed to create, 
edit, or delete a subscription if provided a user and host names in the 
request. The goal of LinkSubscriptionTag is then to output a block like:</p>
+    <p>
+        The other DynaActionForms we've seen used only String properties.
+        SubscriptionForm is different in that it uses a Boolean type for the 
"autoConnect" property.
+        On the HTML form, the autoConnect field is represented by a checkbox,
+        and checkboxes need to be handled differently that other controls.
+    </p>
 
+    <hr/>
+    <h5>Note:</h5>
     <blockquote>
-      <p><code>&lt;A 
HREF=[path]EditSubscription.do?action=[action]&amp;username=[user]&amp;host=[host]"&gt;[action]<br
 />
-      &lt;/A&gt;</code></p>
-    </blockquote>
-
-    <p>based on input block like:</p>
+      <p class="hint">
+          <strong>Checkboxes</strong> -
+          The HTML checkbox is a tricky control.
+          The problem is that, according to the W3C specification, a value is 
only guarnateed to be sent
+          if the control is checked.
+          If the control is not checked, then the control may be omitted from 
the request, as if it was on on the page.
+          This can cause a problem with session-scope checkboxes.
+          Once you set the checkbox to true, the control can't set it to false 
again,
+          because if you uncheck the box, nothing is sent, and so the control 
stays false.
+      </p>
 
-    <blockquote>
-      <p><code>&lt;app:linkSubscription<br />
-      page="/EditSubscription.do?action=Delete"&gt;Delete<br />
-      &lt;/app:linkSubscription&gt;</code></p>
+      <p class="hint">
+          The simple solution is to set the value for a checkbox control to 
false before the form is populated.
+          If the checkbox is checked, it will return a value, and the checkbox 
will represent true.
+          If the checkbox is unchecked, it will not return a value, and the 
checkbox will remain false.
+      </p>
     </blockquote>
+    <hr/>
 
-    <p>To reduce overhead, LinkSubscriptionTag uses "subscription" as the 
default name (which the iterator refers to as "ID"), so that can be omitted 
from the tag properties. The "action" portion of the will differ, and so that 
is given as the page property to the tag</p>
+    <p>
+        To be sure the autoConnect checkbox is handled correctly,
+        the SubscriptionForm initilizes the property to FALSE, and sets 
"reset" to TRUE,
+        so that the property is set back to FALSE before autopopulation.
+    </p>
 
-    <p>Here are a few annotated highlights from LinkSubscriptionTag.java:</p>
+    <p>
+        The SubscriptionForm will also look familiar, but it also has a few 
twists of its own.
+    </p>
 
-    <ol>
-      <li><i>Create a string buffer, and ask the request for the relative path 
to the application</i><br />
-      <code>StringBuffer url = new 
StringBuffer(request.getContextPath());</code></li>
+    <hr/>
+    <h5>SubscriptionAction.Edit</h5>
+<pre><code>public ActionForward Edit(
+        ActionMapping mapping,
+        ActionForm form,
+        HttpServletRequest request,
+        HttpServletResponse response)
+        throws Exception {
 
-      <li><i>Snag a reference to the subscription bean (for this iteration)<br 
/></i> <code>subscription = (Subscription) 
pageContext.findAttribute(name);</code></li>
+        final String method = Constants.EDIT;
+        doLogProcess(mapping,method);
 
-      <li><i>Append the username and host from the bean to the path 
request.<br /></i> <code>url.append("&amp;username="); 
url.append(BeanUtils.filter(subscription.getUser().getUsername()));<br />
-      url.append("&amp;host=");<br />
-      url.append(BeanUtils.filter(subscription.getHost()));</code></li>
-    </ol>
+        HttpSession session = request.getSession();
+        User user = doGetUser(session);
+        <strong>if (user==null) return doFindLogon(mapping);</strong>
+
+        // Retrieve the subscription, if there is one
+        Subscription subscription;
+        <strong>String host = doGet(form,HOST);
+        boolean updating = (host!=null);</strong>
+        if (updating) {
+            subscription = <strong>doFindSubscription</strong>(user,host);
+            if (subscription==null) return 
<strong>doFindFailure</strong>(mapping);
+            session.setAttribute(Constants.SUBSCRIPTION_KEY, subscription);
+            <strong>doPopulate</strong>(form,subscription);
+            doSet(form,TASK,method);
+        }
 
-    <p>These are the essentials, but be sure to see the full source in 
LinkSubscriptionTag.java for the rest of the error and logic checking that a 
working application needs to succeed.</p>
+        return doFindSuccess(mapping);
+    }</code></pre>
+    <hr />
 
-    <p>Meanwhile, back on registration.jsp, there is one more link on the 
page. This uses yet another custom tag, the app:linkUser tag.</p>
+    <p>
+        In RegistrationAction, we looked for the user object to decide if we 
were updating or inserting.
+        In SubscriptionAction, the user object is required (and we trot off to 
the Login page if it is missing).
+        This could happen because a session expired, or because someone 
bookmarked a page.
+    </p>
 
-    <blockquote>
-      <p><code>&lt;app:linkUser 
page="/EditSubscription.do?action=Create"&gt;<br />
-      &lt;bean:message key="registration.addSubscription"/&gt;<br />
-      &lt;/app:linkUser&gt;</code></p>
-    </blockquote>
+    <p>
+        To decide if we are inserting or updating a subscription,
+        we look to see if the <strong>host</strong> is set to the ActionForm.
+        If it is an update, we fetch the subcription from the database.
+    </p>
 
-    <p>By this time, you must be ready to flip directly to LinkUserTag.java 
with nary a glance at the configuration file ...</p>
+    <hr />
+    <h5>SubscriptionAction.doFindSubscription</h5>
+<pre><code>    private Subscription doFindSubscription(User user, String host) 
{
 
-    <h4><a name="LinkUserTag.java" 
id="LinkUserTag.java">LinkUserTag.java</a></h4>
+        Subscription subscription;
 
-    <p>Since they solve the same general problem, LinkUserTag and 
LinkSubscriptionTag are quite a bit a like, except that LinkUserTag grabs the 
user bean from the session context, instead of a subscription bean from the 
iteration. Like the LinkSubscriptionTag, the name for the user bean (e.g. 
"user") is defaulted, and can be omitted from the tag; all that's needed is the 
page property -- the rest is automatic!</p>
+        try {
+            subscription = user.findSubscription(host);
+        }
+        catch (NullPointerException e) {
+            subscription = null;
+        }
 
-    <blockquote>
-      <p><code>&lt;app:linkUser 
page="/EditSubscription.do?action=Create"&gt;<br />
-      &lt;bean:message key="registration.addSubscription"/&gt;<br />
-      &lt;/app:linkUser&gt;</code></p>
-    </blockquote>
+        if ((subscription == null) && (log.isTraceEnabled())) {
+            log.trace(
+                " No subscription for user "
+                + user.getUsername()
+                + " and host "
+                + host);
+        }
 
-    <p>When rendered, this displays a HTML hypertext link like:</p>
+        return subscription;
+    }</code></pre>
+    <hr />
 
-    <blockquote>
-      <p><code>&lt;a 
href="/struts-example/EditSubscription.do?action=Create&amp;amp;username=user"&gt;<br
 />
-      Add<br />
-      &lt;/a&gt;</code></p>
+    <p>
+        If we can't find the subscription,
+        we use <strong>doFindFailure</strong> to forward to the Failure result 
(Error.jsp).
+    </p>
 
-      <p><i>Note that anchor links with ampersands should use the character 
entity &amp;amp; as the LinkUserTag has done here (<a 
href="http://www.w3.org/TR/html401/appendix/notes.html#h-B.2.2";>http://www.w3.org/TR/html401/appendix/notes.html#h-B.2.2</a>).</i></p>
-    </blockquote>
+    <hr />
+    <h5>BaseAction.doFindFailure</h5>
+<pre><code>    protected ActionForward doFindFailure(ActionMapping mapping) {
+        if (log.isTraceEnabled()) {
+            log.trace(Constants.LOG_FAILURE);
+        }
+        return (mapping.findForward(Constants.FAILURE));
+    }
+</code></pre>
+    <hr />
 
-    <p>Let's follow that "Add" link now and see what's up with the 
EditSubcription action anyway.</p>
+    <p>
+        In the normal course, the subscription should alwawys be found,
+        since we selected the host from a system-generated list.
+        If the subscription is not found,
+        it would because the database disappeared or the request is being 
spoofed.
+    </p>
 
-    <h4><a name="EditSubscriptionAction.java" 
id="EditSubscriptionAction.java">EditSubscriptionAction.java</a></h4>
+    <p>
+        Like the RegisterAction, the <strong>doPopulate</strong> method 
transfers data from the form to the domain
+        object. In this case, a Subscription object.
+    </p>
 
-    <p>Predictably, we find a some now-familiar mappings in 
struts-config.xml</p>
+    <hr />
+    <h5>SubscriptionAction.doPopulate</h5>
+<pre><code>    private void doPopulate(ActionForm form, Subscription 
subscription) throws ServletException {
 
-    <blockquote>
-      <p><code>&lt;!-- Subscription form bean --&gt;<br />
-      &lt;form-bean<br />
-      name="SubscriptionForm"<br />
-      type="org.apache.struts.webapp.example.SubscriptionForm"<br />
-      /&gt;</code></p>
+        final String title = Constants.EDIT;
 
-      <p><code>&lt;!-- Edit mail subscription --&gt;<br />
-      &lt;action path="/EditSubscription"<br />
-      type="org.apache.struts.webapp.example.EditSubscriptionAction"<br />
-      name="SubscriptionForm"<br />
-      scope="request"<br />
-      validate="false"<br />
-      &gt;<br />
-      &lt;forward name="failure" path="/mainMenu.jsp"/&gt;<br />
-      &lt;forward name="success" path="/subscription.jsp"/&gt;<br />
-      &lt;/action&gt;</code></p>
+        if (log.isTraceEnabled()) {
+            log.trace(Constants.LOG_POPULATE_FORM + subscription.getHost());
+        }
 
-      <p><i>When we've introduced these type of mappings before, and mentioned 
that the struts-config.xml was parsed when the ActionServlet was initialized. 
But we should make it clear that when the Struts digester parsed this file, it 
actually created standard Java objects, linked as properties to the controller. 
This means you don't have to edit Java source files just to add a bunch of 
"new" statements. (How cool is that?)</i></p>
-    </blockquote>
+        try {
+            <strong>PropertyUtils.copyProperties(form, subscription);</strong>
+            doSet(form,TASK,title);
+        } catch (InvocationTargetException e) {
+            Throwable t = e.getTargetException();
+            if (t == null) t = e;
+            log.error(LOG_SUBSCRIPTION_POPULATE, t);
+            throw new ServletException(LOG_SUBSCRIPTION_POPULATE, t);
+        } catch (Throwable t) {
+            log.error(LOG_SUBSCRIPTION_POPULATE, t);
+            throw new ServletException(LOG_SUBSCRIPTION_POPULATE, t);
+        }
+    }</code></pre>
+    <hr />
 
-    <p>Following what was specified by struts-config.xml, the controller makes 
sure that a SubscriptionForm bean exists, along with the SubscriptionAction 
object, and then calls the action object's perform method. The perform method 
first checks to see that the user is logged-in. If not, control is forwarded to 
the Login action. EditSubscriptionAction.perform then either creates a new 
subscription object (if the task is Create), or searches the user's 
subscription hashtable for a matching hostname (if the task is Edit).</p>
+    <p>
+        Most of the code in "doPopulate" is window dressing for the call to
+        <strong>PropertyUtils.copyProperties</strong>, which does the heavy 
lifting.
+    </p>
 
-    <p>Finally, EditSubscriptionAction conforms the ActionForm bean with the 
database bean. There may be several subscriptions in the database, but in 
EditSubscriptionAction we expose the one selected (or just created) for this 
request to use. Once the Action form (called "subform" in the code) is created 
and populated from the database, the bean's action is set to either Create or 
Edit, and control is forwarded to our "success" form, subscription.jsp .</p>
+    <p>
+        But before turning to our final JSP, a word about our database model 
...
+    </p>
 
-    <blockquote>
-      <p><i>Note that the servlet only creates one object for each action. 
Each request is handled as a separate thread, and passed to the single action 
object instance. This means your action objects must be multi-thread 
safe.</i></p>
-    </blockquote>
+    <h4>
+        <a name="User.java" id="User.java">User.java</a> and <a 
name="Subscription.java" id="Subscription.java">Subscription.java</a></h4>
 
-    <p>But before turning to our final JSP, a word about our database model 
...</p>
+    <p>
+        If you're used to working with relational databases,
+        the links between the user and subscription objects may be confusing.
+        A conventional relational database would create two distinct tables,
+        one for the users and another for the subscriptions,
+        and link them together with a user ID.
+        The MailReader application implements a different model, a 
hierarchical database.
+        Here a "table" of subscriptions is stored within each user object,
+        something like the way a filing system stores documents within folders.
+    </p>
 
-    <h4><a name="User.java" id="User.java">User.java</a> and <a 
name="Subscription.java" id="Subscription.java">Subscription.java</a></h4>
+    <p>
+        Development teams often use frameworks like Hibernate to map a 
relational database to a hierarchy of objects,
+        like the one used by MailReader.
+        For simplicity, the MailReader doesn't use a conventional database, 
but saves its data as an XML file.
+        While the MailReader is running, the database is kept in main memory, 
and written to back to disk when changed.
+    </p>
 
-    <p>If you're used to working with relational databases, the links between 
the user and subscription objects may be confusing. A conventional relational 
database would create two distinct tables, one for the users and another for 
the subscriptions, and link them together with a user ID. The Example 
application implements a different model, a hierarchical database. Here a 
"table" of subscriptions is stored within each user object, something like the 
way a filing system stores documents within folders.</p>
+    <p>
+        In addition to the usual getters and setters,
+        the user object also has two methods for working with subscription 
objects.
+        The <strong>findSubscription</strong> method takes a hostname and 
returns the subscription object for that host.
+        The <strong>getSubscriptions</strong> method returns an array of all 
the subscriptions for the user
+        (ready-made for the iterate tag!).
+        Besides the fields needed to manage the SubscriptionForm data,
+        the object also maintains a runtime link to its own user object.
+    </p>
 
-    <p>In addition to the usual getters and setters, the user object also has 
two methods for working with subscription objects. findSubscription takes a 
hostname and returns the subscription object for that host. getSubscriptions 
returns an array of all the subscriptions for the user (ready-made for the 
iterate tag!). Besides the fields needed to manage the SubscriptionForm data, 
the object also maintains a runtime link to its user object.</p>
+    <p>
+        To create a new subscription,
+        EditSubscriptionAction.java simply creates a new subscription object,
+        and sets its user to the object found in the request,
+        and then forwards control to its input form, Subscription.jsp.
+    </p>
 
-    <p>To create a new subscription, EditSubscriptionAction.java simply 
creates a new subscription object, and sets its user to the object found in the 
request, and then forwards control to its input form, subscription.jsp.</p>
+    <h3><a name="subcription.jsp" 
id="subcription.jsp">Subscription.jsp</a></h3>
 
-    <h3><a name="subcription.jsp" 
id="subcription.jsp">subscription.jsp</a></h3>Saving the best for last, 
subscription.jsp demonstrates use of some interesting Struts custom form tags, 
html:options and html:checkbox.
+    <p>
+        Saving the best for last, Subscription.jsp utilizes two interesting 
Struts custom form tags,
+        "html:options" and "html:checkbox".
 
-    <p>In registration.jsp, the Struts iteration tag was used to write a list 
of subscriptions. Another place where iterations and collections are handy is 
the option list for a HTML select tag. Since this is such a common situation, 
Struts offers a html:options (plural) tag can take an array of objects as a 
parameter. The tag then iterates over the members of the array (beans) to place 
each one inside an standard option tag. So given a block like</p>
+    <p>
+        In Registration.jsp, the Struts iteration tag was used to write a list 
of subscriptions.
+        Another place where iterations and collections are handy is the option 
list for a HTML select tag.
+        Since this is such a common situation, Struts offers a html:options 
(plural) tag
+        that can take an array of objects as a parameter.
+        The tag then iterates over the members of the array (beans) to place 
each one inside an standard option tag.
+        So given a block like</p>
 
     <blockquote>
       <p><code>&lt;html:select property="type"&gt;<br />
@@ -1666,7 +1878,7 @@
       &lt;/html:select&gt;</code></p>
     </blockquote>
 
-    <p>Struts outputs a block like</p>
+    <p>The tag outputs a block like</p>
 
     <blockquote>
       <p><code>&lt;select name="type"&gt;<br />
@@ -1675,32 +1887,54 @@
       &lt;/select&gt;</code></p>
     </blockquote>
 
-    <p>Here, one collection contained both the labels and the values, from 
properties of the same name. Options can also use a second array for the 
labels, if they do not match the values. Options can use a Collection, 
Iterator, or Map for the source of the list.</p>
-
-    <p>For demonstrations purposes, the serverTypes array is created at the 
top of this page. Usually, the html:options tag would be used to list valid 
items from a database maintained elsewhere. For example, if the application 
needed you to select a default subscription, a form might list the 
subscriptions in an options tag.</p>
+    <p>
+        Here, one collection contained both the labels and the values, from 
properties of the same name.
+        Options can also use a second array for the labels, if they do not 
match the values.
+        Options can use a Collection, Iterator, or Map for the source of the 
list.
+    </p>
 
-    <blockquote>
-      <p><i>The LabelValueBean used to create the demonstration array is also 
a good example of simple but useful bean object.</i></p>
-    </blockquote>
+    <p>
+        Unlike other data, the serverTypes array is not fetched from the 
database.
+        Instead, it is loaded by a Struts plugin.
+        The <strong>DigestingPlugin</strong> parses an XML document using a 
given set of Digester rules.
+        The MailReader uses a set of rules for "LabelValueBeans" to create a 
list of server types.
+    </p>
+
+        <hr/>
+        <h5>Note:</h5>
+        <blockquote>
+          <p><font class="hint">
+              <strong>LabelValueBeans</strong> -
+              Many developers find the LabelValueBeans useful,
+              so the class is available in the Struts Action distribution as
+              [org.apache.struts.util.LabelValueBean].
+          </font></p>
+        </blockquote>
+        <hr/>
+
+    <p>
+        The plugin stores the list is stored in application scope.
+        Since the Struts custom tags, like standard JSP tags, search the 
scopes in succession,
+        the tag finds the list in application scope and uses it to write out 
the options.
+    </p>
 
-    <p>A particularly tricky HTML control is the checkbox. A problem with a 
checkbox is that it is only sent in the request if it is checked. If it is not 
checked, it is not sent (i.e. null). This can be problematic when trying to 
validate the form's data after it has been translated to a bean. The 
autoconnect property for a subscription demonstrates how to handle validation 
of a checkbox.</p>
 
     <h4><a name="SubscriptionForm.java" 
id="SubscriptionForm.java">SubscriptionForm.java</a></h4>
 
-    <p>Struts validation is handled by the reset and validate methods of the 
ActionForm bean. When creating your own form beans, you should subclass 
ActionForm, add your own fields and their getters/setters, and implement the 
reset and validate methods.</p>
-
-    <p>Struts calls reset before populating the form, and calls validate after 
populating it but before the perform method of the action. Reset should assign 
default values to each of your form fields, usually null. But in the case of 
checkboxes, the default value should usually be false instead of null.</p>
-
-    <blockquote>
-      <p><i>For more examples of validating forms, take another look at 
LoginForm.java and RegistrationForm.java.</i></p>
-    </blockquote>
-
-    <p>Back in subscription.jsp, we have one more block to cover. Although the 
same basic form can be used to created, edit, or delete a subscription, people 
might expect the buttons to be labeled differently in each case. 
subscription.jsp accommodates by using a logic tag to output a different set of 
buttons for each case. This doesn't really change the way subscription.jsp 
works, but it does make things less confusing for the user.</p>
+    <p>
+        Back in Subscription.jsp, we have one more block to cover.
+        Although the same basic form can be used to created, edit, or delete a 
subscription,
+        people might expect the buttons to be labeled differently in each case.
+        Like the Registration page, the Subscription page handles customization
+        by using a logic tag to output a different set of buttons for each 
case.
+        Changing buttons doesn't really change the way the Subscription page 
works,
+        but customizing the buttons does make things less confusing for the 
user.
+    </p>
 
     <blockquote>
       <p><code>&lt;logic:equal<br />
       name="SubscriptionForm"<br />
-      property="action"<br />
+      property="task"<br />
       scope="request"<br />
       value="Create"&gt;<br />
       &lt;html:submit&gt;<br />
@@ -1708,15 +1942,34 @@
       &lt;/logic:equal&gt;</code></p>
     </blockquote>
 
-    <p>In the case of a request to delete a subscription, the submit button is 
labeled "Confirm", since this view is meant to give the user a last chance to 
cancel, before sending that task along to SaveSubscriptionAction.java.</p>
+    <p>
+        In the case of a request to delete a subscription,
+        the submit button is labeled "Confirm", since this view is meant to 
give the user a last chance to cancel,
+        before sending that task along to SaveSubscriptionAction.java.
+    </p>
 
-    <p>The actual action property is placed into the form as a hidden field, 
and SaveSubscriptionAction checks that property to execute the appropriate 
task.</p>
+    <p>
+        The actual task property is placed into the form as a hidden field,
+        and SaveSubscriptionAction checks that property to execute the 
appropriate task.
+    </p>
 
     <h4><a name="SaveSubscriptionAction.java" 
id="SaveSubscriptionAction.java">SaveSubscriptionAction.java</a></h4>
 
-    <p>Our final stop has the job of finishing what 
EditSubscriptionAction.java and subscription.jsp started. After the usual logic 
and error checking, SaveSubscriptionAction either deletes or updates the 
subscription object being handled by this request, and cleans up the bean, just 
to be tidy. By now, you should be very comfortable reading through the source 
on your own, to pickup the finer points.</p>
+    <p>
+        Our final stop has the job of finishing what 
EditSubscriptionAction.java and subscription.jsp started.
+        After the usual logic and error checking,
+        SaveSubscriptionAction either deletes or updates the subscription 
object being handled by this request,
+        and cleans up the bean, just to be tidy.
+        By now, you should be very comfortable reading through the source on 
your own, to pickup the finer points.
+    </p>
 
-    <p>This concludes our tour. To review, you may wish to trace the path a 
new user takes when they register with the application for the first time. You 
should also read over each of the .java and JSP files carefully, since we only 
covered the high points here.</p>
+    <p>
+        This concludes our tour.
+        To review, you may wish to trace the path a new user takes
+        when they register with the application for the first time.
+        You should also read over each of the .java and JSP files carefully,
+        since we only covered the high points here.
+    </p>
 
     <h3><a name="Summary" id="Summary">Summary</a></h3>
 



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

Reply via email to