Monitoring the EJB Container in WildFly

In this article we will show how you can monitor the EJB Container in WildFly application server by adding custom Interceptor classes

Interceptors are classes that allow to separate common, or cross-cutting, code from business methods. A typical usage of interceptors are  logging, auditing, performance monitoring, or security checks.
Such aspects usually mix within business methods. Instead of cluttering business methods with cross-cutting code, you can encapsulate these concerns in separate methods or classes called interceptors.

EJB Interceptors can be added much the same way at two different levels:

  • At EJB Container level
  • At Application level

If you want to learn more Application level EJB interceptors you can have a look at: How to code EJB interceptors like a pro

Finally, if you want to learn how to monitor EJB deployments using the CLI have a look at: Monitoring the EJB container using the CLI

In this article we will show how to apply EJB Interceptors at EJB Container level, which allows tracing calls to all EJBs running as well as individual EJBs.

Configuring Container Interceptors

Firstly, to configure EJB Container interceptors you can use the file jboss-ejb3.xml . You need to place this file in the the META-INF folder of the EJB deployment. Let’s see one example:

<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>com.mastertheboss.interceptor.GenericContainerInterceptor</interceptor-class>
            </jee:interceptor-binding>

            <!-- Class level container-interceptor -->
            <jee:interceptor-binding>
                <ejb-name>ClassLevelContainerInterceptor</ejb-name>
                <interceptor-class>com.mastertheboss.interceptor.ClassLevelContainerInterceptor</interceptor-class>
            </jee:interceptor-binding>

            <!-- Method specific container-interceptor -->
            <jee:interceptor-binding>
                <ejb-name>MethodSpecificContainerInterceptor</ejb-name>
                <interceptor-class>com.mastertheboss.interceptor.MethodSpecificContainerInterceptor</interceptor-class>
                <method>
                    <method-name>mymethod</method-name>
                </method>
            </jee:interceptor-binding>
        </ci:container-interceptors>
    </jee:assembly-descriptor>
</jboss>

This file declares three interceptors:

  • GenericContainerInterceptor: This Interceptor applies to all (*) EJB Running in the Container
  • ClassLevelContainerInterceptor: This Interceptor applies only to the EJB whose name is ClassLevelContainerInterceptor
  • MethodSpecificContainerInterceptor: This interceptor applies to the method mymethod() of the Class MethodSpecificContainerInterceptor

As an example, here is the com.mastertheboss.interceptor.GenericContainerInterceptor which includes the javax.interceptor.AroundInvoke annotation in one of its methods:

package com.mastertheboss.interceptor;

import org.jboss.logging.Logger;

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

public class GenericContainerInterceptor {
    private static Logger log = Logger.getLogger(GenericContainerInterceptor.class);
    
    @AroundInvoke
    private Object intercept(final InvocationContext invocationContext) throws Exception {
         
          log.info("Going to call " +invocationContext.getMethod()); 

          // Invoke the EJB method
          Object result = this.getClass().getName() + " " + invocationContext.proceed();

          
        return result;
    }
 
}

When executed, this Interceptor will display the EJB being called and its method:

15:02:13,198 INFO'  [com.mastertheboss.interceptor.GenericContainerInterceptor] (http-/127.0.0.1:8080-1) Going to call public void com.mastertheboss.ejb.ServiceBean.put(com.mastertheboss.model.SimpleProperty)

Configuring the Order of Interceptors

To configure the Order of Interceptors you can use the interceptor-order element. Within it, add the list of interceptors in the order you want them to be invoked:

<jee:interceptor-binding>
    <ejb-name>AnotherFlowTrackingBean</ejb-name>
    <interceptor-order>
        <interceptor-class>com.mastertheboss.interceptor.ClassLevelContainerInterceptor</interceptor-class>
        <interceptor-class>com.mastertheboss.interceptor.MethodSpecificContainerInterceptor</interceptor-class>
        <interceptor-class>com,nastertheboss.interceptor.ContainerInterceptorOne</interceptor-class>
    </interceptor-order>
    <method>
        <method-name>echoInSpecificOrderOfContainerInterceptors</method-name>
    </method>
</jee:interceptor-binding>

JBoss AS 5 – 6

JBoss 5 EJB container is based on the concept of interceptors. These are simple classed based on the Proxy pattern, which allow to execute all the required steps before method invocation (security checks, instance creation,’ transaction propagation etc.).The great benefit of interceptors is that they are a seamless way to add Aspect Oriented Programming to your business methods.

EJB 3 Interceptors are defined in the file server/<your server>/deploy/ejb3-interceptors.xml.

Here’s the section we want to operate on:
 <domain name="Stateless Bean" extends="Intercepted Bean" inheritBindings="true">
     . . . .
      <bind pointcut="execution(public * *->*(..))">
         
         <interceptor-ref name="org.jboss.aspects.tx.TxPropagationInterceptor"/>
         <interceptor-ref name="org.jboss.ejb3.tx.CMTTxInterceptorFactory"/>
         <interceptor-ref name="org.jboss.ejb3.stateless.StatelessInstanceInterceptor"/>
         <interceptor-ref name="org.jboss.ejb3.tx.BMTTxInterceptorFactory"/>
         <interceptor-ref name="org.jboss.ejb3.AllowedOperationsInterceptor"/>
         <interceptor-ref name="org.jboss.ejb3.entity.TransactionScopedEntityManagerInterceptor"/>
         <!-- interceptor-ref name="org.jboss.ejb3.interceptor.EJB3InterceptorsFactory"/ -->
         <stack-ref name="EJBInterceptors"/>
      </bind>
      <annotation expr="!class(@org.jboss.ejb3.annotation.Pool)">
         @org.jboss.ejb3.annotation.Pool (value="ThreadlocalPool", maxSize=30, timeout=10000)
      </annotation>
</domain>
Next, update jboss-ejb3-core.jar:

<!--------- OUR INTERCEPTOR ---------->
   
   <interceptor class="com.sample.PoolInterceptor" scope="PER_VM"/>
   
   ........
   
   <domain name="Stateless Bean" extends="Intercepted Bean" inheritBindings="true">
         
         <interceptor-ref name="org.jboss.aspects.tx.TxPropagationInterceptor"/>
         <interceptor-ref name="org.jboss.ejb3.tx.CMTTxInterceptorFactory"/>
         <interceptor-ref name="org.jboss.ejb3.stateless.StatelessInstanceInterceptor"/>
         <interceptor-ref name="org.jboss.ejb3.tx.BMTTxInterceptorFactory"/>
         <interceptor-ref name="org.jboss.ejb3.AllowedOperationsInterceptor"/>
         <interceptor-ref name="org.jboss.ejb3.entity.TransactionScopedEntityManagerInterceptor"/>
         
         <!--------- OUR INTERCEPTOR ---------->
         <interceptor-ref name="com.sample.PoolInterceptor"/> 
         
         
         <stack-ref name="EJBInterceptors"/>
      </bind>
      <annotation expr="!class(@org.jboss.ejb3.annotation.Pool)">
         @org.jboss.ejb3.annotation.Pool (value="StrictMaxPool", maxSize=1000, timeout=100000)
      </annotation>
   </domain>

Compile’ the interceptor and add the class to the jboss-ejb3-core.jar

jboss as stateless slsb ejb pool
‘ That’s all! restart the server and verify that your SLSB now debugs information about the current/max size of instances.