Tuesday, January 10, 2012

Token implementation to avoid multiple request

The common problem is browser submitting same request on refresh or ctrl+f5. To overcome the issue in java we have to write token implementation, this is similar to what Struts framework provides.

Common Token Class

package com.nmmc.common.utils;

import java.util.Random;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpSession;

public class CommonTokenUtils
{

    public static String TOKEN_KEY = Constants.SESSION_TOKEN_KEY;
    public static String TOKEN_VALUE = "";

    private static synchronized boolean isTokenValid(HttpSession session,  String requestToken) throws Exception {

        String sessionToken = (String)session.getAttribute(getTokenKey());
        if (requestToken == null) {
            // The hidden field wasn't provided
            throw new Exception("Missing synchronizer token in request");
        }
        if (sessionToken == null) {
            // The session has lost the token.
            throw new Exception("Missing synchronizer token in session");
        }
        if (sessionToken.equals(requestToken)) {
            // Accept the submission and increment the token so this form can't
            // be submitted again ...
            TOKEN_VALUE=nextToken();
            session.setAttribute(getTokenKey(), TOKEN_VALUE);
            return true;
        }
        return false;
    }
   
    private static String nextToken() {
        long seed = System.currentTimeMillis();
        Random r = new Random();
        r.setSeed(seed);
        return Long.toString(seed) + Long.toString(Math.abs(r.nextLong()));
    }

    private static String getTokenKey() {
        return TOKEN_KEY;
    }
   
    public static void setNewToken(HttpServletRequest request)
    {
          HttpSession session = request.getSession();
          TOKEN_VALUE=nextToken();
          session.setAttribute(getTokenKey(), TOKEN_VALUE); 
    }
   
    public static void setNewToken(HttpSession session)
    {
          TOKEN_VALUE=nextToken();
          session.setAttribute(getTokenKey(), TOKEN_VALUE); 
    }
   
    public static boolean allowFormSubmit(HttpServletRequest request)
    {
        try {
            HttpSession session = request.getSession();
            String requestToken = request.getParameter(getTokenKey());
            if(isTokenValid(session, requestToken))
                return true;
        } catch (Exception e) {
            e.printStackTrace();
        }
        return false;       
    }
   
    public static boolean allowFormSubmit(HttpSession session, String requestToken)
    {
        try {
            if(isTokenValid(session, requestToken))
                return true;
        } catch (Exception e) {
            e.printStackTrace();
        }
        return false;       
    }
}

Client Code in Controller:

if (CommonTokenUtils.allowFormSubmit(request)){
   // Allow save or update
}
//reset the token to avoid duplicate submission
CommonTokenUtils.setNewToken(request);