MyBeanInterface bean = lookupBean(); bean.doSomething();
JBoss AS versions prior to AS7 allowed a JBoss specific way to plug-in user application specific interceptors on the server side so that those interceptors get invoked during an EJB invocation. Such interceptors differed from the typical (portable) spec provided Java EE interceptors. The Java EE interceptors are expected to run after the container has done necessary invocation processing which involves security context propagation, transaction management and other such duties. As a result, these Java EE interceptors come too late into the picture, if the user applications have to intercept the call before certain container specific interceptor(s) are run.
A typical EJB invocation looks like this:
MyBeanInterface bean = lookupBean(); bean.doSomething();
The invocation on the bean.doSomething() triggers the following (only relevant portion of the flow shown below):
JBoss AS specific interceptor (a.k.a container interceptor) 1
JBoss AS specific interceptor (a.k.a container interceptor) 2
....
JBoss AS specific interceptor (a.k.a container interceptor) N
User application specific Java EE interceptor(s) (if any)
Invocation on the EJB instance's method
The JBoss AS specific interceptors include the security context propagation, transaction management and other container provided services. In some cases, the "container interceptors" (let's call them that) might even decide break the invocation flow and not let the invocation proceed (for example: due to the invoking caller not being among the allowed user roles who can invoke the method on the bean).
Previous versions of JBoss AS allowed a way to plug-in the user application specific interceptors (which relied on JBoss AS specific libraries) into this invocation flow so that they do run some application specific logic before the control reaches step#5 above. For example, AS5 allowed the use of JBoss AOP interceptors to do this.
JBoss AS 7.0 and 7.1 doesn't have such a feature.
There were many community users who requested for this feature to be made available in AS7. As a result, https://issues.jboss.org/browse/AS7-5897 JIRA was raised. This feature is now implemented in AS 7.2.x version.
As you can see from the JIRA https://issues.jboss.org/browse/AS7-5897, one of the goals of this feature implementation was to make sure that we don't introduce any new JBoss AS specific library dependencies for the container interceptors. So we decided to allow the Java EE interceptors (which are just POJO classes with lifecycle callback annotations) to be used as container interceptors. As such you won't need any dependency on any AS7 specific libraries. That will allow us to support this feature for a longer time in future versions of JBoss AS.
Furthermore, configuring these container interceptors is similar to configuring the Java EE interceptors for EJBs. In fact, it uses the same xsd elements that are allowed in ejb-jar.xml for 3.1 version of ejb-jar deployment descriptor.
Container interceptors can only be configured via deployment descriptors. There's no annotation based way to configure container interceptors. This was an intentional decision, taken to avoid introducing any JBoss AS specific library dependency for the annotation.
Configuring the container interceptors can be done in jboss-ejb3.xml file, which then gets placed under the META-INF folder of the EJB deployment, just like the ejb-jar.xml. Here's an example of how the container interceptor(s) can be configured in jboss-ejb3.xml:
<jboss xmlns="http://www.jboss.com/xml/ns/javaee" xmlns:jee="http://java.sun.com/xml/ns/javaee" xmlns:ci ="urn:container-interceptors:1.0"> <jee:assembly-descriptor> <ci:container-interceptors> <!-- Default interceptor --> <jee:interceptor-binding> <ejb-name>*</ejb-name> <interceptor-class>org.jboss.as.test.integration.ejb.container.interceptor.ContainerInterceptorOne</interceptor-class> </jee:interceptor-binding> <!-- Class level container-interceptor --> <jee:interceptor-binding> <ejb-name>AnotherFlowTrackingBean</ejb-name> <interceptor-class>org.jboss.as.test.integration.ejb.container.interceptor.ClassLevelContainerInterceptor</interceptor-class> </jee:interceptor-binding> <!-- Method specific container-interceptor --> <jee:interceptor-binding> <ejb-name>AnotherFlowTrackingBean</ejb-name> <interceptor-class>org.jboss.as.test.integration.ejb.container.interceptor.MethodSpecificContainerInterceptor</interceptor-class> <method> <method-name>echoWithMethodSpecificContainerInterceptor</method-name> </method> </jee:interceptor-binding> <!-- container interceptors in a specific order --> <jee:interceptor-binding> <ejb-name>AnotherFlowTrackingBean</ejb-name> <interceptor-order> <interceptor-class>org.jboss.as.test.integration.ejb.container.interceptor.ClassLevelContainerInterceptor</interceptor-class> <interceptor-class>org.jboss.as.test.integration.ejb.container.interceptor.MethodSpecificContainerInterceptor</interceptor-class> <interceptor-class>org.jboss.as.test.integration.ejb.container.interceptor.ContainerInterceptorOne</interceptor-class> </interceptor-order> <method> <method-name>echoInSpecificOrderOfContainerInterceptors</method-name> </method> </jee:interceptor-binding> </ci:container-interceptors> </jee:assembly-descriptor> </jboss>
The usage of urn:container-interceptors:1.0 namespace which allows the container-interceptors elements to be configured
The container-interceptors element which contain the interceptor bindings
The interceptor bindings themselves are the same elements as what the EJB3.1 xsd allows for standard Java EE interceptors
The interceptors can be bound either to all EJBs in the deployment (using the the * wildcard) or individual bean level (using the specific EJB name) or at specific method level for the EJBs.
The xsd for the urn:container-interceptors:1.0 namespace is available here https://github.com/wildfly/wildfly/blob/master/ejb3/src/main/resources/jboss-ejb-container-interceptors_1_0.xsd
The interceptor classes themselves are simple POJOs and use the @javax.annotation.AroundInvoke to mark the around invoke method which will get invoked during the invocation on the bean. Here's an example of the interceptor:
public class ClassLevelContainerInterceptor { @AroundInvoke private Object iAmAround(final InvocationContext invocationContext) throws Exception { return this.getClass().getName() + " " + invocationContext.proceed(); } }
The container interceptors configured for a EJB are guaranteed to be run before the JBoss AS provided security interceptors, transaction management interceptors and other such interceptors thus allowing the user application specific container interceptors to setup any relevant context data before the invocation proceeds.
Although the container interceptors are modeled to be similar to the Java EE interceptors, there are some differences in the API semantics. One such difference is that invoking on javax.interceptor.InvocationContext.getTarget() method is illegal for container interceptors since these interceptors are invoked way before the EJB components are setup or instantiated.
This testcase in the AS7 codebase can be used for reference for implementing container interceptors in user applications https://github.com/wildfly/wildfly/blob/master/testsuite/integration/basic/src/test/java/org/jboss/as/test/integration/ejb/container/interceptor/ContainerInterceptorsTestCase.java