Wednesday, July 7, 2010

Struts2 : Token Session Interceptor

In case of multiple request using same session, this interceptor is capable to block all the subsequesnt requests, while the first request is being processed.

Here is the sample code:

index.jsp


<%@ page language="java" contentType="text/html; charset=ISO-8859-1"
pageEncoding="ISO-8859-1"%>

<%@ taglib prefix="s" uri="/struts-tags" %>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1">
<title>Insert title here</title>
</head>
<body>
<s:form action="execActionAction" method="POST">
<s:textfield name="somestring"/>
<br>
<s:submit value="Enter"/>
<s:token />
</s:form>
</body>
</html>

result.jsp

<%@ page language="java" contentType="text/html; charset=ISO-8859-1"
pageEncoding="ISO-8859-1"%>
<%@ taglib prefix="s" uri="/struts-tags" %>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1">
<title>Result</title>
</head>
<body>
<s:property value="somestring" />
<br>
</body>
</html>

Test.java

package com.Test;

import com.opensymphony.xwork2.ActionSupport;

public class Test extends ActionSupport{

private String somestring;

public String getSomestring() {
return somestring;
}

public void setSomestring(String somestring) {
this.somestring = somestring;
}


public String execute() throws Exception{

System.out.println("Printing Token-Session");

return SUCCESS;
}

}


struts.xml

<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE struts PUBLIC
"-//Apache Software Foundation//DTD Struts Configuration 2.0//EN"
"http://struts.apache.org/dtds/struts-2.0.dtd ">
<struts>

<include file="struts-default.xml" />
<package name="mypkgTest" extends="struts-default">

<action name="execActionAction" class="com.Test.Test">
<interceptor-ref name="basicStack" />
<interceptor-ref name="tokenSession" />


<result name="success">/result.jsp</result>
<result name="invalid.token">/index.jsp</result>

</action>

</package>
</struts>


web.xml

<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://java.sun.com/xml/ns/javaee" xmlns:web="http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd" xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd" id="WebApp_ID" version="2.5">
<display-name>myBlankProject</display-name>

<filter>
<filter-name>struts2</filter-name>
<filter-class>org.apache.struts2.dispatcher.FilterDispatcher</filter-class>
</filter>

<filter-mapping>
<filter-name>struts2</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>


<welcome-file-list>
<welcome-file>index.html</welcome-file>
<welcome-file>index.htm</welcome-file>
<welcome-file>index.jsp</welcome-file>
<welcome-file>default.html</welcome-file>
<welcome-file>default.htm</welcome-file>
<welcome-file>default.jsp</welcome-file>
</welcome-file-list>
</web-app>


The below form I've filled out with some text and pressed submit.








The result page displayed the string correctly.







In my Model (POJO) I've print another string on the console which is "Printing Token-Session". It is already there in the console as you can verify in the below screen shot.









Now, I've resubmit the form by pressing "Refresh" button on the browser. Now you can see that there is only one occurrence of the string "Printing Token Session" on the console even I've resubmitted the form and there will be an Warning stating that"Form token does not match the session token null.







So, this is the advantage of Token Session Interceptor, by which you can stop resubmitting of the form by the user.

Tuesday, July 6, 2010

Struts2 : Token Interceptor

It may happen that user double clicked on the submit button or back button, which may cause some side effects on the execution of the action class. This interceptor can make sure that back buttons and double clicks don't cause un-intended side affects. For example, you can use this to prevent careless users who might double click on a "checkout" button at an online store. This interceptor uses a fairly primitive technique for when an invalid token is found: it returns the result invalid.token, which can be mapped in your action configuration. A more complex implementation, TokenSessionStoreInterceptor, can provide much better logic for when invalid tokens are found.


Example:

index.jsp

Note: To set a token in your form, you should use the token tag. This tag is required and must be used in the forms that submit to actions protected by this interceptor. Any request that does not provide a token (using the token tag) will be processed as a request with an invalid token.


<%@ page language="java" contentType="text/html; charset=UTF-8"

