RSS Entries RSS
RSS Subscribe by Email

Struts 2 Tutorial – Interceptors

Interceptors are my favorite aspect of Struts 2. They inspect and/or act on a user’s request. There are three main uses cases that I’ll discuss here: intercepting before the action, between the action and view, and after the view. At the end, I’ll show you how to add your brand spankin’ new interceptor to your struts.xml file so that it is called on each request.

Intercepting Before the Action:

package org.lumidant.tutorial.struts2.interceptor;

import java.util.Map;

import com.opensymphony.xwork2.Action;
import com.opensymphony.xwork2.ActionInvocation;
import com.opensymphony.xwork2.ValidationAware;
import com.opensymphony.xwork2.interceptor.AbstractInterceptor;

public class AuthorizationInterceptor extends AbstractInterceptor {

	private static final String USER_KEY = "user";

	public String intercept(ActionInvocation invocation) throws Exception {
		Map session = invocation.getInvocationContext().getSession();
		if(session.get(USER_KEY) == null) {
			addActionError(invocation, "You must be authenticated to access this page");
			return Action.ERROR;
		}

		return invocation.invoke();
	}

	private void addActionError(ActionInvocation invocation, String message) {
		Object action = invocation.getAction();
		if(action instanceof ValidationAware) {
			((ValidationAware) action).addActionError(message);
		}
	}

}

You can see that we check to see if the user is authorized and present an error message if he/she is not logged in. We do this by adding an ActionError, which can be displayed on your view. If the user is logged in, then he/she proceeds normally.

Intercepting Between the Action and Generation of View:

package org.lumidant.tutorial.struts2.interceptor;

import java.util.Map;

import com.opensymphony.xwork2.ActionInvocation;
import com.opensymphony.xwork2.interceptor.AbstractInterceptor;
import com.opensymphony.xwork2.interceptor.PreResultInterceptor;
import org.apache.struts2.ServletActionContext;

public class WirelessInterceptor extends AbstractInterceptor {

	private static final String RESULT_CODE_SUFFIX_WIRELESS = "Wireless";
	private static final String REQUEST_HEADER_ACCEPT = "Accept";
	private static final String ACCEPT_HEADER_WIRELESS = "vnd.wap";

	public String intercept(ActionInvocation invocation) throws Exception {

		invocation.addPreResultListener()(new PreResultListener() {
			public void beforeResult(ActionInvocation invocation, String resultCode) {

				// check if a wireless version of the page exists
				// by looking for a wireless action mapping in the struts.xml
				Map results = invocation.getProxy().getConfig().getResults();
				if(!results.containsKey(resultCode + RESULT_CODE_SUFFIX_WIRELESS)) {
					return;
				}

				// send to wireless version if wireless device is being used
				final String acceptHeader = ServletActionContext.getRequest().getHeader(REQUEST_HEADER_ACCEPT);
				if(acceptHeader != null && acceptHeader.toLowerCase().contains(ACCEPT_HEADER_WIRELESS)) {
					invocation.setResultCode(resultCode + RESULT_CODE_SUFFIX_WIRELESS);
				}
			}
		});

		return invocation.invoke();
	}
}

In this example, the action has already been taken, but we have not generated the view that the user will see yet. This allows us to send the user to a separate page if he/she is using a Blackberry. We check the Accept HTML header to see if the string “vnd.wap” is present and if so then we append “Wireless” to the result code. So if the action was going to send the user to the result “Success” then we will instead show them the result “SuccessWireless”. We could easily adopt this technique for a Google Android or an iPhone as well.

Intercepting after View Creation:

package org.lumidant.tutorial.struts2.interceptor;

import java.util.Map;

import org.hibernate.Transaction;
import org.marketcharts.data.dao.util.HibernateSessionFactory;

import com.opensymphony.xwork2.Action;
import com.opensymphony.xwork2.ActionInvocation;
import com.opensymphony.xwork2.interceptor.AbstractInterceptor;

public class HibernateInterceptor extends AbstractInterceptor {

	public String intercept(ActionInvocation invocation) throws Exception {
		try {
			return invocation.invoke();
		} catch(Exception e) {
			Transaction tx = HibernateSessionFactory.getSession().getTransaction();
			if(tx != null && tx.isActive()) {
				tx.rollback();
			}
			return Action.ERROR;
		} finally {
			HibernateSessionFactory.getSession().close();
		}
	}

}

This example uses Hibernate, an Object Relational Mapper (ORM), which is library for easy database access. Hibernate needs an open session when the view is created (Open Session in View Pattern) because it lazily accesses the database. If the session is closed and we go to access the database, then Hibernate will throw an Exception. So this interceptor provides a method to close the session after the view has already been created and all the database calls have been made.

Adding an Interceptor to your struts.xml:

