Thursday, January 27, 2011

Struts2 Interceptors

Interceptors are one of the most powerful, and yet seemingly least understood feature of Struts2. The Interceptor framework is basically the core of the Struts2 framework, and understanding how it works is the key to really unlocking the power of Struts2.

For any given web request, there is a series of Interceptors that get fired off before your Action class is called. Each Interceptor performs a specific job that is required for every action. Some of the core functionality of Struts2 lives in these Interceptors by default, such as populating the member variables of your action class, validating data and exception handling.

The Interceptors fire based off of what is known as the Interceptor Stack. The Stack is just an ordered list of Interceptors that need to be fired prior to entering the action. When you include the struts core library in your project, it includes a file called "struts-default.xml", which defines all of the core Interceptors and a default Interceptor Stack. Since these are set up by default, and they handle most use cases, most people do not really understand the Stack, because it "Just Works".

To understand how it works, you just need to look at what happens when struts receives a new request. It starts things off by creating an object called the ActionInvocation, and calling a method called "invoke" on that object. During the first trigger, invoke looks at the configured Stack, gets the first Interceptor configured, and fires that Interceptor's "intercept" method.

Inside "intercept" is where the Interceptor performs whatever tasks it needs to get done. For example, there is an Interceptor available for use called the LoggingInterceptor. Inside of this Interceptor's "intercept" method, the first thing that it does is log out an "Entering" message.

After performing any necessary operations, the interceptor then calls ActionInvocation.invoke again. Bear in mind the call stack we have going so far:
    ActionInvocation.invoke()
        Interceptor1.intercept()
            ActionInvocation.invoke()

Back inside invoke, the ActionInvocation class has kept track of what Interceptors it has already fired. In this case, it has made note of the fact that Interceptor1 has already been called. It looks again at the Stack, and finds the Interceptor configured to fire after Interceptor1, and calls that Interceptor's "intercept" method.

This continues on and on, until we reach the last interceptor. After the last interceptor performs whatever it needs to do, it again calls ActionInvocation.invoke. ActionInvocation now recognizes that all of the Interceptors have been called, and proceed to call the Action class's execute method. So the final call stack looks something like this:
    ActionInvocation.invoke()
        Interceptor1.intercept()
            ActionInvocation.invoke()
                Interceptor2.intercept()
                    ActionInvocation.invoke()
                        .
                        .
                        .
                        InterceptorN.intercept()
                            ActionInvocation.invoke()
                                Action.execute()

This is now the part that most people are familiar with - the Action class. Your Action does what it needs to do, then returns a String value. Something like "success", "error", "input", etc. These return values end up determining what page gets displayed to the user.

This String that gets returned by your Action class - where does it go? If we look up at our call stack, we will see that it will return to ActionInvocation.invoke. Interesting. Here is the fun part - both ActionInvocation.invoke and all of the Interceptors "intercept" methods return Strings as well. In fact, they return your String.

So now we start to unwind back up the Stack. This is another very important part of the framework. Do you ever remember seeing those weird Struts2 pictures, that show all of the Interceptors being fired twice? Once before the Action, and once after? Like this one:


This call stack is how that works. The Interceptors do not actually get fired twice. They are fired once, but the Action call occurs inside of them. Back to the above mentioned LoggingInterceptor now. As I said, this Interceptor logs out an "Entering" message when it starts, then it fires "invoke". After "invoke" returns, though, this Interceptor is not done - it also logs a "Leaving" message afterward.

Here is the complete code necessary in order to log an entering and leaving message before and after every single one of your Action calls:
@Override
public String intercept(ActionInvocation invocation) throws Exception {
        logMessage(invocation, START_MESSAGE);
        String result = invocation.invoke();
        logMessage(invocation, FINISH_MESSAGE);
        return result;
}

That's it. Instead of log lines inserted at the top and bottom of every single Action class, this one little snippet set up as an Interceptor does all that work for you.

I wanted to go over how to do a custom interceptor, but I have already prattled quite a bit longer than I thought I would. Hopefully I have given you a bit better understanding on how Interceptors work, and gotten you hungry to learn how you can start writing your own. More posts will follow.

4 comments:

  1. wow.....Thanx. Now i got how struts2 interceptors work. This is a good blog to understand how to strust2 interceptor work. :)

    ReplyDelete
  2. Thank you, its very understandful written.

    ReplyDelete
  3. nice one.. but need to explain more in detail and depth

    ReplyDelete
  4. Thanks for this nice post.Now able to understand working of Struts2 interceptors better.

    ReplyDelete