pageEncoding="UTF-8"%>
<%@ taglib prefix="s" uri="/struts-tags" %>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"
"http://www.w3.org/TR/html4/loose.dtd">

<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>Insert title here</title>
</head>
<body>
<s:form action="AddEntry">
<s:textfield label="Name" name="name"/>
<s:textfield label="Address" name="address"/>
<s:textfield label="Phone Number" name="phoneNumber"/>
<s:submit value="ADD"/>
<s:token name="clientToken"></s:token>
</s:form>
</body>
</html>


success.jsp

<%@ page language="java" contentType="text/html; charset=UTF-8"

pageEncoding="UTF-8"%>
<%@ taglib prefix="s" uri="/struts-tags" %>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"
"http://www.w3.org/TR/html4/loose.dtd">

<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>Insert title here</title>
</head>
<body>
Name: <s:property value="name" />
<br>
Address: <s:property value="address" />
<br>
Phone: <s:property value="phoneNumber" />
</body>
</html>


AddEntry.java

package phoneBook;

import com.opensymphony.xwork2.ActionSupport;

public class AddEntry extends ActionSupport{

private static final long serialVersionUID = 1L;
private String name = null;


private String address = null;
private String phoneNumber = null;

public String getName() {
return name;
}

public void setName(String name) {
this.name = name;

}
public String getAddress() {
return address;

}
public void setAddress(String address) {
this.address = address;

}
public String getPhoneNumber() {
return phoneNumber;

}
public void setPhoneNumber(String phoneNumber) {
this.phoneNumber = phoneNumber;

}

public String execute() throws Exception{
System.out.println("Name\t\t:" +name);

System.out.println("Address\t\t:" +address);
System.out.println("Phone Number\t:" +phoneNumber);

return SUCCESS;
}
}


struts.xml

<!DOCTYPE struts PUBLIC

"-//Apache Software Foundation//DTD Struts Configuration 2.0//EN"
"http://struts.apache.org/dtds/struts-2.0.dtd">

<struts>
<package name="default" extends="struts-default">
<action name="AddEntry" class="phoneBook.AddEntry">
<interceptor-ref name="token" />
<interceptor-ref name="basicStack" />
<result name="success">/success.jsp</result>
<result name="invalid.token">/index.jsp</result>
</action>
</package>
</struts>


web.xml

<?xml version="1.0" encoding="UTF-8"?>

<web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://java.sun.com/xml/ns/javaee" xmlns:web="http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd" xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd" id="WebApp_ID" version="2.5">
<display-name>MyBlankProj</display-name>

<filter>
<filter-name>struts2</filter-name>
<filter-class>org.apache.struts2.dispatcher.ng.filter.StrutsPrepareAndExecuteFilter</filter-class>
</filter>

<filter-mapping>
<filter-name>struts2</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>

<welcome-file-list>
<welcome-file>index.html</welcome-file>
<welcome-file>index.htm</welcome-file>
<welcome-file>index.jsp</welcome-file>
<welcome-file>default.html</welcome-file>
<welcome-file>default.htm</welcome-file>
<welcome-file>default.jsp</welcome-file>
</welcome-file-list>
</web-app>

ok, the coding is over, now its time for test.......

Lets start our application by typing the url or by eclipse. The below page (index.jsp) would be displayed. I've filled-out the form as below. and pressed submit.

















The result page would appear (success.jsp). The thing here to notice is I've written code to print in the console also. In eclipse you can see the result appeared in the console just like below.








It means it will again appear if I refresh the page (i.e., resubmit the page). Lets do it....

No, it will never happen, it will go to the index.jsp page without resubmitting the page. You can check the console after refreshing the page and there you will find that only one occurrence of the result is showing and there will be an Warning stating that "com.opensymphony.xwork2.util.logging.commons.CommonsLogger warn WARNING: Form token JVP8Z7FXG8UYSN0QMT6WZ3SOYT63QD5G does not match the session token null.".






So, this is the advantage of Token Interceptor, by which you can stop resubmitting of the form by the user.