<package name="example" extends="struts-default">
  <interceptors>
    <!--
      One possible use of an interceptor is to send the user to special version of the .jsp
  	view if they are using a Blackberry as shown above.
    -->
    <interceptor name="wireless" class="com.lumidant.tutorial.struts2.interceptor.WirelessInterceptor">

    <interceptor-stack name="wirelessStack">
      <interceptor-ref name="exception" />
      <interceptor-ref name="servlet-config" />
      <interceptor-ref name="i18n" />
      <interceptor-ref name="chain" />
      <interceptor-ref name="params" />
      <interceptor-ref name="wireless" />
    </interceptor-stack>
  </interceptors>

  <default-interceptor-ref name="wirelessStack" />
</package>

In this example, we’ve change the default interceptor stack to be a custom stack which we’ve created. You can also extend existing stacks.

Share and Enjoy:
  • Add to favorites
  • HackerNews
  • DZone
  • Reddit
  • del.icio.us
  • StumbleUpon
  • Slashdot
  • Digg
  • Google Bookmarks
  • Facebook

Tags: ,

16 Comments »

  1. Struts 2 Tutorial - Struts Configuration | Lumidant said,

    September 20, 2008 at 11:16 am

    [...] struts.xml file defines the relationship between actions and .jsp views, the inclusion of interceptors, and possible result types.  It’s essential that you be able to handle at least basic [...]

  2. Rosario said,

    November 6, 2008 at 4:42 am

    Hi,
    your example is very interesting and i understand what the interceptors are from this simple example.
    Thanks a lot!!!

  3. Andriy said,

    February 23, 2009 at 3:45 am

    Realy interesting! I read book “struts2 in action” but did not find any example about
    Intercepting after View Creation and Intercepting Between the Action and Generation of View:

  4. Frank said,

    July 3, 2009 at 4:27 am

    Straight forward and clear example! Here’s a follow up:
    You may add parameters to the interceptor-definition in struts.xml like this

    something

    How do you retrieve that parameter in the interceptor’s java code?

  5. Arne said,

    July 10, 2009 at 6:21 am

    Please do NOT use the “Open Session in View-Pattern”. This should only be an example to unerstand how interceptors works. The “Open Session in View Pattern” makes the View dependend on persistence layer aspects…

  6. Nageswara Rao M said,

    August 7, 2009 at 2:03 am

    Hi..,
    This information good and stight forward to the beginers.
    I really enjoyed while reading this article.
    Thak you.

  7. PEEBEEASH said,

    October 1, 2009 at 4:09 am

    This is one of the best example I have ever read for interceptor…Really fantastic example…..It helped me a lot..Thanks a lot

  8. Bhaskar V said,

    November 2, 2009 at 12:01 am

    It is very good for beginners Struts2….

  9. Praveen Aithal said,

    February 3, 2010 at 12:39 am

    I dint know about this. Thanks for the idea. But I wanted to know how struts.xml will look in the last case: Intercepting after View Creation. plz help me and thanks in advance.

  10. Ben said,

    February 4, 2010 at 3:07 pm

    Praveen, the struts.xml file will look the same regardless.

  11. Kamlesh said,

    February 5, 2010 at 3:19 am

    Hi Benjamin,

    Nice to see your blog,
    we are using interceptor, now we want that only one can login with the same usename, can we do it by using interceptor, how? pls guide me.

    Tanx
    Kamlesh

  12. Ben said,

    February 5, 2010 at 7:35 pm

    Kamlesh, I’m afraid I don’t understand your question entirely.

  13. Kamlesh said,

    February 5, 2010 at 10:35 pm

    Hi Benjamin

    Actually we are already using interceptor in our web portal, But in this web portal one user can login more than once simultaneously with the same username and password(username is unique).

    It means if i logged in with username “kamlesh” and pw “123456″ even though other can login with username “kamlesh” ane pw “123456″ (the username is unique). I want to restrict this.

    At a time Only one can login with one username. No one can login with username which is already logged in.
    If you have faced this problem then pls help out me.

    Regard
    Kamlesh

  14. Ben said,

    February 6, 2010 at 10:31 am

    Kamlesh, what you are talking about is tying a login to an IP address. You can invalidate the session ID if the IP address changes or ignore all new session requests while there is an active session under an old IP address. This can present usability problems to some users if their IP address changes. Another option would be to present an alert to the user that the IP address logged in has changed. For example, GMail lists the last account activity on the page. You should log these instances as well in case they present a security incident. You’ll likely want to put a decent portion of this logic in your login Action.

  15. billy vandory said,

    June 17, 2010 at 1:41 am

    @Arnie: OSIV is a valid pattern. Arnie, it may have caused you grief, but to advise everyone NOT TO USE IT is a little cocky, no? There are use cases when OSIV may work just fine, like a backoffice application where the need to break out the layers into tiers with some kind of facade separating concerns is not doable due to project timelines and costs.

  16. praveen said,

    August 24, 2010 at 8:57 pm

    good example .

RSS feed for comments on this post · TrackBack URL

Leave a Comment