Enterprise Java

Java EE EJB Interceptors tutorial and example

In this example we are going to see how to use Interceptors in an EJB and test it using a simple Web Application.

1. Introduction

Interceptors are used, as the name suggests, when you want to intercept calls to EJB methods. If you declare an Interceptor for a Bean, every time a method of that Bean is invoked, it will be intercepted with one method of the Interceptor. That means that the execution goes straight to the Interceptor’s method. The intercepting method then, can decide whether to call the intercepted EJB method or simply replace it.

You might find the above behavior resembling the Aspect Oriented Programming philosophy, and you’d be correct. Despite the fact that the implementation of the two technologies is completely different, the truth is they can be used for the same purposes. For example, when you want to log something before of after a Beans method is executed. Or when you want to enforce a specific policy concerning method calls, e.g. authentication, input checking etc. Of course an EJB can have a chain of Interceptors that will intercept the method in a specific order.

In this example we are going to create an EAR Project and an EJB Project that will host our EJBs and Interceptors and a Dynamic Web Application that will host a Servlet to test the aforementioned behavior. We are going to use Eclipse Java EE IDE 4,3 Kepler and Glassfish 4.0 as our container.

2. Create a new Enterprise Application Project

Create a new Enterprise Application Project named EJBInterceptorEAR .In Eclipse IDE select File -> New -> Enterprise Application Project and fill in the form and click Finish:

new-ear-project

3. Create a new EJB Projet

Create a new EJB Project called InterceptorsEJB. We are going to create our session bean on this. Go to File -> New -> EJB Project and fill out the form. Be careful to select “Add EAR Project” and Select “EJBInterceptorEAR” as EAR project name:

new-ejb-projecct

Click Next twice and choose to create EJB Client JAR, as well as to generate the ejb-jar.xml deployment descriptor :

4. Create a simple Interceptor class

We are going to define a simple Interceptor, which has only one method. In InterceptorsEJB project under ejbModule folder create a new package called com.javacodegeeks.enterprise.ejb.interceptor and create the following class:

SimpleInterceptor.java:

package com.javacodegeeks.enterprise.ejb.interceptor;

import javax.interceptor.AroundInvoke;
import javax.interceptor.InvocationContext;

public class SimpleInterceptor {

	@AroundInvoke
	public Object intercept(InvocationContext context) throws Exception {

		System.out.println("SimpleInterceptor - Logging BEFORE calling method :"+context.getMethod().getName() );

		Object result = context.proceed();

		System.out.println("SimpleInterceptor - Logging AFTER calling method :"+context.getMethod().getName() );

		return result;
	}
}

Note that public Object intercept in annotated with @AroundInvoke. This means that this specific method will intercept on the EJB method call. It is important to address the the fact that an interceptor class can have any number of methods, but only one can be annotated with @AroundInvoke.

You can use the InvocationContext argument of the intercept method for two purposes. You can either extract useful information concerning the EJB method that is being intercepted (for example we used getMethod().getName() API call chain to obtain the name of the intercepted method), or you can continue the execution using proceed() API method. This method will switch the execution flow to the next interceptor in the chain, or to the actual intercepted EJB method, if there are no interceptors left in the chain. This method will return the result of the EJB method call. But we don’t know the returning type, thus proceed() returns an Object instance. If you do know the returning type of the EJB method you can cast the result of proceed() to that particular type, and then use that instance as you wish. Notice that intercept method also returns the result of the actual EJB call. This will be either passed to the next interceptor in the Interceptor chain, or to the client if there is no other interceptors left.

So, any business logic you want to execute before calling the actual EJB method should be placed before calling proceed(). Consequently, you put the code you want to execute after the execution of the actual EJB method, after calling proceed(). Of course you could bypass the normal execution of the EJB method all together if you want.

4. Create a simple EJB

Here is the EJB that will use the above Interceptor to intercept it’s methods. In InterceptorsEJB project under ejbModule folder create a new package called com.javacodegeeks.enterprise.ejb and create the following class:

package com.javacodegeeks.enterprise.ejb;

import javax.ejb.Stateless;
import javax.interceptor.Interceptors;

import com.javacodegeeks.enterprise.ejb.interceptor.SimpleInterceptor;

@Stateless
@Interceptors(SimpleInterceptor.class)
public class SimpleEJB {

	public String printMessage(String message) {

		System.out.println(" Executing method : printMessage" + message);
		return "Message is "+message;
	}

}

As you can see we’ve marked the class with @Interceptors(SimpleInterceptor.class) annotation. This means that all methods of this class will be intercepted by SimpleInterceptor

