I'm going to chime in on this for a moment.

I've always thought the best strategy for handling double submits (assuming you 
can detect them) is to essentially ignore them.  If possible, if you detect a 
double submit, then bypass the processing logic and either ignore the request, 
or forward to the page that would have resulted from the original submit (I'm 
not sure which sub-strategy is better).

Will this functionality you're adding allow this detection and processing?

> -----Original Message-----
> From: [EMAIL PROTECTED] [mailto:[EMAIL PROTECTED] 
> 
> Author: rich
> Date: Mon Jan  3 13:42:54 2005
> New Revision: 124028
> 
> URL: http://svn.apache.org/viewcvs?view=rev&rev=124028
> Log:
> First cut at annotation/tag support for double-submit 
> prevention.  Currently, the feature is simply this: 
> 
> ��� @Jpf.Action(preventDoubleSubmit=true,...) 
> ������������� -or- 
> ��� @Jpf.SimpleAction(preventDoubleSubmit=true,...) 
> 
> If you use netui:form, netui:button (with an 'action'), 
> netui:anchor, or netui:imageAnchor in conjunction with a 
> 'preventDoubleSubmit=true' action, you will get a 
> DoubleSubmitException if you click two or more times on the 
> same link/button.
> 
> DRT: netui (WinXP)
> BB: self (linux)
> 
> 
> Added:
>    
> incubator/beehive/trunk/netui/src/pageflow/org/apache/beehive/
> netui/pageflow/DoubleSubmitException.java
>       - copied, changed from r124020, 
> incubator/beehive/trunk/netui/src/pageflow/org/apache/beehive/
> netui/pageflow/DoubleFormPostException.java
>    
> incubator/beehive/trunk/netui/test/webapps/drt/coreWeb/miniTes
> ts/preventDoubleSubmit/
>    
> incubator/beehive/trunk/netui/test/webapps/drt/coreWeb/miniTes
> ts/preventDoubleSubmit/Controller.jpf   (contents, props changed)
>    
> incubator/beehive/trunk/netui/test/webapps/drt/coreWeb/miniTes
> ts/preventDoubleSubmit/caughtit.jsp   (contents, props changed)
>    
> incubator/beehive/trunk/netui/test/webapps/drt/coreWeb/miniTes
> ts/preventDoubleSubmit/index.jsp   (contents, props changed)
>    
> incubator/beehive/trunk/netui/test/webapps/drt/coreWeb/miniTes
> ts/preventDoubleSubmit/submitted.jsp   (contents, props changed)
> Removed:
>    
> incubator/beehive/trunk/netui/src/pageflow/org/apache/beehive/
> netui/pageflow/DoubleFormPostException.java
> Modified:
>    
> incubator/beehive/trunk/netui/src/compiler/org/apache/beehive/
> netui/compiler/JpfLanguageConstants.java
>    
> incubator/beehive/trunk/netui/src/compiler/org/apache/beehive/
> netui/compiler/genmodel/GenActionModel.java
>    
> incubator/beehive/trunk/netui/src/compiler/org/apache/beehive/
> netui/compiler/grammar/ActionGrammar.java
>    
> incubator/beehive/trunk/netui/src/compiler/org/apache/beehive/
> netui/compiler/grammar/SimpleActionGrammar.java
>    
> incubator/beehive/trunk/netui/src/compiler/org/apache/beehive/
> netui/compiler/model/ActionModel.java
>    
> incubator/beehive/trunk/netui/src/pageflow/org/apache/beehive/
> netui/pageflow/PageFlowRequestProcessor.java
>    
> incubator/beehive/trunk/netui/src/pageflow/org/apache/beehive/
> netui/pageflow/annotations/Jpf.java
>    
> incubator/beehive/trunk/netui/src/pageflow/org/apache/beehive/
> netui/pageflow/config/PageFlowActionMapping.java
>    
> incubator/beehive/trunk/netui/src/tags-html/org/apache/beehive
> /netui/tags/html/AnchorBase.java
>    
> incubator/beehive/trunk/netui/src/tags-html/org/apache/beehive
> /netui/tags/html/Button.java
>    
> incubator/beehive/trunk/netui/src/tags-html/org/apache/beehive
> /netui/tags/html/Form.java
>    
> incubator/beehive/trunk/netui/src/tags-html/org/apache/beehive
> /netui/tags/internal/PageFlowTagUtils.java
>    
> incubator/beehive/trunk/netui/src/util/org/apache/beehive/netu
> i/util/netui.properties
>    
> incubator/beehive/trunk/netui/test/webapps/drt/coreWeb/WEB-INF
> /tiles-defs.xml
> 
> Modified: 
> incubator/beehive/trunk/netui/src/compiler/org/apache/beehive/
> netui/compiler/JpfLanguageConstants.java
> Url: 
> http://svn.apache.org/viewcvs/incubator/beehive/trunk/netui/sr
> c/compiler/org/apache/beehive/netui/compiler/JpfLanguageConsta
> nts.java?view=diff&rev=124028&p1=incubator/beehive/trunk/netui
> /src/compiler/org/apache/beehive/netui/compiler/JpfLanguageCon
> stants.java&r1=124027&p2=incubator/beehive/trunk/netui/src/com
> piler/org/apache/beehive/netui/compiler/JpfLanguageConstants.j
> ava&r2=124028
> ==============================================================
> ================
> --- 
> incubator/beehive/trunk/netui/src/compiler/org/apache/beehive/
> netui/compiler/JpfLanguageConstants.java      (original)
> +++ 
> incubator/beehive/trunk/netui/src/compiler/org/apache/beehive/
> netui/compiler/JpfLanguageConstants.java      Mon Jan  3 13:42:54 2005
> @@ -161,6 +161,7 @@
>      public static final String RAISE_ACTIONS_ATTR = "raiseActions";
>      public static final String MULTIPART_HANDLER_ATTR = 
> "multipartHandler";
>      public static final String SHARED_FLOW_REFS_ATTR = 
> "sharedFlowRefs";
> +    public static final String PREVENT_DOUBLE_SUBMIT_ATTR = 
> + "preventDoubleSubmit";
>      
>      public static final String MIN_INT_ATTR = "minInt";
>      public static final String MAX_INT_ATTR = "maxInt";
> 
> Modified: 
> incubator/beehive/trunk/netui/src/compiler/org/apache/beehive/
> netui/compiler/genmodel/GenActionModel.java
> Url: 
> http://svn.apache.org/viewcvs/incubator/beehive/trunk/netui/sr
> c/compiler/org/apache/beehive/netui/compiler/genmodel/GenActio
> nModel.java?view=diff&rev=124028&p1=incubator/beehive/trunk/ne
> tui/src/compiler/org/apache/beehive/netui/compiler/genmodel/Ge
> nActionModel.java&r1=124027&p2=incubator/beehive/trunk/netui/s
> rc/compiler/org/apache/beehive/netui/compiler/genmodel/GenActi
> onModel.java&r2=124028
> ==============================================================
> ================
> --- 
> incubator/beehive/trunk/netui/src/compiler/org/apache/beehive/
> netui/compiler/genmodel/GenActionModel.java   (original)
> +++ 
> incubator/beehive/trunk/netui/src/compiler/org/apache/beehive/
> netui/compiler/genmodel/GenActionModel.java   Mon Jan  3 13:42:54 2005
> @@ -72,6 +72,12 @@
>          setLoginRequired( loginRequired );
>          
>          //
> +        // prevent-double-submit
> +        //
> +        Boolean preventDoubleSubmit = 
> CompilerUtils.getBoolean( annotation, 
> PREVENT_DOUBLE_SUBMIT_ATTR, false );
> +        setPreventDoubleSubmit( preventDoubleSubmit );
> +        
> +        //
>          // readOnly
>          //
>          Boolean readOnly = CompilerUtils.getBoolean( 
> annotation, READONLY_ATTR, true );
> 
> Modified: 
> incubator/beehive/trunk/netui/src/compiler/org/apache/beehive/
> netui/compiler/grammar/ActionGrammar.java
> Url: 
> http://svn.apache.org/viewcvs/incubator/beehive/trunk/netui/sr
> c/compiler/org/apache/beehive/netui/compiler/grammar/ActionGra
> mmar.java?view=diff&rev=124028&p1=incubator/beehive/trunk/netu
> i/src/compiler/org/apache/beehive/netui/compiler/grammar/Actio
> nGrammar.java&r1=124027&p2=incubator/beehive/trunk/netui/src/c
> ompiler/org/apache/beehive/netui/compiler/grammar/ActionGramma
> r.java&r2=124028
> ==============================================================
> ================
> --- 
> incubator/beehive/trunk/netui/src/compiler/org/apache/beehive/
> netui/compiler/grammar/ActionGrammar.java     (original)
> +++ 
> incubator/beehive/trunk/netui/src/compiler/org/apache/beehive/
> netui/compiler/grammar/ActionGrammar.java     Mon Jan  3 13:42:54 2005
> @@ -17,7 +17,6 @@
>   */
>  package org.apache.beehive.netui.compiler.grammar;
>  
> -import org.apache.beehive.netui.compiler.AnnotationGrammar;
>  import org.apache.beehive.netui.compiler.RuntimeVersionChecker;
>  import org.apache.beehive.netui.compiler.AnnotationMemberType;
>  import org.apache.beehive.netui.compiler.FlowControllerInfo;
> @@ -40,6 +39,7 @@
>          addMemberType( READONLY_ATTR, new 
> AnnotationMemberType( VERSION_8_SP2_STRING, this ) );
>          addMemberType( USE_FORM_BEAN_ATTR,
>                         new WritableFieldType( 
> OBJECT_CLASS_NAME, USE_FORM_BEAN_ATTR, VERSION_8_SP2_STRING, this ) );
> +        addMemberType( PREVENT_DOUBLE_SUBMIT_ATTR, new 
> + AnnotationMemberType( null, this ) );
>          
>          addMemberArrayGrammar( FORWARDS_ATTR, new 
> ForwardGrammar( env, diags, null, rvc, fcInfo ) );
>          addMemberArrayGrammar( CATCHES_ATTR, new 
> CatchGrammar( env, diags, null, rvc, ACTION_TAG_NAME, fcInfo ) );
> 
> Modified: 
> incubator/beehive/trunk/netui/src/compiler/org/apache/beehive/
> netui/compiler/grammar/SimpleActionGrammar.java
> Url: 
> http://svn.apache.org/viewcvs/incubator/beehive/trunk/netui/sr
> c/compiler/org/apache/beehive/netui/compiler/grammar/SimpleAct
> ionGrammar.java?view=diff&rev=124028&p1=incubator/beehive/trun
> k/netui/src/compiler/org/apache/beehive/netui/compiler/grammar
> /SimpleActionGrammar.java&r1=124027&p2=incubator/beehive/trunk
> /netui/src/compiler/org/apache/beehive/netui/compiler/grammar/
> SimpleActionGrammar.java&r2=124028
> ==============================================================
> ================
> --- 
> incubator/beehive/trunk/netui/src/compiler/org/apache/beehive/
> netui/compiler/grammar/SimpleActionGrammar.java       (original)
> +++ 
> incubator/beehive/trunk/netui/src/compiler/org/apache/beehive/
> netui/compiler/grammar/SimpleActionGrammar.java       Mon Jan 
>  3 13:42:54 2005
> @@ -58,6 +58,7 @@
>          addMemberType( TILES_DEFINITION_ATTR, new 
> AnnotationMemberType( null, this ) );
>          addMemberType( REDIRECT_ATTR, new 
> AnnotationMemberType( null , this ) );
>          addMemberType( EXTERNAL_REDIRECT_ATTR, new 
> AbsolutePathType( null , this ) );
> +        addMemberType( PREVENT_DOUBLE_SUBMIT_ATTR, new 
> + AnnotationMemberType( null, this ) );
>          
>          addMemberArrayGrammar( CONDITIONAL_FORWARDS_ATTR,
>                                 new 
> SimpleActionForwardGrammar( env, diags, null, rvc, fcInfo ) );
> 
> Modified: 
> incubator/beehive/trunk/netui/src/compiler/org/apache/beehive/
> netui/compiler/model/ActionModel.java
> Url: 
> http://svn.apache.org/viewcvs/incubator/beehive/trunk/netui/sr
> c/compiler/org/apache/beehive/netui/compiler/model/ActionModel
> .java?view=diff&rev=124028&p1=incubator/beehive/trunk/netui/sr
> c/compiler/org/apache/beehive/netui/compiler/model/ActionModel
> .java&r1=124027&p2=incubator/beehive/trunk/netui/src/compiler/
> org/apache/beehive/netui/compiler/model/ActionModel.java&r2=124028
> ==============================================================
> ================
> --- 
> incubator/beehive/trunk/netui/src/compiler/org/apache/beehive/
> netui/compiler/model/ActionModel.java (original)
> +++ 
> incubator/beehive/trunk/netui/src/compiler/org/apache/beehive/
> netui/compiler/model/ActionModel.java Mon Jan  3 13:42:54 2005
> @@ -67,6 +67,7 @@
>      private boolean _isOverloaded;
>      private boolean _readonly;
>      private boolean _isSimpleAction = false;
> +    private boolean _preventDoubleSubmit = false;
>      private String _formMember;     // pageflow-scoped form
>      private String _formClass;      // applicable for 
> non-ActionForm-derived types
>      private Map< String, String > _conditionalForwards;
> @@ -115,6 +116,7 @@
>          _formClass = src._formClass;
>          _roles = src._roles;
>          _loginRequired = src._loginRequired;
> +        _preventDoubleSubmit = src._preventDoubleSubmit;
>          _isSimpleAction = src._isSimpleAction;
>          _isOverloaded = src._isOverloaded;
>          _readonly = src._readonly;
> @@ -222,6 +224,7 @@
>          if ( _formMember != null ) addSetProperty( xb, 
> "formMember", _formMember );
>          if ( _formClass != null ) addSetProperty( xb, 
> "formClass", _formClass );
>          if ( _loginRequired ) addSetProperty( xb, 
> "loginRequired", _loginRequired );
> +        if ( _preventDoubleSubmit ) addSetProperty( xb, 
> + "preventDoubleSubmit", _preventDoubleSubmit );
>          if ( _isOverloaded ) addSetProperty( xb, 
> "overloaded", _isOverloaded );
>          if ( _readonly ) addSetProperty( xb, "readonly", _readonly );
>          if ( _isSimpleAction ) addSetProperty( xb, 
> "simpleAction", _isSimpleAction ); @@ -464,14 +467,14 @@
>          _roles = roles;
>      }
>  
> -    public boolean isLoginRequired()
> -    {
> -        return _loginRequired;
> -    }
> -
>      public void setLoginRequired( boolean loginRequired )
>      {
>          _loginRequired = loginRequired;
> +    }
> +    
> +    public void setPreventDoubleSubmit( boolean preventDoubleSubmit )
> +    {
> +        _preventDoubleSubmit = preventDoubleSubmit;
>      }
>  
>      public boolean isSimpleAction()
> 
> Deleted: 
> /incubator/beehive/trunk/netui/src/pageflow/org/apache/beehive
> /netui/pageflow/DoubleFormPostException.java
> Url: 
> http://svn.apache.org/viewcvs/incubator/beehive/trunk/netui/sr
> c/pageflow/org/apache/beehive/netui/pageflow/DoubleFormPostExc
> eption.java?view=auto&rev=124027
> ==============================================================
> ================
> 
> Copied: 
> incubator/beehive/trunk/netui/src/pageflow/org/apache/beehive/
> netui/pageflow/DoubleSubmitException.java (from r124020, 
> incubator/beehive/trunk/netui/src/pageflow/org/apache/beehive/
> netui/pageflow/DoubleFormPostException.java)
> Url: 
> http://svn.apache.org/viewcvs/incubator/beehive/trunk/netui/sr
> c/pageflow/org/apache/beehive/netui/pageflow/DoubleSubmitExcep
> tion.java?view=diff&rev=124028&p1=incubator/beehive/trunk/netu
> i/src/pageflow/org/apache/beehive/netui/pageflow/DoubleFormPos
> tException.java&r1=124020&p2=incubator/beehive/trunk/netui/src
> /pageflow/org/apache/beehive/netui/pageflow/DoubleSubmitExcept
> ion.java&r2=124028
> ==============================================================
> ================
> --- 
> incubator/beehive/trunk/netui/src/pageflow/org/apache/beehive/
> netui/pageflow/DoubleFormPostException.java   (original)
> +++ 
> incubator/beehive/trunk/netui/src/pageflow/org/apache/beehive/
> netui/pageflow/DoubleSubmitException.java     Mon Jan  3 13:42:54 2005
> @@ -20,11 +20,11 @@
>  import javax.servlet.http.HttpServletResponse;
>  import java.io.IOException;
>  
> -public class DoubleFormPostException
> +public class DoubleSubmitException
>          extends PageFlowException
>          implements ResponseErrorCodeSender
>  {
> -    DoubleFormPostException( String actionName, FlowController fc )
> +    DoubleSubmitException( String actionName, FlowController fc )
>      {
>          super( actionName, fc );
>      }
> @@ -36,7 +36,7 @@
>  
>      protected String[] getMessageParts()
>      {
> -        return new String[]{ "A double-post occurred for 
> action ", " in page flow ", "." };
> +        return new String[]{ "A double-submit occurred for 
> action ", " 
> + in page flow ", "." };
>      }
>      
>      public void sendResponseErrorCode( HttpServletResponse 
> response ) throws IOException
> 
> Modified: 
> incubator/beehive/trunk/netui/src/pageflow/org/apache/beehive/
> netui/pageflow/PageFlowRequestProcessor.java
> Url: 
> http://svn.apache.org/viewcvs/incubator/beehive/trunk/netui/sr
> c/pageflow/org/apache/beehive/netui/pageflow/PageFlowRequestPr
> ocessor.java?view=diff&rev=124028&p1=incubator/beehive/trunk/n
> etui/src/pageflow/org/apache/beehive/netui/pageflow/PageFlowRe
> questProcessor.java&r1=124027&p2=incubator/beehive/trunk/netui
> /src/pageflow/org/apache/beehive/netui/pageflow/PageFlowReques
> tProcessor.java&r2=124028
> ==============================================================
> ================
> --- 
> incubator/beehive/trunk/netui/src/pageflow/org/apache/beehive/
> netui/pageflow/PageFlowRequestProcessor.java  (original)
> +++ 
> incubator/beehive/trunk/netui/src/pageflow/org/apache/beehive/
> netui/pageflow/PageFlowRequestProcessor.java  Mon Jan  3 13:42:54 2005
> @@ -930,16 +930,13 @@
>                                              ActionMapping 
> mapping, String actionPath )
>          throws IOException
>      {
> -        //
> -        // TODO: We haven't yet hooked up the support for 
> marking an action as preventDoublePost=true.
> -        //
> -        if ( false )
> +        if ( mapping instanceof PageFlowActionMapping && ( ( 
> + PageFlowActionMapping ) mapping ).isPreventDoubleSubmit() )
>          {
>              if ( ! 
> TokenProcessor.getInstance().isTokenValid( request, true ) )
>              {
>                  FlowController currentFC = 
> RequestValues.getCurrentFlowController( request );
>                  String actionName = 
> InternalUtils.getActionName( mapping );
> -                DoubleFormPostException ex = new 
> DoubleFormPostException( actionName, currentFC );
> +                DoubleSubmitException ex = new 
> DoubleSubmitException( 
> + actionName, currentFC );
>                  
>                  if ( currentFC != null )
>                  {
> 
> Modified: 
> incubator/beehive/trunk/netui/src/pageflow/org/apache/beehive/
> netui/pageflow/annotations/Jpf.java
> Url: 
> http://svn.apache.org/viewcvs/incubator/beehive/trunk/netui/sr
> c/pageflow/org/apache/beehive/netui/pageflow/annotations/Jpf.j
> ava?view=diff&rev=124028&p1=incubator/beehive/trunk/netui/src/
> pageflow/org/apache/beehive/netui/pageflow/annotations/Jpf.jav
> a&r1=124027&p2=incubator/beehive/trunk/netui/src/pageflow/org/
> apache/beehive/netui/pageflow/annotations/Jpf.java&r2=124028
> ==============================================================
> ================
> --- 
> incubator/beehive/trunk/netui/src/pageflow/org/apache/beehive/
> netui/pageflow/annotations/Jpf.java   (original)
> +++ 
> incubator/beehive/trunk/netui/src/pageflow/org/apache/beehive/
> netui/pageflow/annotations/Jpf.java   Mon Jan  3 13:42:54 2005
> @@ -186,7 +186,7 @@
>       * was jpf:action
>       */
>      @Target( METHOD )
> -            @Retention( RUNTIME )
> +    @Retention( RUNTIME )
>      public @interface Action
>      {
>          /**
> @@ -228,6 +228,12 @@
>           * forward used when validation fails
>           */
>          Forward validationErrorForward() default 
> @Jpf.Forward( name="" );
> +        
> +        /**
> +         * Prevent multiple submits to this action.  If 
> multiple submits occur, a
> +         * [EMAIL PROTECTED] 
> org.apache.beehive.netui.pageflow.DoubleSubmitException} is thrown.
> +         */ 
> +        boolean preventDoubleSubmit() default false;
>      }
>      
>      @Target( ANNOTATION_TYPE )
> @@ -314,6 +320,12 @@
>          String outputFormBean() default "";
>          boolean redirect() default false; // optional
>          boolean externalRedirect() default false; // optional
> +        
> +        /**
> +         * Prevent multiple submits to this action.  If 
> multiple submits occur, a
> +         * [EMAIL PROTECTED] 
> org.apache.beehive.netui.pageflow.DoubleSubmitException} is thrown.
> +         */ 
> +        boolean preventDoubleSubmit() default false;
>      }
>  
>      /**
> 
> Modified: 
> incubator/beehive/trunk/netui/src/pageflow/org/apache/beehive/
> netui/pageflow/config/PageFlowActionMapping.java
> Url: 
> http://svn.apache.org/viewcvs/incubator/beehive/trunk/netui/sr
> c/pageflow/org/apache/beehive/netui/pageflow/config/PageFlowAc
> tionMapping.java?view=diff&rev=124028&p1=incubator/beehive/tru
> nk/netui/src/pageflow/org/apache/beehive/netui/pageflow/config
> /PageFlowActionMapping.java&r1=124027&p2=incubator/beehive/tru
> nk/netui/src/pageflow/org/apache/beehive/netui/pageflow/config
> /PageFlowActionMapping.java&r2=124028
> ==============================================================
> ================
> --- 
> incubator/beehive/trunk/netui/src/pageflow/org/apache/beehive/
> netui/pageflow/config/PageFlowActionMapping.java      (original)
> +++ 
> incubator/beehive/trunk/netui/src/pageflow/org/apache/beehive/
> netui/pageflow/config/PageFlowActionMapping.java      Mon Jan 
>  3 13:42:54 2005
> @@ -31,6 +31,7 @@
>  {
>      private String _unqualifiedActionPath;
>      private boolean _loginRequired = false;
> +    private boolean _preventDoubleSubmit = false;
>      private boolean _simpleAction = false;
>      private boolean _isOverloaded = false;
>      private String _formMember;
> @@ -70,6 +71,16 @@
>      public void setLoginRequired( boolean loginRequired )
>      {
>          _loginRequired = loginRequired;
> +    }
> +
> +    public boolean isPreventDoubleSubmit()
> +    {
> +        return _preventDoubleSubmit;
> +    }
> +
> +    public void setPreventDoubleSubmit( boolean preventDoubleSubmit )
> +    {
> +        _preventDoubleSubmit = preventDoubleSubmit;
>      }
>  
>      public boolean isSimpleAction()
> 
> Modified: 
> incubator/beehive/trunk/netui/src/tags-html/org/apache/beehive
> /netui/tags/html/AnchorBase.java
> Url: 
> http://svn.apache.org/viewcvs/incubator/beehive/trunk/netui/sr
> c/tags-html/org/apache/beehive/netui/tags/html/AnchorBase.java
> ?view=diff&rev=124028&p1=incubator/beehive/trunk/netui/src/tag
> s-html/org/apache/beehive/netui/tags/html/AnchorBase.java&r1=1
> 24027&p2=incubator/beehive/trunk/netui/src/tags-html/org/apach
> e/beehive/netui/tags/html/AnchorBase.java&r2=124028
> ==============================================================
> ================
> --- 
> incubator/beehive/trunk/netui/src/tags-html/org/apache/beehive
> /netui/tags/html/AnchorBase.java      (original)
> +++ 
> incubator/beehive/trunk/netui/src/tags-html/org/apache/beehive
> /netui/tags/html/AnchorBase.java      Mon Jan  3 13:42:54 2005
> @@ -10,6 +10,7 @@
>  import org.apache.beehive.netui.util.Bundle;
>  import org.apache.beehive.netui.util.ParamHelper;
>  import org.apache.beehive.netui.util.logging.Logger;
> +import org.apache.struts.taglib.html.Constants;
>  
>  import javax.servlet.ServletContext;
>  import javax.servlet.ServletRequest;
> @@ -327,18 +328,33 @@
>              return createPageAnchor(request, trb);
>          }
>  
> -        // report that action is not an action
> -        if ((_action != null) && 
> (!PageFlowTagUtils.isAction(request, _action))) {
> -            String s = null;
> -            if (_action.equals("")) {
> -                s = Bundle.getString("Tags_NullBadAction", null);
> +        if (_action != null) {
> +            // report that action is not an action
> +            if (!PageFlowTagUtils.isAction(request, _action)) {
> +                String s = null;
> +                if (_action.equals("")) {
> +                    s = Bundle.getString("Tags_NullBadAction", null);
> +                }
> +                else {
> +                    s = Bundle.getString("Tags_BadAction", _action);
> +                }
> +                registerTagError(s, null);
>              }
>              else {
> -                s = Bundle.getString("Tags_BadAction", _action);
> +                //
> +                // If the action we're submitting to is 
> checking for double-submits, save a token in the session.
> +                // This will be written out as a param 
> (below), and will be checked in PageFlowRequestProcessor.
> +                //
> +                String token = 
> PageFlowTagUtils.getToken(request, _action);
> +                if (token != null) {
> +                    if (_params == null) {
> +                        _params = new HashMap();
> +                    }
> +                    _params.put(Constants.TOKEN_KEY, token);
> +                }
>              }
> -            registerTagError(s, null);
>          }
> -
> +        
>          // we assume that tagId will over have override id if both
>          // are defined.
>          if (tagId != null) {
> 
> Modified: 
> incubator/beehive/trunk/netui/src/tags-html/org/apache/beehive
> /netui/tags/html/Button.java
> Url: 
> http://svn.apache.org/viewcvs/incubator/beehive/trunk/netui/sr
> c/tags-html/org/apache/beehive/netui/tags/html/Button.java?vie
> w=diff&rev=124028&p1=incubator/beehive/trunk/netui/src/tags-ht
ml/org/apache/beehive/netui/tags/html/Button.jav> 
a&r1=124027&p2=incubator/beehive/trunk/netui/src/tags-html/org
/apache/beehive/netui/tags/html/Button.java&r2=> 124028
> ==============================================================
> ================
> --- 
> incubator/beehive/trunk/netui/src/tags-html/org/apache/beehive
> /netui/tags/html/Button.java  (original)
> +++ 
> incubator/beehive/trunk/netui/src/tags-html/org/apache/beehive
> /netui/tags/html/Button.java  Mon Jan  3 13:42:54 2005
> @@ -28,6 +28,7 @@
>  import org.apache.beehive.netui.tags.rendering.WriteRenderAppender;
>  import org.apache.beehive.netui.util.Bundle;
>  import org.apache.beehive.netui.util.ParamHelper;
> +import org.apache.struts.taglib.html.Constants;
>  
>  import javax.servlet.http.HttpServletRequest;
>  import javax.servlet.http.HttpServletResponse;
> @@ -233,6 +234,18 @@
>          if (_action != null) {
>              boolean isAction = 
> PageFlowTagUtils.isAction(request, _action);
>              if (isAction) {
> +                //
> +                // If the action we're submitting to is 
> checking for double-submits, save a token in the session.
> +                // This will be written out as a param 
> (below), and will be checked in PageFlowRequestProcessor.
> +                //
> +                String token = 
> PageFlowTagUtils.getToken(request, _action);
> +                if (token != null) {
> +                    if (_params == null) {
> +                        _params = new HashMap();
> +                    }
> +                    _params.put(Constants.TOKEN_KEY, token);
> +                }
> +                
>                  String overrideAction = ACTION_OVERRIDE + _action;
>                  overrideAction = 
> HtmlUtils.addParams(overrideAction, _params, 
> response.getCharacterEncoding());
>                  String buttonOutput = 
> URLRewriterService.rewriteName(pageContext.getServletContext(),
> 
> Modified: 
> incubator/beehive/trunk/netui/src/tags-html/org/apache/beehive
> /netui/tags/html/Form.java
> Url: 
> http://svn.apache.org/viewcvs/incubator/beehive/trunk/netui/sr
> c/tags-html/org/apache/beehive/netui/tags/html/Form.java?view=
> diff&rev=124028&p1=incubator/beehive/trunk/netui/src/tags-html
/org/apache/beehive/netui/tags/html/Form.java&r1> 
=124027&p2=incubator/beehive/trunk/netui/src/tags-html/org/apa
> che/beehive/netui/tags/html/Form.java&r2=124028
> ==============================================================
> ================
> --- 
> incubator/beehive/trunk/netui/src/tags-html/org/apache/beehive
> /netui/tags/html/Form.java    (original)
> +++ 
> incubator/beehive/trunk/netui/src/tags-html/org/apache/beehive
> /netui/tags/html/Form.java    Mon Jan  3 13:42:54 2005
> @@ -20,6 +20,7 @@
>  import org.apache.beehive.netui.core.urls.MutableURI;
>  import org.apache.beehive.netui.core.urls.URLRewriterService;
>  import org.apache.beehive.netui.pageflow.*;
> +import 
> org.apache.beehive.netui.pageflow.config.PageFlowActionMapping;
>  import org.apache.beehive.netui.pageflow.internal.ContextCache;
>  import org.apache.beehive.netui.pageflow.internal.InternalUtils;
>  import org.apache.beehive.netui.pageflow.internal.InternalConstants;
> @@ -30,6 +31,7 @@
>  import org.apache.beehive.netui.util.ParamHelper;
>  import org.apache.beehive.netui.util.logging.Logger;
>  import org.apache.struts.Globals;
> +import org.apache.struts.util.TokenProcessor;
>  import org.apache.struts.action.ActionForm;
>  import org.apache.struts.action.ActionMapping;
>  import org.apache.struts.action.ActionServlet;
> @@ -723,11 +725,18 @@
>          TagRenderingBase br = 
> TagRenderingBase.Factory.getRendering(TagRenderingBase.FORM_TA
> G, request);
>          br.doStartTag(writer, _state);
>  
> +        //
> +        // If the action we're submitting to is checking for 
> double-submits, save a token in the session.
> +        // This will be written out as a hidden param 
> (below), and will be checked in PageFlowRequestProcessor.
> +        //
> +        String token = PageFlowTagUtils.getToken(request, _mapping);
> +        
>          // Add a transaction token (if present in our session)
>          HttpSession session = pageContext.getSession();
>          if (session != null) {
> -            String token =
> -                    (String) 
> session.getAttribute(Globals.TRANSACTION_TOKEN_KEY);
> +            if (token != null) {
> +                token = (String) 
> session.getAttribute(Globals.TRANSACTION_TOKEN_KEY);
> +            }
>              if (token != null) {
>                  writeHiddenParam(Constants.TOKEN_KEY, token, 
> writer, request, true);
>              }
> 
> Modified: 
> incubator/beehive/trunk/netui/src/tags-html/org/apache/beehive
> /netui/tags/internal/PageFlowTagUtils.java
> Url: 
> http://svn.apache.org/viewcvs/incubator/beehive/trunk/netui/sr
> c/tags-html/org/apache/beehive/netui/tags/internal/PageFlowTag
> Utils.java?view=diff&rev=124028&p1=incubator/beehive/trunk/net
> ui/src/tags-html/org/apache/beehive/netui/tags/internal/PageFl
> owTagUtils.java&r1=124027&p2=incubator/beehive/trunk/netui/src
> /tags-html/org/apache/beehive/netui/tags/internal/PageFlowTagU
> tils.java&r2=124028
> ==============================================================
> ================
> --- 
> incubator/beehive/trunk/netui/src/tags-html/org/apache/beehive
> /netui/tags/internal/PageFlowTagUtils.java    (original)
> +++ 
> incubator/beehive/trunk/netui/src/tags-html/org/apache/beehive
> /netui/tags/internal/PageFlowTagUtils.java    Mon Jan  3 13:42:54 2005
> @@ -26,10 +26,13 @@
>  import org.apache.beehive.netui.pageflow.PageFlowUtils;
>  import org.apache.beehive.netui.pageflow.SecurityProtocol;
>  import org.apache.beehive.netui.pageflow.SharedFlowController;
> +import 
> org.apache.beehive.netui.pageflow.config.PageFlowActionMapping;
>  import org.apache.beehive.netui.pageflow.internal.InternalUtils;
>  import org.apache.beehive.netui.pageflow.internal.InternalConstants;
>  import org.apache.struts.action.ActionMapping;
>  import org.apache.struts.config.ActionConfig;
> +import org.apache.struts.util.TokenProcessor;
> +import org.apache.struts.Globals;
>  
>  import java.net.URISyntaxException;
>  import java.util.Map;
> @@ -38,6 +41,7 @@
>  import javax.servlet.ServletRequest;
>  import javax.servlet.http.HttpServletResponse;
>  import javax.servlet.http.HttpServletRequest;
> +import javax.servlet.http.HttpSession;
>  
>  /**
>   * This is a utility class for the beehive tags with 
> routines for helping with URL rewriting. @@ -178,6 +182,44 @@
>          return true;
>      }
>  
> +    /**
> +     * Get or generate a token used to prevent double 
> submits to an action.  The token is stored in the session,
> +     * and checked (and removed) when processing an action 
> with the <code>preventDoubleSubmit</code> attribute
> +     * set to <code>true</code>.
> +     */ 
> +    public static String getToken( HttpServletRequest 
> request, String action )
> +    {
> +        FlowController flowController = 
> + InternalUtils.getCurrentPageFlow( request, false );
> +        
> +        if ( flowController != null )
> +        {
> +            MappingAndController mac = getActionMapping( 
> request, flowController, action );
> +            if ( mac != null ) return getToken( request, 
> mac.mapping );
> +        }
> +        
> +        return null;
> +    }
> +    
> +    /**
> +     * Get or generate a token used to prevent double 
> submits to an action.  The token is stored in the session,
> +     * and checked (and removed) when processing an action 
> with the <code>preventDoubleSubmit</code> attribute
> +     * set to <code>true</code>.
> +     */ 
> +    public static String getToken( HttpServletRequest 
> request, ActionMapping mapping )
> +    {
> +        if ( mapping instanceof PageFlowActionMapping && ( ( 
> PageFlowActionMapping ) mapping ).isPreventDoubleSubmit() )
> +        {
> +            HttpSession session = request.getSession();
> +            String token = ( String ) session.getAttribute( 
> Globals.TRANSACTION_TOKEN_KEY );
> +            if ( token != null ) return token;
> +            token = 
> TokenProcessor.getInstance().generateToken( request );
> +            request.getSession().setAttribute( 
> Globals.TRANSACTION_TOKEN_KEY, token );
> +            return token;
> +        }
> +        
> +        return null;
> +    }
> +    
>      public static class MappingAndController
>      {
>          public ActionMapping mapping;
> @@ -198,12 +240,32 @@
>              
>              if ( dot == -1 )
>              {
> +                //
> +                // It's an action in the current page flow, 
> or in the (deprecated) Global.app.
> +                //
>                  if ( action.charAt( 0 ) != '/' ) action = 
> '/' + action;
>                  mapping = 
> flowController.getModuleConfig().findActionConfig( action );
>                  fc = flowController;
> +                
> +                //
> +                // If we don't find it in the current page 
> flow, look in Global.app.
> +                //
> +                if ( mapping == null )
> +                {
> +                    FlowController globalApp =
> +                            PageFlowUtils.getSharedFlow( 
> InternalConstants.GLOBALAPP_CLASSNAME, request );
> +                    if ( globalApp != null )
> +                    {
> +                        mapping = 
> globalApp.getModuleConfig().findActionConfig( action );
> +                        fc = globalApp;
> +                    }
> +                }
>              }
>              else if ( dot < action.length() - 1 )
>              {
> +                //
> +                // It's an action in a shared flow.
> +                //
>                  String sharedFlowName = action.substring( 0, dot );
>                  if ( sharedFlowName.length() > 0 && 
> sharedFlowName.charAt( 0 ) == '/' )
>                  {
> 
> Modified: 
> incubator/beehive/trunk/netui/src/util/org/apache/beehive/netu
> i/util/netui.properties
> Url: 
> http://svn.apache.org/viewcvs/incubator/beehive/trunk/netui/sr
> c/util/org/apache/beehive/netui/util/netui.properties?view=dif
> f&rev=124028&p1=incubator/beehive/trunk/netui/src/util/org/apa
> che/beehive/netui/util/netui.properties&r1=124027&p2=incubator
/beehive/trunk/netui/src/util/org/apache/beehive> 
/netui/util/netui.properties&r2=124028
> ==============================================================
> ================
> --- 
> incubator/beehive/trunk/netui/src/util/org/apache/beehive/netu
> i/util/netui.properties       (original)
> +++ 
> incubator/beehive/trunk/netui/src/util/org/apache/beehive/netu
> i/util/netui.properties       Mon Jan  3 13:42:54 2005
> @@ -452,19 +452,19 @@
>  PageFlow_ActionNotFoundException_Message= \
>  Unable to find matching action {0} in page flow {1}.
>  
> -PageFlow_DoubleFormPostException_Page= \ 
> -<html><head><title>Page Flow Error - Double Form 
> Post</title></head>\n \
> +PageFlow_DoubleSubmitException_Page= \
> +<html><head><title>Page Flow Error - Double Submit</title></head>\n \
>  <body>\n \
> -<h1>Page Flow Error - Double Form Post</h1>\n \
> +<h1>Page Flow Error - Submit</h1>\n \
>  <table border="1" cellspacing="0">\n \
>  <tr><td><b>Page Flow:</b></td><td>{1}</td></tr>\n \  
> <tr><td><b>Action:</b></td><td>{0}</td></tr>\n \  </table><br 
> />\n \ -<span style="color:red">A double-post occurred for 
> action <b>{0}</b>.</span>\n \
> +<span style="color:red">A double-submit occurred for action 
> +<b>{0}</b>.</span>\n \
>  </body></html>\n
>  
> -PageFlow_DoubleFormPostException_Message= \
> -A double-post occurred for action <b>{0}</b> in page flow {1}.
> +PageFlow_DoubleSubmitException_Message= \
> +A double-submit occurred for action <b>{0}</b> in page flow {1}.
>  
>  PageFlow_UnhandledException_Page = \
>  <html><head><title>Page Flow Unhandled Exception</title></head>\n \
> 
> Modified: 
> incubator/beehive/trunk/netui/test/webapps/drt/coreWeb/WEB-INF
> /tiles-defs.xml
> Url: 
> http://svn.apache.org/viewcvs/incubator/beehive/trunk/netui/te
> st/webapps/drt/coreWeb/WEB-INF/tiles-defs.xml?view=diff&rev=12
> 4028&p1=incubator/beehive/trunk/netui/test/webapps/drt/coreWeb
> /WEB-INF/tiles-defs.xml&r1=124027&p2=incubator/beehive/trunk/n
> etui/test/webapps/drt/coreWeb/WEB-INF/tiles-defs.xml&r2=124028
> ==============================================================
> ================
> --- 
> incubator/beehive/trunk/netui/test/webapps/drt/coreWeb/WEB-INF
> /tiles-defs.xml       (original)
> +++ 
> incubator/beehive/trunk/netui/test/webapps/drt/coreWeb/WEB-INF
> /tiles-defs.xml       Mon Jan  3 13:42:54 2005
> @@ -2,7 +2,7 @@
>  
>   <!DOCTYPE tiles-definitions PUBLIC
>         "-//Apache Software Foundation//DTD Tiles Configuration//EN"
> -       "http://jakarta.apache.org/struts/dtds/tiles-config.dtd";>
> +       "http://jakarta.apache.org/struts/dtds/tiles-config_1_1.dtd";>
>  
>  
>  <!--
> 
> Added: 
> incubator/beehive/trunk/netui/test/webapps/drt/coreWeb/miniTes
> ts/preventDoubleSubmit/Controller.jpf
> Url: 
> http://svn.apache.org/viewcvs/incubator/beehive/trunk/netui/te
> st/webapps/drt/coreWeb/miniTests/preventDoubleSubmit/Controlle
> r.jpf?view=auto&rev=124028
> ==============================================================
> ================
> --- (empty file)
> +++ 
> incubator/beehive/trunk/netui/test/webapps/drt/coreWeb/miniTes
> ts/preventDoubleSubmit/Controller.jpf Mon Jan  3 13:42:54 2005
> @@ -0,0 +1,27 @@
> +package miniTests.preventDoubleSubmit;
> +
> +import org.apache.beehive.netui.pageflow.*;
> +import org.apache.beehive.netui.pageflow.annotations.*;
> +
> [EMAIL PROTECTED](
> +    simpleActions={
> +        @Jpf.SimpleAction(name="begin", path="index.jsp"),
> +        @Jpf.SimpleAction(name="anchorSubmit", 
> preventDoubleSubmit=true, path="submitted.jsp")
> +    },
> +    catches={
> +        @Jpf.Catch(type=DoubleSubmitException.class, 
> path="caughtit.jsp")
> +    }
> +)
> +public class Controller extends PageFlowController
> +{
> +    @Jpf.Action(
> +        preventDoubleSubmit=true,
> +        forwards={
> +            @Jpf.Forward(name="submitted", path="submitted.jsp")
> +        }
> +    )
> +    public Forward formSubmit()
> +    {
> +        return new Forward("submitted");
> +    }
> +}
> 
> Added: 
> incubator/beehive/trunk/netui/test/webapps/drt/coreWeb/miniTes
> ts/preventDoubleSubmit/caughtit.jsp
> Url: 
> http://svn.apache.org/viewcvs/incubator/beehive/trunk/netui/te
> st/webapps/drt/coreWeb/miniTests/preventDoubleSubmit/caughtit.
> jsp?view=auto&rev=124028
> ==============================================================
> ================
> --- (empty file)
> +++ 
> incubator/beehive/trunk/netui/test/webapps/drt/coreWeb/miniTes
> ts/preventDoubleSubmit/caughtit.jsp   Mon Jan  3 13:42:54 2005
> @@ -0,0 +1,19 @@
> +<%@ page language="java" contentType="text/html;charset=UTF-8"%>
> +<%@ taglib prefix="netui" 
> +uri="http://beehive.apache.org/netui/tags-html-1.0"%>
> +<%@ taglib prefix="netui-data" 
> uri="http://beehive.apache.org/netui/tags-databinding-1.0"%>
> +<%@ taglib prefix="netui-template" 
> uri="http://beehive.apache.org/netui/tags-template-1.0"%>
> +
> +
> +<netui:html>
> +    <head>
> +        <netui:base/>
> +    </head>
> +    <netui:body>
> +        OK -- caught DoubleSubmitException
> +        <br/>
> +        <netui:anchor action="begin">start over</netui:anchor>
> +    </netui:body>
> +</netui:html>
> +
> +  
> +
> 
> Added: 
> incubator/beehive/trunk/netui/test/webapps/drt/coreWeb/miniTes
> ts/preventDoubleSubmit/index.jsp
> Url: 
> http://svn.apache.org/viewcvs/incubator/beehive/trunk/netui/te
> st/webapps/drt/coreWeb/miniTests/preventDoubleSubmit/index.jsp
> ?view=auto&rev=124028
> ==============================================================
> ================
> --- (empty file)
> +++ 
> incubator/beehive/trunk/netui/test/webapps/drt/coreWeb/miniTes
> ts/preventDoubleSubmit/index.jsp      Mon Jan  3 13:42:54 2005
> @@ -0,0 +1,27 @@
> +<%@ page language="java" contentType="text/html;charset=UTF-8"%>
> +<%@ taglib prefix="netui" 
> +uri="http://beehive.apache.org/netui/tags-html-1.0"%>
> +<%@ taglib prefix="netui-data" 
> uri="http://beehive.apache.org/netui/tags-databinding-1.0"%>
> +<%@ taglib prefix="netui-template" 
> uri="http://beehive.apache.org/netui/tags-template-1.0"%>
> +
> +
> +<netui:html>
> +    <head>
> +        <netui:base/>
> +    </head>
> +    <netui:body>
> +        <netui:form action="formSubmit">
> +            <netui:button value="netui:form (prevent double post)"/>
> +        </netui:form>
> +        <netui:form action="begin">
> +            <netui:button action="formSubmit" 
> value="netui:button (prevent double post)"/>
> +        </netui:form>
> +        <netui:anchor action="anchorSubmit">netui:anchor 
> (prevent double post)</netui:anchor>
> +        <br/>
> +        <br/>
> +        <netui:imageAnchor action="anchorSubmit" 
> src="../../resources/images/goButton.jpg">netui:imageAnchor 
> (prevent double post)</netui:imageAnchor>
> +        <br/>
> +    </netui:body>
> +</netui:html>
> +
> +  
> +
> 
> Added: 
> incubator/beehive/trunk/netui/test/webapps/drt/coreWeb/miniTes
> ts/preventDoubleSubmit/submitted.jsp
> Url: 
> http://svn.apache.org/viewcvs/incubator/beehive/trunk/netui/te
st/webapps/drt/coreWeb/miniTests/preventDoubleSubmit/submitted.jsp?view=auto&rev=124028
==============================================================================
--- (empty file)
+++ 
incubator/beehive/trunk/netui/test/webapps/drt/coreWeb/miniTests/preventDoubleSubmit/submitted.jsp
  Mon Jan  3 13:42:54 2005
@@ -0,0 +1,17 @@
+<%@ page language="java" contentType="text/html;charset=UTF-8"%>
+<%@ taglib prefix="netui" 
+uri="http://beehive.apache.org/netui/tags-html-1.0"%>
+<%@ taglib prefix="netui-data" 
uri="http://beehive.apache.org/netui/tags-databinding-1.0"%>
+<%@ taglib prefix="netui-template" 
uri="http://beehive.apache.org/netui/tags-template-1.0"%>
+
+
+<netui:html>
+    <head>
+        <netui:base/>
+    </head>
+    <netui:body>
+        OK -- submitted once.  Use the back button and submit again.
+    </netui:body>
+</netui:html>
+
+  
+

Reply via email to