Free Online Courses for Software Developers - MrBool
× Please, log in to give us a feedback. Click here to login
×

You must be logged to download. Click here to login

×

MrBool is totally free and you can help us to help the Developers Community around the world

Yes, I'd like to help the MrBool and the Developers Community before download

No, I'd like to download without make the donation

×

MrBool is totally free and you can help us to help the Developers Community around the world

Yes, I'd like to help the MrBool and the Developers Community before download

No, I'd like to download without make the donation

Design Patterns: Working with Interceptor in Java EE Platform

See in this article what is the design pattern Interceptor, how it is implemented in pure code (POJOs) and how we can implement this pattern in the Java EE 7 platform.

A very important concept when studying the interceptors is the Aspect-oriented Programming or AOP, which, although not described in the GoF book and not being a classic pattern of the literature, it introduced a new concept and new paradigm for programming. The idea behind is to base code execution order through aspects. Thus, every aspect intercepts the implementation of the program and add your own behavior before proceeding with the call. Aspects basically add logic and behavior for runtime code. However, this technique also brings an execution order rather difficult to debug code.

Despite the AOP has many followers, the Java EE platform has a fairly clean implementation that can be very useful for many developers. In the rest of the article will be seen what is the aspect-oriented programming and how the interceptors can be implemented using AOP technique.

Aspect-Oriented Programming

The aspect-oriented programming aims to add behavior to existing codes or to applications to address particular problems. The AOP has become a popular paradigm in the past decade and with it came many third-party frameworks that offers it. Among these frameworks stand out from the AspectJ and Spring. Both AspectJ and Spring are widely accepted and have been used for a long time in Java projects. Java SE also has a similar approach, but more basic by using servletfilters, besides this approach is limited for web requests. Using these filters, any request or response can be intercepted, and therefore, any behavior can be added. The Java EE 7Platformalso adopted the AOP and introduced the concept of interceptors.

AOP is not classified as a design pattern, but is accepted as a programming paradigm, so it is not found in the reference literature, such as the GoF book, nor in other design patterns books.

The literature states that the AOP is basically the injection of code during compile or execution time to add the desired behavior or functionality.

The Frameworks performing compile time injection alter the file ".class". The problem is that this file becomes incompatible with the source code because of this code that was injected. On the other hand, the run-time injection does not modify the source code or the file ".class". This injection is performed by intercepting calls and implementation of the desired code before or after the original order of execution. This will be exemplified further when discussing the Java EE platform.

AOP is very useful for adding repetitive actions such as logging or security for a code, making it a great tool to encapsulate concepts that do not involve the business. The disadvantage of AOP is that its implementation causes decentralization and distribution, thus making it difficult to test and debug the code.

Aspects can be turned on or off, which is interesting depending on the environment or design phase.

The rest of the article shows practically the operating of Interceptor pattern.

Implementing Interceptors in Pure Code (POJO)

Java SE supports all AOP features only through third-party frameworks using AspectJ or Spring. They are also an alternative implementation of the Java EE. However, Java Web applications have advantages when using Servlets to intercept requests or responses. To implement a servlet filter simply create a new class and implement the filterinterface and after, you must implement the doFilter() method, as shown in the example in Listing 1.

Listing 1. Implementing a Servlet Filter.

package com.mrbool.interceptor.filter;

import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import javax.servlet.Filter;
import javax.servlet.FilterChain;
import javax.servlet.FilterConfig;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

public class SecurityFilter implements Filter {

	   @SuppressWarnings("unused")
	   private FilterConfig filterConfig = null;

	   // doFilter() implementation
	   @Override
	   public void doFilter(ServletRequest request, ServletResponse response,
			 FilterChain filterChain) throws IOException, ServletException {

			 Log.info(((HttpServletRequest) request).getRemoteAddr());

			 // run some security checking here
	   }

	   @Override
	   public void init(FilterConfig filterConfig) throws ServletException {
			 this.filterConfig = filterConfig;
	   }
}

In addition to the above code, the web container also need the web.xml file settings shown in the code in Listing 2.

Listing 2. Setting up the filter mappings in the web.xml file.