Let’s create a simple Servlet to test the desired functionality.

5. Create a new Dynamic Web Project

Go to File -> New -> Dynamic Web Project. Fill out the form and make sure you check “Add project to an EAR” and put EJBInterceptorEAR as the “EAR project name”:

new-dynamic-web-application

After clicking “Finish”, go to the project Explorer and Right click on the Project InterceptorTesting and go to Properties-> Deployment Assembly -> Add -> Porject -> EJBInterceptorEAR :

deployment-assembly

6. Create new  Servlet

Go to InterceptorTesting Web project and create a new Servlet named TestSerlvet:

new-serlvet

Let’s see the code of that Servlet:

TestServlet.java:

package com.javacodegeeks.enterprise.servlet;

import java.io.IOException;

import javax.naming.InitialContext;
import javax.naming.NamingException;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import com.javacodegeeks.enterprise.ejb.SimpleEJB;

@WebServlet("/TestSerlvet")
public class TestSerlvet extends HttpServlet {
	private static final long serialVersionUID = 1L;

	public TestSerlvet() {
		super();

	}

	protected void doGet(HttpServletRequest request,
			HttpServletResponse response) throws ServletException, IOException {
		System.out.println("Hello from Servlet");

		InitialContext ic;
		SimpleEJB bean;

		String message = request.getParameter("printMessage");

		if (message != null) {

			try {

				ic = new InitialContext();
				bean = (SimpleEJB) ic
						.lookup("java:global/EJBInterceptorEAR/InterceptorTesting/SimpleEJB!"
								+ "com.javacodegeeks.enterprise.ejb.SimpleEJB");

				bean.printMessage(message);

			} catch (NamingException e) {

				e.printStackTrace();
			}
		}
	}
}

As you can see we simple parse a printMessage query parameter and we pass its value to the printMessage method of SimpleEJB.

Tip: If you are having trouble figuring out the Portable JNDI names for EJB PassivationObject look at the logs or output of Glassfish when deploying the project and you will find a line like this :2014-01-09T15:14:14.627+0200|INFO: EJB5181:Portable JNDI names for EJB SimpleEJB:java:global/EJBInterceptorEAR/InterceptorTesting/SimpleEJB!
com.javacodegeeks.enterprise.ejb.SimpleEJB,java:global/EJBInterceptorEAR/InterceptorTesting/SimpleEJB)

7. Test

You can deploy your Application on Glassfish and issue the following request:

http://localhost:8080/InterceptorTesting/TestSerlvet?printMessage=Hello%20From%20JCG

If you watch the output of Glassfish on the console you will see:

2014-01-09T17:43:14.356+0200|INFO: Hello from Servlet
2014-01-09T17:43:14.357+0200|INFO: Logging BEFORE calling method :printMessage
2014-01-09T17:43:14.357+0200|INFO: Executing method : printMessage : Hello From JCG
2014-01-09T17:43:14.357+0200|INFO: Logging AFTER calling method :printMessage

8. Multiple Interceptors

Go ahead and create another new Interceptor in InterceptorsEJB project under com.javacodegeeks.enterprise.ejb.interceptor package.

Here it is :

SecondInterceptor.java:

package com.javacodegeeks.enterprise.ejb.interceptor;

import javax.interceptor.AroundInvoke;
import javax.interceptor.InvocationContext;

public class SecondInterceptor {

	@AroundInvoke
	public Object intercept(InvocationContext context) throws Exception {

		System.out.println("SecondInterceptor - Logging BEFORE calling method :"+context.getMethod().getName() );

		Object result = context.proceed();

		System.out.println("SecondInterceptor  -Logging AFTER calling method :"+context.getMethod().getName() );

		return result;
	}
}

And here is SimpleEJB.

SimpleEJB.java:

package com.javacodegeeks.enterprise.ejb;

import javax.ejb.Stateless;
import javax.interceptor.Interceptors;

import com.javacodegeeks.enterprise.ejb.interceptor.SecondInterceptor;
import com.javacodegeeks.enterprise.ejb.interceptor.SimpleInterceptor;

@Stateless
@Interceptors({SimpleInterceptor.class, SecondInterceptor.class})
public class SimpleEJB {

	public String printMessage(String message) {

		System.out.println(" Executing method : printMessage" + message);
		return "Message is "+message;
	}

}

Now, if we issue the same request again:

http://localhost:8080/InterceptorTesting/TestSerlvet?printMessage=Hello%20From%20JCG

If you watch the output of Glassfish on the console you will see:

