The Source for Java Technology Collaboration
User: Password:



Meeraj Kunnumpurath

Meeraj Kunnumpurath's Blog

Interceptors with EJB 3

Posted by meeraj on January 25, 2006 at 04:15 AM | Comments (4)

I have been having a look at EJB 3.0 interceptors with Glassfish. 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 <methodName>(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.acme.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.acme.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.acme.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 using Glassfish

    The classes shown above can be packaged as a jar file and copied to the auto deploy directory of your Glassfish 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 using the Glassfish console.


    Bookmark blog post: del.icio.us del.icio.us Digg Digg DZone DZone Furl Furl Reddit Reddit
    Comments
    Comments are listed in date ascending order (oldest first) | Post Comment

    • Hi Meeraj,

      very clear article, but I have some problems implementing my own interceptors.

      I’m trying the method level interceptors. The thing is that interceptors work pretty well for methods that are the entry point of the execution flow in the class, but if those methods call other methods in the class, these calls are not intercepted.

      Is there anything that I’m missing?

      This an example of the code I’m referring to:

          @Interceptors({
      com.care.library.service.impl.interceptors.BookPreconditions.class})
          @TransactionAttribute(value=TransactionAttributeType.SUPPORTS)
          public BookOID create_instance1(ServiceContext serCtx, String pt_isbn, String pt_title, Integer pt_author) {
              Author author_pt_author = authorData.find(pt_author);
              Book book = this.create_instance2(serCtx, pt_isbn, pt_title, author_pt_author);
              return book.getOid();
          }
      
          @TransactionAttribute(value=TransactionAttributeType.REQUIRED)
          public Book create_instance2(ServiceContext serCtx, String pt_isbn, String pt_title, Author pt_author) {
              Book book = this.create_instance3(serCtx, pt_isbn, pt_title, pt_author);
              return book;
          }
      
      
          @Interceptors({
      com.care.library.service.impl.interceptors.BookPreconditions.class})
          public Book create_instance3(ServiceContext serCtx, String pt_isbn, String pt_title, Author pt_author) {
              Book book = bookData.create(pt_isbn, pt_title, pt_author);
              return book;
          }
      

      And the interceptor

      public class BookPreconditions {
          /* logging service */
          private static final Logger LOGGER = Logger.getLogger(BookPreconditions.class.getName());
      
          @AroundInvoke
          public Object preconditionInterceptor(InvocationContext ctx) throws Exception
          {
              LOGGER.info("Preconditions Check...[" + ctx.getMethod().getName() + "]");
              if (ctx.getMethod().getName().equals("create_instance3")) {
                  create_instance(ctx);
              }
              return ctx.proceed();
          }
      

      The method create_instance1 is being intercepted while the method create_instance3 is not. Why?

      ..:: Carlos ::..

      Posted by: cgarcia on May 08, 2006 at 10:26 AM

    • Excellent tutorial, Meeraj. Do you have any references or pointers to other resources on Interceptors?

      Posted by: rudradixit on April 20, 2007 at 07:20 AM

    • I dont know if its possible but I'm trying to use EJB3 logging interceptor to work on non-EJB classes like struts actions and DAOs. Is it possible?

      Posted by: sim4life on July 05, 2007 at 12:56 AM

    • Hi, I even have similar problem. Meeraj, can you please comment on the above issue ? Many Thanks, Praveen

      Posted by: praveen_dvk on March 27, 2008 at 04:41 PM



    Only logged in users may post comments. Login Here.


    Powered by
    Movable Type 3.01D
     Feed java.net RSS Feeds