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:
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:
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”:
After clicking “Finish”, go to the project Explorer and Right click on the Project InterceptorTesting
and go to Properties-> Deployment Assembly -> Add -> Porject -> EJBInterceptorEAR
:
6. Create new Servlet
Go to InterceptorTesting
Web project and create a new Servlet named TestSerlvet
:
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
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.
Great article to understand interceptors.
Good luck,
Fatih
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.