2014-01-09T17:59:55.647+0200|INFO: Hello from Servlet
2014-01-09T17:59:55.659+0200|INFO: SimpleInterceptor - Logging BEFORE calling method :printMessage
2014-01-09T17:59:55.659+0200|INFO: SecondInterceptor - Logging BEFORE calling method :printMessage
2014-01-09T17:59:55.660+0200|INFO: Executing method : printMessageHello From JCG
2014-01-09T17:59:55.660+0200|INFO: SecondInterceptor  -Logging AFTER calling method :printMessage
2014-01-09T17:59:55.660+0200|INFO: SimpleInterceptor  -Logging AFTER calling method :printMessage

9. Method level interceptors

Sometimes it’s possible that you don’t want all of your bean methods to get intercepted. You can choose which methods to intercept by annotating them, and not the entire class.

Let’s see how:

SimpleEJB.java:

package com.javacodegeeks.enterprise.ejb;

import javax.ejb.Stateless;
import javax.interceptor.Interceptors;

import com.javacodegeeks.enterprise.ejb.interceptor.SimpleInterceptor;

@Stateless
public class SimpleEJB {

	@Interceptors(SimpleInterceptor.class)
	public String printMessage(String message) {

		System.out.println(" Executing method : printMessage : " + message);
		return "Message is " + message;
	}

	public String printSomething(String message) {

		System.out.println(" Executing method : printSomething :" + message);
		return "Message is " + message;
	}

}

TestServlet.java:

package com.javacodegeeks.enterprise.servlet;

import java.io.IOException;

import javax.naming.InitialContext;
import javax.naming.NamingException;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import com.javacodegeeks.enterprise.ejb.SimpleEJB;

@WebServlet("/TestSerlvet")
public class TestSerlvet extends HttpServlet {
	private static final long serialVersionUID = 1L;

	public TestSerlvet() {
		super();

	}

	protected void doGet(HttpServletRequest request,
			HttpServletResponse response) throws ServletException, IOException {
		System.out.println("Hello from Servlet");

		InitialContext ic;
		SimpleEJB bean;

		String message = request.getParameter("printMessage");

		if (message != null) {

			try {

				ic = new InitialContext();
				bean = (SimpleEJB) ic
						.lookup("java:global/EJBInterceptorEAR/InterceptorTesting/SimpleEJB!"
								+ "com.javacodegeeks.enterprise.ejb.SimpleEJB");

				bean.printMessage(message);

				bean.printSomething("This method is not intercepted");

			} catch (NamingException e) {

				e.printStackTrace();
			}
		}

	}

}

Now, if we issue the same request again:

http://localhost:8080/InterceptorTesting/TestSerlvet?printMessage=Hello%20From%20JCG

If you watch the output of Glassfish on the console you will see:

2014-01-09T19:52:00.909+0200|INFO: Hello from Servlet
2014-01-09T19:52:00.920+0200|INFO: SimpleInterceptor - Logging BEFORE calling method :printMessage
2014-01-09T19:52:00.921+0200|INFO: Executing method : printMessage : Hello From JCG
2014-01-09T19:52:00.921+0200|INFO: SimpleInterceptor  -Logging AFTER calling method :printMessage
2014-01-09T19:52:00.921+0200|INFO: Executing method : printSomething :This method is not intercepted

Download Eclipse Project

This was an example on EJB Interceptors. Download the Eclipse Projects of this tutorial : EJBInterceptor.zip

Nikos Maravitsas

Nikos has graduated from the Department of Informatics and Telecommunications of The National and Kapodistrian University of Athens.
Subscribe
Notify of
guest

This site uses Akismet to reduce spam. Learn how your comment data is processed.

3 Comments
Oldest
Newest Most Voted
Inline Feedbacks
View all comments
Leandro Souza
Leandro Souza
10 years ago

in “5. Create a new Dynamic Web Project” no need add EJBInterceptorEJB and EJBInterceptorEJBClient like “Deployment Assembly” only “java build path” -> project
if add like “Deployment Assembly” “SimpleEJB” will be deployed twice, in “java:global/EJBInterceptorEAR/InterceptorTesting/SimpleEJB” and “java:global/EJBInterceptorEAR/InterceptorsEJB/SimpleEJB”

Sorry for my english.

Fatih
9 years ago

Great article to understand interceptors.

Good luck,
Fatih

Schaun Patrick
Schaun Patrick
8 years ago

Great article! There is a typo however. You used TestSerlvet instead of TestServlet. Eclipse pointed that out for me and I had to modify the URL as well to remove the typo. Thanks for article it was very clear on using interceptors.

Back to top button