Friday, May 20, 2011

Struts 2 Interceptors - before, between and after

Struts 2 Interceptors is one of the greatest features of Struts 2 to handle regular routing logic and special logic at special occassion on demand the AOP way.
In most cases, you want to intercept the running application before action invocation, between action invocation and result generation and after view rendered.

I found a great tutorial on how to handle the above 3 senario at Benjamin J. McCann's blog post.

Below is quick summary:

To create a Struts 2 interceptor, you need to implement Interceptor interface or extend one of the build-in interceptor class. E.g. AbstractInterceptor

Intercept Before Action

public class MyInterceptor extends AbstractInterceptor {
  private static final long serialVersionUID = 5065298925572763728L;
    @Override
    public String intercept(ActionInvocation invocation) throws Exception {
      // do something before invoke
      try{
        if(o instanceof MyAction){
          ((MyAction) o).someLogicBeforeAction();
        }
      }catch(Exception e){
        return "error";
      } 

      // invocation continue    
      return invocation.invoke();
    }
  }
}

Intercept Between Action and Result

(after action is executed but before result is rendered)

Register a PreResultListener to the invocation instance. Sample code as below:
public class MyInterceptor extends AbstractInterceptor {
  private static final long serialVersionUID = 5065298925572763728L;
    @Override
    public String intercept(ActionInvocation invocation) throws Exception {
      // Register a PreResultListener and implement the beforeReslut method
      invocation.addPreResultListener(new PreResultListener() { 
        @Override
        public void beforeResult(ActionInvocation invocation, String resultCode) {
          Object o = invocation.getAction();
          try{
            if(o instanceof MyAction){
              ((MyAction) o).someLogicAfterActionBeforeView();
            }
          }catch(Exception e){
            invocation.setResultCode("error");
          }
        }
      });
      
      // Invocation Continue
      return invocation.invoke();
    }
  }
}

Intercept After View Rendered


public class MyInterceptor extends AbstractInterceptor {
  private static final long serialVersionUID = 5065298925572763728L;
    @Override
    public String intercept(ActionInvocation invocation) throws Exception {
      // do something before invoke
      try{
        // invocation continue    
        return invocation.invoke();
      }catch(Exception e){
        // You cannot change the result code here though, such as:
        // return "errorr"; 
        // This line will not work because view is already generated  
        // You can do something like database cleanup or logging at this point
        doSomeLogicAfterView();
      } 
    }
  }
}