在Struts中使用令牌

I have a problem when i click twice on a link in my application, i have 2 calls done and page is refresh twice, and some error occurs.

So i decide to use token session interceptor to prevent of this errors.

And I'm trying to add struts 2 tokenSession interceptor in my application and i have a problem.

I have add this interceptor with all other interceptor :

<interceptor name="tokenSession" class="org.apache.struts2.interceptor.TokenSessionStoreInterceptor"/>

and now, my action look like :

<action name="SC002AfficherTestSeuil!*" method="{1}" class="fr.edf.mpv2.castor.actions.surveillance.SC002AfficherTestSeuilAction">
        <interceptor-ref name="tokenSession"></interceptor-ref>
        <interceptor-ref name="mpoStack"></interceptor-ref>
        <result name="input">/jsp/fr/edf/mpv2/castor/surveillance/SC002__afficherLesTestsDeSeuil.jsp</result>
        <result name="PAGE_SC002_afficherLesTestsDeSeuil">/jsp/fr/edf/mpv2/castor/surveillance/SC002__afficherLesTestsDeSeuil.jsp</result>
    </action>

My page contain a listbox and one button name "show"

when i select item in the listbox, user click on show button and an ajax call is done.

I enter into a method of public class TokenSessionStoreInterceptor extends TokenInterceptor

like :

 protected String handleInvalidToken(ActionInvocation invocation) throws Exception {
    ActionContext ac = invocation.getInvocationContext();

    HttpServletRequest request = (HttpServletRequest) ac.get(ServletActionContext.HTTP_REQUEST);
    HttpServletResponse response = (HttpServletResponse) ac.get(ServletActionContext.HTTP_RESPONSE); 
    String tokenName = TokenHelper.getTokenName();
    String token = TokenHelper.getToken(tokenName);

    Map params = ac.getParameters();
    params.remove(tokenName);
    params.remove(TokenHelper.TOKEN_NAME_FIELD);

    if ((tokenName != null) && (token != null)) {
        ActionInvocation savedInvocation = InvocationSessionStore.loadInvocation(tokenName, token);

        if (savedInvocation != null) {
            // set the valuestack to the request scope
            ValueStack stack = savedInvocation.getStack();
            Map context = stack.getContext();
            request.setAttribute(ServletActionContext.STRUTS_VALUESTACK_KEY, stack);

            ActionContext savedContext = savedInvocation.getInvocationContext();
            savedContext.getContextMap().put(ServletActionContext.HTTP_REQUEST, request);
            savedContext.getContextMap().put(ServletActionContext.HTTP_RESPONSE, response);
            Result result = savedInvocation.getResult();

            if ((result != null) && (savedInvocation.getProxy().getExecuteResult())) {
                synchronized (context) {
                    result.execute(savedInvocation);
                }
            }

            // turn off execution of this invocations result
            invocation.getProxy().setExecuteResult(false);

            return savedInvocation.getResultCode();
        }
    }

    return INVALID_TOKEN_CODE;
}

I don't understand why, but this line Result result = savedInvocation.getResult(); always return null, so if you read the struts code; my action is never done and my page is never refresh (remember that is an ajax call, so only a part of the page need to be refresh).

Could someone can give me some help to understand why my result is null? Did i forgot something in the configuration?

thanks a lot

EDIT #1 => add mpoStack

<interceptor-stack name="mpoStack">
            <interceptor-ref name="exception" />
            <interceptor-ref name="alias" />
            <interceptor-ref name="servletConfig" />
            <interceptor-ref name="prepare" />
            <interceptor-ref name="i18n" />
            <interceptor-ref name="chain" />
            <!--<interceptor-ref name="debugging" />-->
            <!--<interceptor-ref name="profiling" />-->
            <!-- Stack d'interceptor sécurité de Marco Polo - Start -->
            <interceptor-ref name="securiteStack" >

            </interceptor-ref>
            <!-- Stack d'interceptor sécurité de Marco Polo - End -->
            <interceptor-ref name="fileUpload" />
            <interceptor-ref name="checkbox" />
            <interceptor-ref name="staticParams" />
            <interceptor-ref name="params">
                <param name="excludeParams">dojo\..*</param>
            </interceptor-ref>
            <!--<interceptor-ref name="conversionError" />-->
            <interceptor-ref name="validation">
                <param name="excludeMethods">input,back,cancel,browse,execute,retour,annuler</param>
            </interceptor-ref>
            <interceptor-ref name="jsonValidation"/>
            <interceptor-ref name="workflow">
                <param name="excludeMethods">input,back,cancel,browse,execute,retour,annuler</param>
            </interceptor-ref>
        </interceptor-stack>
        <interceptor-stack name="mpoStackApplet">
            <interceptor-ref name="alias" />
            <interceptor-ref name="servletConfig" />
            <interceptor-ref name="prepare" />
            <interceptor-ref name="chain" />
            <interceptor-ref name="securiteStack" />
        </interceptor-stack>
        <!-- QC#3040 PATROL : web.log : Infinite recursion detected -->
        <interceptor-stack name="ErrorStack">
             <interceptor-ref name="exception" />
            <interceptor-ref name="alias" />
            <interceptor-ref name="servletConfig" />
            <interceptor-ref name="prepare" />
            <interceptor-ref name="i18n" />
            <interceptor-ref name="chain" />
            <interceptor-ref name="fileUpload" />
            <interceptor-ref name="checkbox" />
            <interceptor-ref name="staticParams" />
            <interceptor-ref name="params">
                <param name="excludeParams">dojo\..*</param>
            </interceptor-ref>
            <interceptor-ref name="validation">
                <param name="excludeMethods">input,back,cancel,browse,execute,retour,annuler</param>
            </interceptor-ref>
            <interceptor-ref name="jsonValidation"/>
            <interceptor-ref name="workflow">
                <param name="excludeMethods">input,back,cancel,browse,execute,retour,annuler</param>
            </interceptor-ref>
        </interceptor-stack>
    </interceptors>

    <default-interceptor-ref name="mpoStack" />

Appearently it is Issue WW-3415 (itself related to Issue WW-3865 and Issue WW-3895).

If this is the case, you could try moving to 2.3.20 that is the first release where it has been fixed.

Alternatively you can try the workaround proposed by OP of the first Issue, changing

return savedInvocation.getResultCode();

into

// Checks if the saved invocation has been executed as of now. 
// If not it gets executed again.
if(savedInvocation.isExecuted()) { 
    return savedInvocation.getResultCode();  
} else { 
    return savedInvocation.invoke(); 
}

finaly the problem is not the reason why i m having invalidtoken invoken but, like Roman C say in a comment, why i'm not getting a valid token at this point. so i have correct my code to handle valid token and all work fine now.