From 6b4325fa5d611f5fe4c2099a5b5b1578ba2a2964 Mon Sep 17 00:00:00 2001 From: Ted Nathan Husted Date: Tue, 12 Sep 2006 00:04:46 +0000 Subject: [PATCH] WW-1349 MailReader - Refator subscripton actions into a package so that they can share settings. Update tour. git-svn-id: https://svn.apache.org/repos/asf/struts/struts2/trunk@442393 13f79535-47bb-0310-9956-ffa450edef68 --- .../src/main/java/mailreader-support.xml | 22 ++- .../src/main/java/struts.properties | 2 +- apps/mailreader/src/main/webapp/tour.html | 150 ++++++++---------- 3 files changed, 84 insertions(+), 90 deletions(-) diff --git a/apps/mailreader/src/main/java/mailreader-support.xml b/apps/mailreader/src/main/java/mailreader-support.xml index f84c58ee0..05091bafc 100644 --- a/apps/mailreader/src/main/java/mailreader-support.xml +++ b/apps/mailreader/src/main/java/mailreader-support.xml @@ -20,7 +20,7 @@ Welcome - + /Login.jsp Welcome MainMenu @@ -31,23 +31,29 @@ - + /Registration.jsp MainMenu + - + + + /Subscription.jsp Registration!input + + + - - /Subscription.jsp - Registration!input - - + + + + + /{1}.jsp diff --git a/apps/mailreader/src/main/java/struts.properties b/apps/mailreader/src/main/java/struts.properties index 15de55115..14f925247 100644 --- a/apps/mailreader/src/main/java/struts.properties +++ b/apps/mailreader/src/main/java/struts.properties @@ -1,4 +1,4 @@ struts.objectFactory = spring -struts.devMode = true +struts.devMode = false struts.action.extension = do struts.enable.DynamicMethodInvocation = false diff --git a/apps/mailreader/src/main/webapp/tour.html b/apps/mailreader/src/main/webapp/tour.html index 4277e16e8..851ec084d 100644 --- a/apps/mailreader/src/main/webapp/tour.html +++ b/apps/mailreader/src/main/webapp/tour.html @@ -1262,7 +1262,7 @@ public void setSession(Map value) {
mailreader-support.xml Login
-
<action name="Login!*" class="mailreader2.Login" method="{1}">
+
<action name="Login!*" method="{1}" class="mailreader2.Login">
   <result name="input">/pages/Login.jsp</result>
   <result name="cancel" type="redirect-action">Welcome</result>
   <result type="redirect-action">MainMenu</result>
