Interceptors and Injection
Interceptors belong to the same ENC as the EJBs they intercept. Like the EJBs they intercept, interceptor classes have full support for all the injection
annotations, as well as injection through XML. So, you can use annotations like @Resource, @EJB, and @PersistenceContext within your interceptor class if you so desire. Let's illustrate this in an auditing interceptor:
package com.titan.interceptors;
import javax.ejb.*;
import javax.persistence.*;
import javax.annotation.Resource;
import javax.interceptor.*;
public class AuditInterceptor {
@Resource EJBContext ctx;
@PersistenceContext(unitName="auditdb") EntityManager manager;
@AroundInvoke
public Object audit(InvocationContext invocation) throws Exception {
Audit audit = new Audit( ) ;
audit.setMethod(invocation.getMethod().toString( ));
audit.setUser(ctx.getCallerPrincipal().toString( ));
audit.setTime(new Date( ));
try {
Object returnValue = invocation.proceed( );
} catch (Exception ex) {
audit.setFailure(ex.getMessage( ));
throw ex;
} finally {
manager.persist(audit);
}
}
}
The purpose of this interceptor is to log in a database every method invocation done on a particular bean so that an audit trail is created. From this audit trail, system administrators can research security breaches or replay the actions of a particular user. The interceptor obtains the calling user by invoking getCallerPrincipal( ) on the javax.ejb.EJBContext
injected into the ctx member variable. It allocates an Audit entity bean and sets properties like the method being invoked, the calling principal, and the current time. If the method throws an exception, this is also stored in the Audit entity. At the end of the @AroundInvoke method, the Audit entity is persisted to the database by the EntityManager injected into the manager member variable.
As with bean classes, interceptor injection annotations create additional entries in the ENC of the EJB to which the interceptor class is bound. This means that the persistence context referenced by the manager field is also available in JNDI with the string java:comp/env/com.titan.interceptors.AuditInterceptor/manager
.
XML Injection
If you do not want to use annotations to inject dependencies into your interceptor classes, the XML alternative is to define an <interceptor> element within your ejb-jar.xml deployment descriptor:
<ejb-jar
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/ejb-jar_3_0.xsd"
version="3.0">
<interceptors>
<interceptor>
<interceptor-class>
com.titan.interceptors.AuditInterceptor
</interceptor-class>
<around-invoke>
<method-name>audit</method-name>
</around-invoke>
<persistence-context-ref>
<persistence-context-name>
com.titan.interceptors.AuditInterceptor/manager
</persistence-context-name>
<persistence-context-unit-name>auditdb
</
persistence-context-unit-name>
<injection-target>
<injection-target-class>
com.titan.interceptors.AuditInterceptor
</injection-target-class>
<injection-target-name>manager</injection-target-name>
</injection-target>
</persistence-context-ref>
</interceptor>
</interceptors>
</ejb-jar>
The <interceptors> element is a new, top-level element in <ejb-jar>. The <interceptor> subelement accepts any environment entries that are available within an EJB description. Also, if you elect not to use annotations in your class definitions, you can specify metadata like @AroundInvoke using the <around-invoke> element.
There may be times when you want to override injections specified on the interceptor class on a per-EJB basis. This can be done through annotations or via XML. For instance, say you want to use a different persistence unit for the interceptor bound to your TravelAgent EJB other than the auditdb unit that is currently being injected into
your AuditInterceptor
class. You can do this by overriding the environment name of the injected property in your EJB definition:
@Stateful
@PersistenceContext
(name="com.titan.interceptors.AuditInterceptor/manager",
unitName="EnterpriseWideAuditDB")
public class TravelAgentBean implements TravelAgentRemote {
...
}
Since all injections are based on the ENC name, the preceding code uses the @PersistenceContext annotation on the EJB bean class to override the interceptor's persistence context reference. This can be done in XML as well:
<ejb-jar
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/ejb-jar_3_0.xsd"
version="3.0">
<enterprise-beans>
<session>
<ejb-name>TravelAgentBean</ejb-name>
<persistence-context-ref>
<persistence-context-name>
com.titan.interceptors.AuditInterceptor/manager
</persistence-context-name>
<persistence-context-unit-name>auditdb</persistence-context-unit-name>
</persistence-context-ref>
</session>
</enterprise-beans>
</ejb-jar>
The <persistence-context-unit-name> element references the default ENC name of the manager field in the AuditInterceptor class.
|