<?xml version= "1.0" encoding="UTF-8" ?>
<web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
	xmlns="http://java.sun.com/xml/ns/javaee"
	xmlns:web="http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd"
	xsi:schemaLocation="http://java.sun.com/xml/ns/javaee
	http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd" version="3.0">


	   <filter>
		 <filter-name>SecurityFilter</filter-name>
		 <filter-class>com.mrbool.interceptor.filter.SecurityFilter</filter-class>
	   </filter>


	   <filter-mapping>
		 <filter-name>SecurityFilter</filter-name>
		 <url-pattern>/*</url-pattern>
	   </filter-mapping>
</web-app>

As you can see, this XML file is the mapping of the URLs to specific classes in Java.

In Java EE 7 platform is even simpler to implement the filters by simply using annotations, as the example in Listing 3.

Listing 3. Implementing a filter in Java EE 7 Platform

package com.mrbool.interceptor.filter;

import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.Filter;
import javax.servlet.annotation.WebFilter;
import javax.servlet.annotation.WebInitParam;

@WebFilter(filterName = "SecurityFilter", urlPatterns = {"/*"})
public class SecurityFilter implements Filter {

	   @Override
	   public void doFilter(ServletRequest request, ServletResponse response,
		 FilterChain filterChain) throws IOException, ServletException {

		 Log.info(((HttpServletRequest) request).getRemoteAddr());

		 // run some security checking here
	   }
}

Although simple to implement, the filters are widely used in business applications. Unfortunately, however, the filters are limited only to web requests. To intercept other method calls you need to use another form, such as CDI or EJBs as discussed in the next section.

Implementing Interceptors in the Java EE platform

Interceptors were introduced in Java EE from version 5, but in the Java EE 5 platform interceptors were limited to Enterprise JavaBeans (EJB). In the Java EE 7 platform, with the introduction of Context and Dependency Injection (CDI), interceptors do not need more of EJBs to be used.

In a similar way to the interceptors used in the Java SE platform, each interceptor has a block of code to be added. The destination to be decorated is called "Advice". Each call to an "Advice" into the interceptor scope is intercepted. The exact location of the point to be executed is called "pointcut".

Basic interceptors can only work with EJBs. An example of use of an interceptor would be in an application with hundreds of EJBs and we configure the application to log all EJB calls through a deploy of an interceptor to the target pointing to all the EJBs.

Implementing an interceptor in Java EE is straightforward. First, you need to create a new interceptor class and annotate it with the @Interceptor annotation. Any method annotated with @AroundInvoke runs on pointcut (exact aspect place to run). However, there are some syntax rules for thepointcut method signature. The first rule says that any pointcut method should return an Object type object and have a parameter of type InvocationContext, and the second rule says that the pointcut method should throw an exception.

Thus, it can be used InvocationContext parameter to access information about the current context. Listing 4 follows an example of how this functionality can be performed.

Listing 4. Implementation of an interceptor in the Java EE platform.

package com.mrbool.interceptor;

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

@Interceptor
public class SecurityInterceptor {

	   @AroundInvoke
	   public Object checkSecurity(InvocationContext context) throws Exception {
		 Logger.getLogger("SecurityLog").info(context.getMethod().getName() + " was accessed!");

		 return context.proceed();
	   }
}

To put the interceptor class in action is necessary to annotate the Advice class destination with the @Interceptors annotation. The @Interceptors annotation should be used only in one EJB or MDB (Message Driven Bean).

Follows in Listing 5 an example of implementing an Advice.

Listing 5. Implementation of the Advice destination.

package com.mrbool.interceptor;

import javax.ejb.Stateless;
import javax.ejb.TransactionAttribute;
import javax.ejb.TransactionAttributeType;
import javax.enterprise.event.Event;
import javax.inject.Inject;
import javax.interceptor.Interceptors;

@Interceptors(SecurityInterceptor.class)
@Stateless
@TransactionAttribute(TransactionAttributeType.REQUIRED)
public class BusinessServiceExample {

	   public void startBusinessService() {
		System.out.println("Example of business service intercepted.");
	   }

	   public void startOtherBusinessService() {
		System.out.println("Example of other business service intercepted.");
	   }
}

The Interceptors annotation is very flexible and can be used in class level and method level. The Interceptors annotation also supports multiple interceptors entries, which allows you to enable multiple interceptors in Advice destination.

The above example used interceptors at class level, which means that the interceptor SecurityInterceptor willintercept any one of the service calls. If it is not necessary to intercept all the calls methods in the class, annotationscan be usedon method level as the example in Listing 6.

Listing 6. Example of interception at method level.

package com.mrbool.interceptor;

import javax.ejb.Stateless;
import javax.ejb.TransactionAttribute;
import javax.ejb.TransactionAttributeType;
import javax.enterprise.event.Event;
import javax.inject.Inject;
import javax.interceptor.Interceptors;

@Stateless
@TransactionAttribute(TransactionAttributeType.REQUIRED)
public class BusinessServiceExample {

	   @Interceptors(SecurityInterceptor.class)
	   public void startBusinessService() {
		System.out.println("Example of business service intercepted.");
	   }

	   public void startOtherBusinessService() {
		System.out.println("Example of other business service intercepted.");
	   }
}

In the example above only calls for startBusinessService() method are intercepted, differently from the previous list where all the methods of the class are intercepted. Each method should be annotated separately.

Besides the seen annotations, it can be used the InvocationContext interface to extract context information or interact with the Advice context. Follows in Table 1 the most useful methods used in the InvocationContext interface.

Method

Description

public Object getTarget();

Returns the Advice destination.

public Method getMethod();

Returns the method executed by the Advice.

public Object[] getParameters();

Access the method parameters of theAdvice.

public void setParameters(Object[]);

Configure the method parameters of theAdvice.

public java.util.Map getContextData();

Access the context info.

public Object proceed() throws

Exception;

Continue the execution.

Table 1. Description of the InvocationContext interface methods.

In the example in Listing 7 the method name is accessed. Moreover, it is checked whether the interceptor had authorized access to the user previously, if it was not the user is authorized to access this method.

Listing 7. Accessing information in the InvocationContext.

package com.mrbool.interceptor;

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

@Interceptor
public class SecurityInterceptor {

	   @AroundInvoke
	   public Object checkSecurity(InvocationContext context) throws Exception {
			 System.out.println(context.getMethod().getName() + " was accessed!");

			 String user = context.getContextData.get("user");

			 if (user == null) {
				  user = (String) context.getParameters()[0];
				  context.getContextData.put("user", user);
			 }

			 return context.proceed();
	   }
}

Another way to use interceptors is using CDI. Before the rise of the CDI, the interceptors were applicable only for EJBs and MDBs. The CDI has a enormous power and made possible interceptors working on any object.

The deployment of interceptors using CDI is straightforward and flexible. First you need to specify a "binding" (or a link) which is a customized annotation annotated with @InterceptorBinding. Follows an example in Listing 8.

Listing 8. Implementing interceptor using CDI.

@InterceptorBinding 
@Target({TYPE, METHOD}) 
@Retention(RUNTIME) 
public @interface Security {}

The @InterceptorBinding annotation is used to bind interceptors with a destination code. It can then be implemented and annotated the interceptor with a custom binding. The CDI interceptors are implemented in the same way as EJB interceptors, the only significant difference is the annotation as can be seen in the example shown in Listing 9.

Listing 9. Linking an interceptor with @Security.

package com.mrbool.interceptor;

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

@Security
@Interceptor
public class SecurityInterceptor {

	   @AroundInvoke
	   public Object checkSecurity(InvocationContext context) throws Exception {
		 System.out.println(context.getMethod().getName()+ " was accessed!");

		 String user = context.getContextData.get("user");

		 if (user == null) {
			  user = (String) context.getParameters()[0];
			  context.getContextData.put("user", user);
		 }

		 return context.proceed();
	   }

	   @PostConstruct
	   public void activate(){
		 System.out.println("Activating...");
	   }

	   @PreDestroy
	   public void desactivate(){
		System.out.println("Desactivating...");
	   }
}

Just as EJB interceptors, the @Interceptor annotation must be used to promote the class for an interceptor. The @Security annotation links the interceptor. Finally, the @AroundInvoke annotation marks the method that will be executed during the intercepted calls. The next step is to write down the interceptor on an Advice, as the example in Listing 10.

Listing 10. Implementing the interceptor @Securityon an Advice.

package com.mrbool.interceptor;

import javax.interceptor.Interceptors;

@Security
public class BusinessServiceExample {

	   public void startBusinessService() {
		System.out.println("Example of business service intercepted.");
	   }

	   public void startOtherBusinessService() {
		System.out.println("Example of other business service intercepted.");
	   }
}

CDI interceptors require an additional step which is to declare the interceptors in a beans.xml file. This step is used to determine the execution order of the interceptors. The CDI container does not start if the beans.xml file is missing.

Follows in Listing 11an example of beans.xml file.

Listing 11. Example of beans.xml file with two declared interceptors.

<beans xmlns="http://java.sun.com/xml/ns/javaee"
	xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
	xsi:schemaLocation=" http://java.sun.com/xml/ns/javaee
	http://java.sun.com/xml/ns/javaee/beans_1_0.xsd">

	   <interceptors>
		 <class>com.mrbool.interceptor.SecurityInterceptor</class>
		 <class>com.mrbool.interceptor.OtherInterceptor</class>
	   </interceptors>
</beans>

Conclusion

The interceptor order of execution depends on the order of the declaration in beans.xml file, so only this file is responsible for dictating the execution order of interceptors.

A situation that can occur is a mixture of CDI and EJB interceptors, in which case the EJB interceptors perform before the CDI interceptors.

If you need to make this mixture of CDI interceptors with EJB you should know that this brings more complexity to the application, especially in application architecture, and with it, developers who are not familiar with the code may have problems in understanding and coding the application.



Fabrí­cio Galdino is a software expert and has worked with IT analysis and business development for more than five years. It has extensive experience with testing, back and front-end technologies.

What did you think of this post?
Services
[Close]
To have full access to this post (or download the associated files) you must have MrBool Credits.

  See the prices for this post in Mr.Bool Credits System below:

Individually – in this case the price for this post is US$ 0,00 (Buy it now)
in this case you will buy only this video by paying the full price with no discount.

Package of 10 credits - in this case the price for this post is US$ 0,00
This subscription is ideal if you want to download few videos. In this plan you will receive a discount of 50% in each video. Subscribe for this package!

Package of 50 credits – in this case the price for this post is US$ 0,00
This subscription is ideal if you want to download several videos. In this plan you will receive a discount of 83% in each video. Subscribe for this package!


> More info about MrBool Credits
[Close]
You must be logged to download.

Click here to login