Friday, July 10, 2009

How to - Interceptors in EJB 3.0

I was checking the interceptors concept with EJB 3.0, and found it quite confusing, so just thought of writing this to clear the clouds around.

EJB 3.0 allows you to define interceptor methods that are called around the business methods and lifecycle events on the bean instances. The interceptor methods can either be defined within the bean class or in separate interceptor classes. Interceptor definitions and binding interceptors to bean classes or specific methods within the beans can be done either using annotations or within the deployment descriptors. Here, I will try to provide a simple example of using interceptors on business methods using annotations.

Methods that intercept invocations to business methods or lifecycle events can be defined either in the bean class or in separator interceptor classes. Only one interceptor method is allowed per class. The interceptor methods should be annotated with the @AroundInvoke annotation and should have the signature, Object (javax.ejb.InvocationContext). If the bean class has a method with the above signature and annotation, the method will be used to interpose on all the business method invocations on that bean. Additionally, you can define interceptors for all the business methods on the bean or individual business methods using the @Interceptors annotation. The value of this annotation is the list of interceptor classes. The interceptor classes are required to have a single interceptor method with the same signature and annotation as explained earlier. Interceptor classes have the same lifecycle as the associated bean instance and can have dependency injection, which will be done using the same naming context as the bean.

InvocationContext

InvocationContext allows you to propagate state across a chain of interceptors. In addition it allows to get/set method parameters, get a reference to the bean, get the invoked method name etc. The methods provided by InvocationContext interface are,
# Object getBean(): Returns a reference to the bean.
# Method getMethod(): Returns a reference to the invoked method.
# Object[] getParameters(): Returns the parameters passed to the method.
# void setParameters(Object[] parameters) : Sets the parameters.
# Map getContextData(): Get contextual data that can be shared in a chain.
# Object proceed(): Proceed to the next interceptor in the chain or the business method if it is the last interceptor.

Order of Interception

The interceptors are invoked in the order in which they are declared in the annotation. Bean level interceptors using interceptor classes are invoked before method level interceptors using interceptor classes. Interceptor method defined in the bean class itself is invoked at the end. If the bean or the interceptor classes have super classes with interceptor methods, they are invoked before the interceptor methods on the sub-classes are called.

Example

Now we will have a look at a simple example for doing interception on an EJB's business method.
Bean Class

package com.ed.ejb;

import javax.ejb.AroundInvoke;
import javax.ejb.Interceptors;
import javax.ejb.InvocationContext;
import javax.ejb.Stateless;
import javax.jws.WebMethod;
import javax.jws.WebService;

@Stateless
@WebService
@Interceptors( { Interceptor2.class })
public class HelloWorldBean {

@Interceptors( { Interceptor1.class })
@WebMethod
public String sayHello() {
return "Hello";
}

@WebMethod
public String sayHi() {
return "Hi";
}

@AroundInvoke
public Object log(InvocationContext invocationContext) throws Exception {
System.err.println(invocationContext.getMethod().getName() + " called from interceptor 3");
return invocationContext.proceed();
}

}

The bean class has an AroundInvoke method, a bean level interceptor and a method level interceptor. A call to sayHello will invoke the interceptors in the order bean level interceptor, method level interceptor and the AroundInvoke method within the bean class. A call to sayHi will invoke the interceptors in the order bean level interceptor and the AroundInvoke method within the bean class.

Interceptor Classes

package com.ed.ejb;

import javax.ejb.AroundInvoke;
import javax.ejb.InvocationContext;

public class Interceptor1 {

@AroundInvoke
public Object log(InvocationContext invocationContext) throws Exception {
System.err.println(invocationContext.getMethod().getName() + " called from interceptor 1");
return invocationContext.proceed();
}

}

package com.ed.ejb;

import javax.ejb.AroundInvoke;
import javax.ejb.InvocationContext;

public class Interceptor2 {

@AroundInvoke
public Object log(InvocationContext invocationContext) throws Exception {
System.err.println(invocationContext.getMethod().getName() + " called from interceptor 2");
return invocationContext.proceed();
}

}

Testing the Example

The classes shown above can be packaged as a jar file and deployed to your application Server domain. The EJB is annotated with the @WebService annotation and the methods are annotated with the @WebMethod annotation, you can easily test the method invocations.

Cloud vs. Cloud Native

Introduction These days everyone is moving “On cloud”. Having many cloud vendors with lucrative offers of TCO reduction, does deploying yo...