8.11. Seam interceptors
EJB3 introduced a standard interceptor model for session bean components. To add an interceptor to a bean, you need to write a class with a method annotated
@AroundInvoke and annotate the bean with an @Interceptors annotation that specifies the name of the interceptor class. For example, the following interceptor checks that the user is logged in before invoking an action listener method:
public class LoggedInInterceptor { @AroundInvoke public Object checkLoggedIn(InvocationContext invocation) throws Exception { boolean isLoggedIn = Contexts.getSessionContext() .get("loggedIn")!=null; if (isLoggedIn) { //the user is already logged in return invocation.proceed(); } else { //the user is not logged in, fwd to login page return "login"; } } }
To apply this interceptor to a session bean acting as an action listener, you must annotate the session bean
@Interceptors(LoggedInInterceptor.class). However, Seam builds upon the interceptor framework in EJB3 by allowing you to use @Interceptors as a meta-annotation for class level interceptors (those annotated @Target(TYPE)). In this example, you create a @LoggedIn annotation, as follows:
@Target(TYPE) @Retention(RUNTIME) @Interceptors(LoggedInInterceptor.class) public @interface LoggedIn {}
You can annotate the action listener bean with
@LoggedIn to apply the interceptor:
@Stateless @Name("changePasswordAction") @LoggedIn @Interceptors(SeamInterceptor.class) public class ChangePasswordAction implements ChangePassword { ... public String changePassword() { ... } }
Where interceptor order is important, add
@Interceptor annotations to your interceptor classes to specify an order of interceptors.
@Interceptor(around={BijectionInterceptor.class, ValidationInterceptor.class, ConversationInterceptor.class}, within=RemoveInterceptor.class) public class LoggedInInterceptor { ... }
You can have a client-side interceptor, for built-in EJB3 functions:
@Interceptor(type=CLIENT) public class LoggedInInterceptor { ... }
EJB interceptors are stateful, and their life cycles match the life cycles of the component they intercept. For interceptors that do not need to maintain state, Seam allows performance optimization where
@Interceptor(stateless=true) is specified.
Much of Seam's functionality is implemented as a set of built-in Seam interceptors, including the interceptors named in the previous example. These interceptors exist for all interceptable Seam components; you need not specify them explicitly through annotations.
Seam interceptors can also be used with JavaBean components. EJB defines interception not only for business methods (using
@AroundInvoke), but also for the life cycle methods @PostConstruct, @PreDestroy, @PrePassivate, and @PostActive. Seam supports these life cycle methods on both component and interceptor, not only for EJB3 beans, but also for JavaBean components (except @PreDestroy, which is not meaningful for JavaBean components).