Monday May 10, 2010

TOTD #134: Interceptors 1.1 in Java EE 6 - What and How ?

TOTD #129 explained Managed Beans 1.0, this Tip Of The Day (TOTD) attempts to explain the basics of Interceptors 1.1 - a "new" specification introduced in the Java EE 6.

The specification is not entirely new as the concept is borrowed from the EJB 3.0 specification and abstracted at a higher level so that it can be more generically applied to a broader set of specifications in the platform. Interceptors do what they say - they intercept on invocations and lifecycle events on an associated target class. Basically, interceptor is a class whose methods are invoked when business methods on the target class are invoked and/or lifecycle events such as methods that create/destroy the bean occur. Interceptors are typically used to implement cross-cutting concerns like logging, auditing, and profiling.

Contexts and Dependency Injection (CDI, aka JSR 299) uses the concept defined by Interceptors 1.1 and adds the notion of interceptors binding.

Let see some code to make it all clear.

Each interceptor require at least one interceptor binding to associate with the target class. An interceptor binding is defined as:

import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
import javax.interceptor.InterceptorBinding;

@InterceptorBinding
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.METHOD, ElementType.TYPE})
public @interface MyInterceptorBinding {
}

And then the interceptor is defined as:

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

@Interceptor
@MyInterceptorBinding
public class MyInterceptor {

    @AroundInvoke
    public Object intercept(InvocationContext context) throws Exception {
        System.out.println("before interception");
        Object result = context.proceed();
        System.out.println("after interception");

        return result;
    }
}

The "@AroundInvoke" annotation (can be only one per interceptor) on a method in the interceptor class ensures that this method is invoked around the business method interception. This will be more clear after the program flow is explained later. Multiple interceptors can be chained and the flow/outcome may be diverted in any of them using "InvocationContext".

The associated target bean looks like:

. . .
import javax.interceptor.Interceptors;

@ManagedBean(value="mybean")
@Interceptors(MyInterceptor.class)
public class MyManagedBean {
    @PostConstruct
    public void setupResources() {
        // setup your resources
        System.out.println("Setting up resources ...");
    }

    . . .

}

The only missing part on the server-side is enabling bean discovery by adding an empty "beans.xml" as:

<?xml version="1.0" encoding="UTF-8"?>
<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">
</beans>

Notice, there is no need to explicitly mention <interceptors> in "beans.xml". Multiple interceptors on a bean can be easily defined as:

@ManagedBean(value="mybean")
@Interceptors({MyInterceptor.class, MyInterceptor2.class})
public class MyManagedBean {

Lets see how this bean and interceptor can be used. Create a Servlet as:

@WebServlet(name="TestServlet", urlPatterns={"/TestServlet"})
public class TestServlet extends HttpServlet {

Inject a bean as ...

@Inject
MyManagedBean bean;

and then invoke the bean's method in "doGet" or "doPost" methods of the servlet as:

String result = bean.sayHello("Duke");

Notice that @Inject is used to inject the managed bean and bean discovery is enabled by adding an empty "beans.xml". This ensures that CDI inject works as expected and all the interceptors are invoked as well. Another alternative is to inject the bean using @Resource but "beans.xml" need to be removed in order for the interceptors to be invoked. So inject your bean using @Inject + "beans.xml" or @Resource. The recommended approach is to use @Inject + "beans.xml" as CDI might be used in other parts of your applications as well.

If 2 interceptors, each with a separate interceptor binding, managed bean class, and the servlet is included in a web application then the directory structure will look like:

./META-INF
./META-INF/MANIFEST.MF
./WEB-INF
./WEB-INF/beans.xml
./WEB-INF/classes
./WEB-INF/classes/server
./WEB-INF/classes/server/MyInterceptor.class
./WEB-INF/classes/server/MyInterceptor2.class
./WEB-INF/classes/server/MyInterceptorBinding.class
./WEB-INF/classes/server/MyInterceptorBinding2.class
./WEB-INF/classes/server/MyManagedBean.class
./WEB-INF/classes/server/TestServlet.class

If there are "System.out.println"s inserted at relevant positions in the interceptor and the Servlet code, then the code flow looks like:

Before Intercept
Before Intercept2
sayHello
After Intercept2
After Intercept
processRequest

"Before XXX" messages are printed by a method from the interceptors, in the order of chaining, before "context.proceed" is invoked in all the interceptors. "sayHello" method is invoked from the "doGet" or "doPost" method in the Servlet. "After XXX" messages are printed from the interceptors after "context.proceed" method is invoked, this time in the reverse order of chain. And finally "processRequest" method is invoked again from the "doGet" or "doPost" method in the Servlet.

The complete source code for the sample explained above can be downloaded here.

Technorati: javaee glassfish v3 managedbeans interceptors cdi ejb servlet

Sunday Apr 18, 2010

TOTD #129: Managed Beans 1.0 in Java EE 6 - What and How ?

Two new specifications released as part of the Java EE 6 platform are Managed Beans 1.0 and Interceptors 1.1. This Tip Of The Day (TOTD) attempts to explain the basics of Managed Beans 1.0. A later blog will explain the what/how of Interceptors 1.1.

A short definition for a managed bean - its a POJO that is treated as managed component by the Java EE container.

There are several component specifications in the Java EE platform that annotates a POJO to achieve the desired functionality. For example, adding "@Stateful" annotation to a POJO makes it a stateful EJB. Similarly adding "@javax.faces.bean.ManagedBean" to a POJO makes it a JSF managed bean. Java EE 6 introduces a new specification - "Managed Beans 1.0" that provides a common foundation for the different kinds of component that exist in the Java EE platform. In addition, the specification also defines a small set of basic services:

  • Resource Injection
  • Lifecycle callbacks
  • Interceptors

The different component specifications can then add other characteristics to this managed bean. The specification even defines well known extension points to modify some aspects. For example CDI/JSR 299 relaxes the requirement to have a POJO with no-args constructor and allow constructor with more complex signatures. CDI also adds support for lifecycle scopes and events. Similarly EJB is a managed bean and adds support for transactions and other services.

A managed bean is created by adding "javax.annotation.ManagedBean" annotation as:

@javax.annotation.ManagedBean(value="mybean")
public class MyManagedBean {
  ...
}

The standard annotations "javax.annotation.PostConstruct" and "javax.annotation.PreDestroy" from the JSR 250 can be applied to any methods in the managed bean to perform any resource initialization or clean up by the managed bean. A bean with lifecycle callbacks can look like:

@ManagedBean(value="mybean")
public class MyManagedBean {
  @PostConstruct
  public void setupResources() {
    // setup your resources
    System.out.println("Setting up resources ...");
  }

  @PreDestroy
  public void cleanupResources() {
     // collect them back here
    System.out.println("Collecting them back ...");
  }

  public String sayHello(String name) {
    return "Hello " + name;
  }
}

This bean can be injected in a Servlet or any other managed component in three different ways:

  1. Using @Resource annotation as:

    @Resource
    MyManagedBean bean;
  2. Using "@Inject" annotation as:

    @Inject
    MyManagedBean bean;
  3. Using the JNDI reference "java:app/ManagedBean/mybean" or "java:module/mybean" where "ManagedBean" is name of the deployed archive (WAR in this case), shown as:

    InitialContext ic = new InitialContext();
    MyManagedBean bean = (MyManagedBean)ic.lookup("java:module/mybean");


    Its important to provide a name to the managed bean, as there is no default name, for the JNDI reference to work. EJB and CDI specifications extend this rule and provide default naming rules.

Once the bean is injected then its business methods can be invoked directly.

As part of Java EE 6, all EJB and CDI beans are defined as managed beans and so:

@Stateless
public class FooBean {
    . . .
}

and

@Named
public class BarBean {
    . . .
}

are implicitly managed beans as well.

No other beans in the Java EE platform are currently implicitly defined as managed beans. However JAX-RS resources can also be defined as EJB and CDI beans in which case the JAX-RS resources will be implicit managed beans as well. A future version of different component specifications may discuss if it makes sense to align other Java EE POJO elements to align with Managed Beans specification.

Technorati: javaee glassfish v3 managedbeans cdi ejb servlet jndi

About

profile image
Arun Gupta is a technology enthusiast, a passionate runner, author, and a community guy who works for Oracle Corp.


Java EE 7 Samples

Stay Connected

Search

Archives
« April 2014
SunMonTueWedThuFriSat
  
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
   
       
Today