@@ -1967,7 +1967,7 @@ public class AuthenticationInterceptor implements Interceptor {
 
 
mailreader-support.xml Subscription element
-
<action name="Subscription!*" class="mailreader2.Subscription" method="{1}">
+
<action name="Subscription!*" method="{1}" class="mailreader2.Subscription">
   <result name="input">/pages/Subscription.jsp</result>
   <result type="redirect-action">Registration!input</result>
 </action>
@@ -2260,96 +2260,39 @@ public Subscription findSubscription(String host) {

Like many applications, the MailReader uses mainly String properties. One exception is the AutoConnect property of the Subscription object. - On the HTML form, the AutoConnect property is represented by a checkbox, - and checkboxes need to be handled differently that other controls. + On the HTML form, the AutoConnect property is represented by a checkbox.

- The checkbox starts out as a simple enough control. -

- -
  <s:checkbox label="%{getText('autoConnect')}"
-  name="subscription.autoConnect"/>
- -

+ When writing web applications, the checkbox can be a tricky control. The Subscription object has a boolean AutoConnect property, and the checkbox simply has to represent its state. The problem is, if you clear a checkbox, the browser client will not submit anything. Nada. Zip. It is as if the checkbox control never existed. - The HTTP protocol has no way to affirm "false". + The HTTP protocol has no way to affirm "false". If the control is missing, we need to figure out it's been unclicked.

-
-
Tip:
-
-

- Checkboxes - - The HTML checkbox is a tricky control. - The problem is that, according to the W3C specification, a value is - only guaranteed 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 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 checked. -

-
-
-

- The simplest solution is to employ our old friend Preparable again, - and reset the checkbox just before a Subscription is saved. - If the control is not submitted, then the property remains false. - If the control is submitted, then the property is set to true. + In Struts 1, + we use the reset method to work around checkbox issues. + In Struts 2, checkbox state is handled automatically. + The framework can detect when a checkbox tag has not been sent back, + and when that happens, + a default "false" value is used for the checkbox value. + No worries, mate.

-

- But, we only want to reset the checkbox when we are about to save - a Subscription. - If we add it to the Subscription class, - all of the aliases will reset the checkbox, - which isn't what we want. - As an alternative, we can give Subscription!save its own class, - so that it can have it's own preparable method. -

- -
-
mailreader-support.xml Subscription!save element
-
<action name="Subscription!save" class="mailreader2.SubscriptionSave">
-        <result name="input">/pages/Subscription.jsp</result>
-        <result type="redirect-action">Registration!input</result>
-        <interceptor-ref name="user-submit" />
-    </action>
-
-
SubscriptionSave
-
public final class SubscriptionSave extends Subscription {
-
-  public void prepare() {
-    super.prepare();
-    // checkbox workaround
-    getSubscription().setAutoConnect(false);
-  }
-
-  public String execute() throws Exception {
-    return save();
-  }
-}
-
-

If we press the SAVE button, the form will be submitted to the Subscription!save action. - Since the action has it's own class, - it can also have its own set of validators. + Since the save method needs some additional validation, + we can add a validation file.


-
SubscriptionSave-validation.xml
+
Subscription-Subscription!save-validation.xml
<!DOCTYPE validators PUBLIC "-//OpenSymphony Group//XWork Validator 1.0.2//EN"
     "http://www.opensymphony.com/xwork/xwork-validator-1.0.2.dtd">
 <validators>
@@ -2369,17 +2312,9 @@ public Subscription findSubscription(String host) {
 

- If validation succeeds, the execute method of SubscriptionSave will fire. - Just to keep all the code together, - all the execute method does is call save on the parent Subscription class. + If validation succeeds, the save method of Subscription will fire.

-
-
SubscriptionSave
- -
public String execute() throws Exception {
-    return save();
-}

Subscription
@@ -2472,6 +2407,59 @@ public Subscription findSubscription(String host) { that would not be easy for us change.

+

Subscription Submit

+ +

+ When we pressed the SAVE button, there was one step that we overlooked. + The Mailreader application uses a "double submit" guard to keep people + from clicking the SAVE button multiple times and submitting the form again. +

+ +

+ To add the double-submit guard, we can change the actions default processing + stack to user-submit. + But, we don't want to just copy and paste the other action settings from + the main Subscription action. + What we can do is put the subscription actions in their own package, + so that they can share result types. +

+ +
+
mailreader-support.xml
+

+</package>
+
+<package name="subscription" namespace="/" extends="mailreader-support">
+
+    <global-results>
+        <result name="input">/Subscription.jsp</result>
+        <result type="redirect-action">Registration!input</result>
+    </global-results>
+
+    <action name="Subscription!save" method="save" class="mailreader2.Subscription">
+        <interceptor-ref name="user-submit" />
+    </action>
+
+    <action name="Subscription!*" method="{1}" class="mailreader2.Subscription" />
+
+</package>
+
+<package name="wildcard" namespace="/" extends="mailreader-support">
+
+    <action name="*" class="mailreader2.MailreaderSupport">
+        <result>/{1}.jsp</result>
+    </action>
+
+</package>
+}
+
+ +

+ Aftering a successful save, + the Subscription Action will return "success", + and the framework will redirect us back to Registration input. +

+

Summary

At this point, we've booted the application, logged on,