Stripes includes an Interceptor system designed to make it easy to add functionality to Stripes. For cross-cutting behaviour it is often simpler to write an interceptor than to extend Stripes' built in components.
The following classes form the core of the Stripes lifecycle and interceptor system:
- LifecycleStage is an enum that describes the stages through which a request progresses. This is discussed in great detail in the Lifecycles Etc. page.
- Interceptor defines the interface contract that interceptors use.
- Intercepts is an annotation used to mark interceptors with the stages that they will intercept
- ExecutionContext wraps up all the context associated with an ActionBean invocation, and is supplied to interceptors
Let's look at an example. The following is a simply interceptor that "logs" a message before and after every lifecycle stage:
While this interceptor does nothing of practical value, it does illustrate some basic concepts. Firstly the @Intercepts is used to specify what lifecycle stages are intercepted. In this case we specify all stages, so the interceptor will be invoked up to six times during every request to an ActionBean! Secondly, interceptors intercept around the lifecycle stage. As a result they can execute code before it and after it. When the interceptor is ready to execute the lifecycle code (and/or any downstream interceptors) it simply calls ExecutionContext.proceed().
In fact interceptors can decide to skip a stage entirely, or even abort execution early by returning a Resolution. When an interceptors does this, the resolution is executed and the rest of the lifecycle is omitted.
Configuring interceptors is fairly straightforward. With Stripes 1.5 and up, your interceptors will automatically be detected if they are in a package configured with the Extension.Packages parameter. You can also use an initialization parameter of the Stripes Filter:
Normally, you would only use the web.xml configuration method if the ordering of the interceptors is important. When multiple interceptors intercept at the same lifecycle stage they are executed in the order they are listed.
If you are using Stripes 1.4.x or earlier, you must use the web.xml configuration, and the only gotcha is that Stripes by default configures a single interceptor, the BeforeAfterMethodInterceptor. When specifying interceptors you need to also specify the BeforeAfterMethodInterceptor unless you wish to disable it:
Another example of where an interceptor might be useful is in application security. A prototype interceptor might look like:
In this case the interceptor intercepts at one specific lifecycle stage: handler resolution. When this stage is complete the ExecutionContext contains information about which ActionBean is being called, and which event is being handled - sufficient information to determine if the user is allowed access or not. On top of this, the interceptor can, through the ActionBeanContext, access information in the HttpServletRequest for further checks.
The BeforeAfterMethodInterceptor mentioned above is an interceptor which gives ActionBeans the ability to define methods to be execute before and/or after certain lifecycle stages. Methods marked with a @Before are run before the specified lifecycle stages. If no stage is specified then the method is run before the EventHandling stage. Methods marked with an @After annotation work similarly, but run after the specified lifecycle stages.
The SpringInterceptorSupport class is a simple base class that provide Spring bean injection into custom interceptors. Otherwise there is no difference between extending SpringInterceptorSupport and implementing Interceptor directly.