





















































Build real world EJB solutions with a collection of simple but incredibly effective recipes with this book and eBook
Most applications have cross-cutting functions which must be performed. These cross-cutting functions may include logging, managing transactions, security, and other aspects of an application. Interceptors provide a way to achieve these cross-cutting activities.
The use of interceptors provides a way of adding functionality to a business method without modifying the business method itself. The added functionality is not intermeshed with the business logic resulting in a cleaner and easier to maintain application.
Aspect Oriented Programming (AOP) is concerned with providing support for these cross-cutting functions in a transparent fashion. While interceptors do not provide as much support as other AOP languages, they do offer a good level of support.
Interceptors can be:
Interceptors are specific methods invoked around a method or methods of a target EJB. We will use the term target, to refer to the class containing the method(s) an interceptor will be executing around.
The interceptor's method will be executed before the EJB's method is executed. When the interceptor method executes, it is passed as an InvocationContext object. This object provides information relating to the state of the interceptor and the target. Within the interceptor method, the InvocationContext's method proceed can be issued that will result in the target's business method being executed or, as we will see shortly, the next interceptor in the chain. When the business method returns, the interceptor continues execution. This permits execution of code before and after the execution of a business method.
Interceptors can be used with:
The @Interceptors annotation defines which interceptors will be executed for all or individual methods of a class. Interceptor classes use the same lifecycle of the EJB they are applied to, in the case of stateful EJBs, which means the interceptor could be passivated and activated. In addition, they support the use of dependency injection. The injection is done using the EJB's naming context.
More than one interceptor can be used at a time. The sequence of interceptor execution is referred to as an interceptor chain. For example, an application may need to start a transaction based on the privileges of a user. These actions should also be logged. An interceptor can be defined for each of these activities: validating the user, starting the transaction, and logging the event. The use of interceptor chaining is illustrated in the Using interceptors to handle application statistics recipe.
Lifecycle callbacks such as @PreDestroy and @PostConstruct can also be used within interceptors. They can access interceptor state information as discussed in the Using lifecycle methods in interceptors recipe.
Interceptors are useful for:
An example of parameter validation can be found in the Using the InvocationContext to verify parameters recipe. Security checks are illustrated in the Using interceptors to enforce security recipe. The use of interceptor chaining to record a method's hit count and the time spent in the method is discussed in the Using interceptors to handle application statistics recipe. Interceptors can also be used in conjunction with timer services.
The recipes in this article are based largely around a conference registration application as developed in the first recipe. It will be necessary to create this application before the other recipes can be demonstrated.
A RegistrationApplication is developed in this recipe. It provides the ability of attendees to register for a conference. The application will record their personal information using an entity and other supporting EJBs. This recipe details how to create this application.
The RegistrationApplication consists of the following classes:
The steps used to create this application include:
The RegistrationManager will be the primary vehicle for the demonstration of interceptors.
Create a Java EE application called RegistrationApplication. Add a packt package to the EJB module and a servlet package in the application's WAR module.
Next, add an Attendee entity to the packt package. This entity possesses four fields: name, title, company, and id. The id field should be auto generated. Add getters and setters for the fields. Also add a default constructor and a three argument constructor for the first three fields. The major components of the class are shown below without the getters and setters.
@Entity
public class Attendee implements Serializable {
private String name;
private String title;
private String company;
private static final long serialVersionUID = 1L;
@Id
@GeneratedValue(strategy = GenerationType.AUTO)
private Long id;
public Attendee() {
}
public Attendee(String name, String title, String company) {
this.name = name;
this.title = title;
this.company = company;
}
}
Next, add an AttendeeFacade stateless session bean which is derived from the AbstractFacade class. The AbstractFacade class is not shown here.
@Stateless
public class AttendeeFacade extends AbstractFacade<Attendee> {
@PersistenceContext(unitName = "RegistrationApplication-ejbPU")
private EntityManager em;
protected EntityManager getEntityManager() {
return em;
}
public AttendeeFacade() {
super(Attendee.class);
}
}
Add a RegistrationManager stateful session bean to the packt package. Add a single method, register, to the class. The method should be passed three strings for the name, title, and company of the attendee. It should return an Attendee reference. Use dependency injection to add a reference to the AttendeeFacade. In the register method, create a new Attendee and then use the AttendeeFacade class to create it. Next, return a reference to the Attendee.
@Stateful
public class RegistrationManager {
@EJB
AttendeeFacade attendeeFacade;
Attendee attendee;
public Attendee register(String name, String title,
String company) {
attendee = new Attendee(name, title, company);
attendeeFacade.create(attendee);
return attendee;
}
}
In the servlet package of the WAR module, add a servlet called RegistrationServlet. Use dependency injection to add a reference to the RegistrationManager. In the try block of the processRequest method, use the register method to register an attendee and then display the attendee's name.
public class RegistrationServlet extends HttpServlet {
@EJB
RegistrationManager registrationManager;
protected void processRequest(HttpServletRequest request,
HttpServletResponse response)
throws ServletException, IOException {
response.setContentType("text/html;charset=UTF-8");
PrintWriter out = response.getWriter();
try {
out.println("<html>");
out.println("<head>");
out.println("<title>Servlet RegistrationServlet</title>");
out.println("</head>");
out.println("<body>");
Attendee attendee = registrationManager.register("Bill
Schroder", "Manager", "Acme Software");
out.println("<h3>" + attendee.getName() + " has been
registered</h3>");
out.println("</body>");
out.println("</html>");
} finally {
out.close();
}
}
...
}
Execute the servlet. The output should appear as shown in the following screenshot:
The Attendee entity holds the registration information for each participant. The RegistrationManager session bean only has a single method at this time. In later recipes we will augment this class to add other capabilities. The RegistrationServlet is the client for the EJBs.