Customizing EJB3 Configuration

This example shows you how to customize EJB3, specifically how to customize the default configuration settings and the default client and server interceptors. For example, we will see how you can modify such things as instance pool sizes for stateless session beans and how to add custom behavior to beans via custom interceptors.

ejb3-interceptors-aop.xml

The majority of EJB3 configuration with the exception of such areas as cluster caches, remoting, and deployer configuration is in the ejb3-interceptors-aop.xml file found in the deploy directory. If you are familiar with EJB2.1, ejb3-interceptors-aop.xml is analagous to standardjboss.xml but uses JBoss's Aspect Oriented Programming mechanism. standardjboss.xml is not used by EJB3.

First, take a look at the default ejb3-interceptors-aop.xml. Each of the sections will be described individually.

Interceptors

The <Interceptor ... /> elements define the interceptors and interceptor factories to be used by the client and server configuration. The scope of each is also defined, specifying how many interceptor instances will be created. Each interceptor or interceptor factory must be defined.

Client Side Interceptors

The <stack .. /> elements are used to create an interceptor chain for the client (i.e. ejb proxy) side. The default chains create standard client side behavior for the various types of beans.

Domains

The <domain ... /> elements configure the server side. There is a default domain for each bean type. This is where the server side interceptor chains are defined using the AOP Pointcut Language (i.e. <bind pointcut="..." />). Please see the AOP documentation for more information on the Pointcut Language. The Domains are also used to introduce default annotations and thus create default behavior for each of the bean types. For example, take a look at the "Stateless Bean" domain. Notice that through the <annotation expr="..." /> element, a default @org.jboss.annotation.ejb.PoolClass is created for each stateless session bean that does not explicitly define a @org.jboss.annotation.ejb.PoolClass annotation on the class.

Customization of ejb3-interceptors-aop.xml

You may modify the default behavior via the interceptor chains and annotation introductions in ejb3-interceptors-aop.xml. Take a look at the modified ejb3-interceptors-aop.xml. First, notice that we have defined a org.jboss.tutorial.configuration.TeacherAopInterceptor interceptor and added this interceptor to the client side interceptor chain in the "StatelessSessionClientInterceptors" stack. Second, notice that we have defined another interceptor, org.jboss.tutorial.configuration.BadMathAopInterceptor and have added it to the server side interceptor stack in the "Stateless Bean" domain. Note that this interceptor is only bound to the subtract methods of the beans. Third, notice that we have changed the default @PoolClass annotation to use StrictMaxPool of size 10, as opposed to ThreadLocalPool of size 30. This becomes the default stateless session bean pool configuration for all beans that do not explicitly define a @PoolClass annotation.

Custom Domains and Stacks

You may also create your own custom server Domains and client interceptor Stacks and reference those configurations via annotations on the beans themselves. Take a look at the modified custom-ejb3-interceptors-aop.xml. We have created a custom client stack and a custom server domain. We have added the TeacherAopInterceptor to the custom client stack. We have removed several of the standard interceptors from the default stateless session domain (e.g. security, transactions, clustering), bound BadMathAopInterceptor to the add method, and modified the @PoolClass to be StrictMaxPool with a size of 1.

Custom Behavior

The custom interceptors are added to the client and server chains of the two concrete extensions of CalculatorBean.java. Take a look at the two concrete classes CustomizedCalculatorBean.java and CustomDomainCalculatorBean.java. The former uses the custom default configuration from ejb3-interceptors-aop.xml. The latter uses the custom stack and domain configuration from custom-ejb3-interceptors-aop.xml. Notice the @AspectDomain and @RemoteBinding annotations reference the custom stack and domain names.

BadMathAopInterceptor catches and modifies the results from the bound methods from the calculator. TeacherAopInterceptor logs a message when an incorrect result is caught on the client side.

The custom PoolClass configuration for CustomDomainCalculatorBean uses a pool size of 1. This in effect, makes the stateless bean stateful and serializes access to the bean. See the results below.

Building and Running

To build and run the example, make sure you have ejb3.deployer installed in JBoss 4.x and JBOSS_HOME is set to that installation.
Unix:    $ export JBOSS_HOME=<where your jboss 4.0 distribution is>
Windows: $ set JBOSS_HOME=<where your jboss 4.0 distribution is>
$ ant
$ ant run

run:
     [java] Testing CustomDomainCalculatorBean ...
     [java] Wrong Answer!!
     [java] 1 + 1 != 3
     [java] 1 - 1 = 0
     [java] Saving 123 ...
     [java] Recalling 123
     [java] Recalling 123
     [java] Recalling 123
     [java] Recalling 123
     [java] Recalling 123
     [java] Recalling 123
     [java] Recalling 123
     [java] Recalling 123
     [java] Recalling 123
     [java] Testing CustomizedCalculatorBean ...
     [java] Recalling 123
     [java] 1 + 1 = 2
     [java] Wrong Answer!!
     [java] 1 - 1 != 1
     [java] Saving 123 ...
     [java] Recalling 123
     [java] Recalling 0
     [java] Recalling 0
     [java] Recalling 0
     [java] Recalling 0
     [java] Recalling 0
     [java] Recalling 0
     [java] Recalling 0
     [java] Recalling 0
     [java] Recalling 0

Look in the console window:

16:10:44,609 INFO  [BadMathAopInterceptor] *** Intercepting in BadMathAopInterceptor in public int org.jboss.tutorial.configuration.bean.CalculatorBean.add(int,int)
16:10:49,718 INFO  [BadMathAopInterceptor] *** Intercepting in BadMathAopInterceptor in public int org.jboss.tutorial.configuration.bean.CalculatorBean.subtract(int,int)