## EJB Interceptors

The EJB 3.0 spec defines the ability to apply custom made interceptors to the business methods of your session and message driven beans (and of course to the JBoss @Service and @Consumer beans). EJB 3.0 interceptors take the form of methods annotated with the `@javax.ejb.AroundInvoke` annotation. These methods must have the following signature:

       @javax.ejb.AroundInvoke
       public Object <Arbitrary method name>(javax.ejb.InvocationContext ctx) throws java.lang.Exception

You can either define an interceptor method in the bean class itself, or in separate classes. There can only be one interceptor method per class.

## Interceptor method in bean class

Take a look at EmailMDB.java. It contains this method:

       @AroundInvoke
       public Object mdbInterceptor(InvocationContext ctx) throws Exception
       {
          System.out.println("*** Intercepting call to EmailMDB.mdbInterceptor()");
          return ctx.proceed();
       }

This method will wrap the call to EmailMDB.onMessage(). The call to ctx.proceed() causes the next object in the chain of interceptors to get invoked. At the end of the chain of interceptors, the actual bean method gets called.

Similarly EmailSystemBean.java has a method annotated with `@AroundInvoke`

       @AroundInvoke
       public Object myBeanInterceptor(InvocationContext ctx) throws Exception
       {
          if (ctx.getMethod().getName().equals("emailLostPassword"))
          {
             System.out.println("*** EmailSystemBean.myBeanInterceptor - username: " + ctx.getParameters()[0]);
          }

          return ctx.proceed();
       }

## External interceptors

The rest of this example will be looking at adding interceptors external to the bean class, more specifically to `EmailSystemBean`. Interceptors can be bound in three different ways

- Default
- Class-level
- Method-level

An external interceptor instance follows the lifecycle of the target bean instance.

### Default interceptors

We will see how class and method-level interceptors can be bound to a bean or a bean's method using annotations or xml. Default interceptors can only be bound via xml. A Default interceptor is an interceptor that is invoked whenever a business method is invoked on any bean within the deployment.

DefaultInterceptor.java defines an `@AroundInvoke` method with the required method signature.

       @AroundInvoke
       public Object intercept(InvocationContext ctx) throws Exception
       {
          System.out.println("*** DefaultInterceptor intercepting " + ctx.getMethod().getName());
          try
          {
             return ctx.proceed();
          }
          finally
          {
             System.out.println("*** DefaultInterceptor exiting");
          }
       }

As mentioned, default interceptors can only be applied via xml.

In ejb-jar.xml we have the following:

       <assembly-descriptor>
          <!-- Default interceptor that will apply to all methods for all beans in deployment -->
          <interceptor-binding>
             <ejb-name>*</ejb-name>
             <interceptor-class>org.jboss.tutorial.interceptor.bean.DefaultInterceptor</interceptor-class>
          </interceptor-binding>
          ...
       </assembly-descriptor>

Using `*` for the ejb-name says that `DefaultInterceptor` is a default interceptor, i.e. it should intercept all calls to all beans within the deployment unit. We could have added more `interceptor-class` entries to bind more interceptors, as shown here:

       <assembly-descriptor>
          <!-- Default interceptor that will apply to all methods for all beans in deployment -->
          <interceptor-binding>
             <ejb-name>*</ejb-name>
             <interceptor-class>org.jboss.tutorial.interceptor.bean.DefaultInterceptor</interceptor-class>
             <interceptor-class>org.jboss.tutorial.interceptor.bean.AnotherInterceptor</interceptor-class>
          </interceptor-binding>
          ...
       </assembly-descriptor>

In this case DefaultInterceptor would be invoked before AnotherInterceptor.

### Class-level interceptors

Class-level interceptors can be bound using xml or annotations.

#### Class-level using annotations

EmailSystemBean.java has been annotated:

       @Stateless
       @Interceptors ({TracingInterceptor.class})
       public class EmailSystemBean
       {
          ...
       }

This says that the `@AroundInvoke` annotated method of TracingInterceptor.java should wrap all calls to `EmailSystemBean`'s business methods. The `@Interceptors` annotation can take an array of classes, so you can bind more than one class-level interceptor this way, e.g.

       @Stateless
       @Interceptors ({TracingInterceptor.class, SomeInterceptor.class})
       public class EmailSystemBean
       {
          ...
       }

#### Class-level using xml

In ejb-jar.xml we have the following:

       <assembly-descriptor>
          ...
          <!-- Class interceptor that will apply to all methods for EmailSystemBean -->
          <interceptor-binding>
             <ejb-name>org.jboss.tutorial.interceptor.bean.EmailSystemBean</ejb-name>
             <interceptor-class>org.jboss.tutorial.interceptor.bean.OtherInterceptor</interceptor-class>
          </interceptor-binding>
          ...
       </assembly-descriptor>

Note that here we are specifying the ejb-name of the bean we want to apply the interceptor to. Hence, the `@AroundInvoke` annotated method of OtherInterceptor.java will wrap all calls to `EmailSystemBean`'s business methods.

### Method-level interceptors

Just as we can define default and class-level interceptors, we can also bind an interceptor to a particular business method within a bean

#### Method-level using annotations

EmailSystemBean's `sendBookingConfirmationMessage()` method has been annotated with the @Interceptors annotation specifying interceptors that will intercept when this perticular method is invoked.

       @Interceptors({AccountsConfirmInterceptor.class})
       public void sendBookingConfirmationMessage(long orderId)
       {
          ...
       }

Method-level interceptors are in addition to default and class-level interceptors, meaning that when we call `EmailSystemBean.sendBookingConfirmationMessage()` we get intercepted by

- DefaultInterceptor (default)
- TracingInterceptor (class-level)
- OtherIntercetor (class-level)
- AccountsConfirmInterceptor (method-level)

An interceptor method can choose to abort an invocation, by not calling `InvocationContext.proceed()` as is done in `AccountConfirmInterceptor`'s interceptor method when a confirmation already exists.

#### Method-level using xml

We can also bind interceptors to a single business method within a bean using xml. But first let's define an interceptor using xml. All the examples we have looked at so far have used the `@AroundInvoke` annotation to mark the interceptor methods.

In ejb-jar.xml we have the following:

       <interceptors>
          <interceptor>
             <interceptor-class>org.jboss.tutorial.interceptor.bean.AccountsCancelInterceptor</interceptor-class>
             <around-invoke-method>
                <method-name>sendCancelMessage</method-name>
             </around-invoke-method>
             ...
       </interceptors>

This tells us that the `sendCancelMessage()` method of AccountsCancelInterceptor is the interceptor method of this interceptor class. (We will see what the other sub-elements of `interceptor` mean in the 'injection' section.

To bind interceptors to a particular method using xml, is much the same as how this was done for class-level interceptors apart from that we specify the `method-name` of the method we want to intercept. From our ejb-jar.xml:

       <assembly-descriptor>
          ...
    	<!-- Method interceptor will apply to sendBookingCancellationMessage for EmailSystemBean -->
          <interceptor-binding>
             <ejb-name>org.jboss.tutorial.interceptor.bean.EmailSystemBean</ejb-name>
             <interceptor-class>org.jboss.tutorial.interceptor.bean.AccountsCancelInterceptor</interceptor-class>
             <method-name>sendBookingCancellationMessage</method-name>
          </interceptor-binding>
       </assembly-descriptor>

In the example just shown, if we had several business methods with the name, the interceptor would get applied to all of them. In the case of overloaded methods, we can further narrow down the method by specifying the method parameters, as in this example:

       <assembly-descriptor>
          ...
    	<!-- Method interceptor will apply to sendBookingCancellationMessage for EmailSystemBean -->
          <interceptor-binding>
             <ejb-name>MyBean</ejb-name>
             <interceptor-class>SomeInterceptor</interceptor-class>
             <method-name>overLoadedMethod</method-name>
    	  <method-params>
    		 <method-param>int</method-param>
    		 <method-param>java.lang.String[][]</method-param>
    	  </method-params>

          </interceptor-binding>
       </assembly-descriptor>

If `MyBean` has several methods called `overLoadedMethod`, `SomeInterceptor` will only get applied to the one that matches the signature, i.e.

    overLoadedMethod(int, java.lang.String[][])

## Exclusion of default and class interceptors

For some beans we may want to exclude the default interceptors configured for the deployment, and for some methods with in a bean class we may want to exclude the class interceptors for the bean (and/or the default interceptors)

### Annotations

The `@javax.ejb.ExcludeDefaultInterceptors` annotation can be applied to a bean class or a method. If applied to a bean class, default interceptors will not get invoked for any of that bean class's methods. If applied to a bean business method, default interceptors will not get invoked when calling that method.

The `@javax.ejb.ExcludeClassInterceptors` annotation can be applied to a bean method, and if used class-level interceptors will not get invoked when calling that method.

EmailMDB.java defines

       @ExcludeDefaultInterceptors
       public class EmailMDB implements MessageListener
       {
          ...
       }

so `DefaultInterceptor` is not invoked when invoking the `EmailMDB.onMessage()`

EmailSystemBean's `noop` method is annotated with both `@ExcludeClassInterceptors` and `@ExcludeDefaultInterceptors` and so will not get intercepted by any of these.

       @ExcludeClassInterceptors
       @ExcludeDefaultInterceptors
       public void noop()
       {
          System.out.println("<In EmailSystemBean.noop business method");
          System.out.println("Exiting EmailSystemBean.noop business method>");
       }

    }}

    !!XML
    We can also exclude class and method-level interceptors within an {{interceptor-binding}} by specifying the {{exclude-class-interceptors}} and {{exclude-default-interceptors}} elements.
    {{{
       <assembly-descriptor>
          ...
          <interceptor-binding>
             <ejb-name>org.jboss.tutorial.interceptor.bean.EmailSystemBean</ejb-name>
             <exclude-class-interceptors/>
             <exclude-default-interceptors/>
             <method-name>noop2</method-name>
          </interceptor-binding>
          ...
       </assembly-descriptor>

## Inheritance Ordering

If an interceptor (or bean class) inherits from another class which has a method declared to be an interceptor method, the interceptor methods from the super class will be invoked first. However, if the interceptor method in the superclass has been overridden (regardless of if the overriding method is declared to be an interceptor method or not) it is not invoked.

Both AccountsConfirmInterceptor and AccountsCancelInterceptor inherit from AccountsInterceptor.

AccountsInterceptor declares the following interceptor method:

       @AroundInvoke
       public Object intercept(InvocationContext ctx) throws Exception
       {
          System.out.println("*** AccountsInterceptor intercepting " + ctx.getMethod().getName());
          try
          {
             return ctx.proceed();
          }
          finally
          {
             System.out.println("*** AccountsInterceptor exiting");
          }
       }

This method is overridden by `AccountsConfirmInterceptor`, even though it is not `AccountsConfirmInterceptor`'s interceptor method:

    public class AccountsConfirmInterceptor extends AccountsInterceptor
    {
       ...
       public Object intercept(InvocationContext ctx) throws Exception
       {
          //overrides AccountsInterceptor.intercept() so that will not be invoked
          return null;
       }

       @AroundInvoke
       public Object sendConfirmMessage(InvocationContext ctx) throws Exception
       {
          ...
       }
    }

So when invoking `AccountsConfirmInterceptor`, we simply invoke its `sendConfirmMessage()` method. `AccountsCancelInterceptor`, on the other hand, does not override `AccountsInterceptor.intercept()`, so when invoking `AccountsCancelInterceptor`, we first get intercepted by `AccountsInterceptor.intercept()` followed by `AccountsCancelInterceptor.sendCancelMessage()`.

## Injection

### Annotations

Just like a bean class, an interceptor can be the target of Dependency injection. The format for how this works is the same, and the injection works off the same ENC as the bean to which the interceptor is bound.

AccountsConfirmInterceptor has dependency injection set up using annotations:

    public class AccountsConfirmInterceptor extends AccountsInterceptor
    {
       @Resource(mappedName="java:ConnectionFactory")
       QueueConnectionFactory cf;

       @Resource(mappedName="queue/tutorial/accounts")
       Queue queue;

       @PersistenceContext
       EntityManager em;

       ...

Remember that interceptors follow the same lifecycle as the bean they are bound to. The interceptors are created at the same time as the bean instance is created, and dependecy injection occurs before the first business method is called. In the example just shown, the container;

- looks up `java:ConnectionFactory`, binds it in the ENC and injects this into the field `cf`
- looks up `queue/tutorial/accounts`, binds it in the ENC and injects this into the field `queue`
- Obtains the default EntityManager injects this into the field `em`

### XML

Injection can also be configured via xml, using the traditional `ejb-ref`, `ejb-local-ref`, `resource-ref`, `resource-env-ref` etc. which bind the global names. The only difference from beans is that we put this into the `interceptors` element defining the interceptor.

       <interceptors>
          <interceptor>
             <interceptor-class>org.jboss.tutorial.interceptor.bean.AccountsCancelInterceptor</interceptor-class>
             <around-invoke-method>
                <method-name>sendCancelMessage</method-name>
             </around-invoke-method>
             <resource-ref>
                <res-ref-name>jms/ConnFactory</res-ref-name>
                <res-type>javax.jms.QueueConnectionFactory</res-type>
                <res-auth>Container</res-auth>
                <mapped-name>java:/ConnectionFactory</mapped-name>
                <injection-target>
                   <injection-target-class>org.jboss.tutorial.interceptor.bean.AccountsCancelInterceptor</injection-target-class>
                   <injection-target-name>cf</injection-target-name>
                </injection-target>
             </resource-ref>
             <resource-env-ref>
                <resource-env-ref-name>accountsQueue</resource-env-ref-name>
                <resource-env-ref-type>javax.jms.Queue</resource-env-ref-type>
                <res-auth>Container</res-auth>
                <mapped-name>queue/tutorial/accounts</mapped-name>
                <injection-target>
                   <injection-target-class>org.jboss.tutorial.interceptor.bean.AccountsCancelInterceptor</injection-target-class>
                   <injection-target-name>queue</injection-target-name>
                </injection-target>
             </resource-env-ref>
          </interceptor>
       </interceptors>

- the Container looks up `java:/ConnectionFactory` in JNDI and creates the `java:comp/env/jms/ConnFactory` entry in the beans ENC, and following bean creation it injects the connction factory into AccountsCancelInterceptor's cf field.
- the Container looks up `queue/tutorial/accounts` in JNDI and creates the `java:comp/env/accountsQueue` entry in the beans ENC, and following bean creation it injects the connction factory into AccountsCancelInterceptor's queue field.

## Interceptor Ordering

By default the ordering of interceptors when invoking a method are

- External interceptors

- Default interceptors, if present
- Class interceptors, if present
- Method interceptors, if present

- Bean class interceptor method

Within each group (default, class, method) the order of the interceptors are from left to right as defined in the @Interceptors annotation, and then the xml interceptors.

### Overriding interceptor ordering

You can override the default sort order of the external interceptors by specifiying an `interceptor-binding` with an `interceptor-order` specifying the order of the interceptors

       <assembly-descriptor>
          ...
          <interceptor-binding>
             <ejb-name>org.jboss.tutorial.interceptor.bean.EmailSystemBean</ejb-name>
             <method-name>sendBookingCancellationMessage</method-name>
             <interceptor-order>
                <interceptor-class>org.jboss.tutorial.interceptor.bean.AccountsCancelInterceptor</interceptor-class>
                <interceptor-class>org.jboss.tutorial.interceptor.bean.DefaultInterceptor</interceptor-class>
                <interceptor-class>org.jboss.tutorial.interceptor.bean.OtherInterceptor</interceptor-class>
                <interceptor-class>org.jboss.tutorial.interceptor.bean.TracingInterceptor</interceptor-class>
             </interceptor-order>
          </interceptor-binding>
       </assembly-descriptor>

So when invoking `EmailSystemBean.sendBookingCancellationMessage` we will get the following interception order, quite different from the default sort order

- AccountsCancelInterceptor (method-level)
- DefaultInterceptor (default interceptor)
- OtherInterceptor (2nd class-level interceptor)
- TracingInterceptor(1st class-level interceptor)

#### InvocationContext

As you have seen the @AroundInvoke annotated interceptor methods all take a parameter of type `javax.ejb.InvocationContext`. The definition of InvocationContext is:

       package javax.ejb;

       public interface InvocationContext {
          public Object getBean();
          public java.lang.reflect.Method getMethod();
          public Object[] getParameters();
          public void setParameters(Object[] params);
          public java.util.Map getContextData();
          public Object proceed() throws Exception;
       }

- `getBean()` - returns the bean instance on which we are calling a method
- `getMethod()` - returns the method we are calling on the bean instance
- `getParameters()` - returns the parameters for the method call
- `setParameters()` - allows you to modify the parameters for the method call
- `getContextData` - The EJB interceptions are stateless, but the same InvocationContext instance is used for each interceptor method in a chain. If you want to pass values between interceptor methods in the business method invocation you can store them in the Map retured by getContextData().
- `proceed` - As discussed, invokes the next interceptor, or if we are in the last interceptor invokes the target bean method.

In some case we might want access to the EJBContext, this can be injected into the interceptor instance using the `@Resource` annotation.The AroundInvoke methods share the JNDI name space of the bean for whose methods they are invoked and execute within the same transaction and security context as the business methods for which they are invoked.

#### Building and Running

To build and run the example, make sure you have `ejb3.deployer` installed in JBoss 4.0.x and have JBoss running. See the reference manual on how to install EJB 3.0.

    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

Look at the JBoss console window to see the output of the interceptions taking place, the EmailMDB and AccountsMDB might occur in slightly different places since they execute asynchronously

    17:34:54,468 INFO  [EJB3Deployer] Deployed: file:/C:/cygwin/home/Kabir/cvs/jboss-head/build/output/jboss-5.0.0alpha/server/all/dep
    loy/tutorial.jar

Calling EmailSystemBean.emailLostPassword()

    17:35:02,328 INFO  [STDOUT] *** DefaultInterceptor intercepting emailLostPassword
    17:35:02,328 INFO  [STDOUT] *** TracingInterceptor intercepting emailLostPassword
    17:35:02,328 INFO  [STDOUT] *** OtherInterceptor intercepting emailLostPassword
    17:35:02,328 INFO  [STDOUT] *** EmailSystemBean.myBeanInterceptor - username: whatever
    17:35:02,328 INFO  [STDOUT] <In EmailSystemBean.emailLostPassword business method
    17:35:05,343 INFO  [STDOUT] Message sent successfully to remote queue.
    17:35:05,343 INFO  [STDOUT] Exiting EmailSystemBean.emailLostPassword business method>
    17:35:05,343 INFO  [STDOUT] *** OtherInterceptor exiting
    17:35:05,343 INFO  [STDOUT] *** TracingInterceptor invocation of org.jboss.tutorial.interceptor.bean.EmailSystemBean.emailLostPass
    word() took 3015ms
    17:35:05,375 INFO  [STDOUT] *** EmailMDB.mdbInterceptor intercepting
    17:35:05,375 INFO  [STDOUT]
    ----------------
    EMailMDB - Got message, sending email
    ----------------
    17:35:05,375 INFO  [STDOUT] *** DefaultInterceptor exiting

Calling EmailSystemBean.sendBookingConfirmationMessage()

    17:35:07,421 INFO  [STDOUT] *** DefaultInterceptor intercepting sendBookingConfirmationMessage
    17:35:07,421 INFO  [STDOUT] *** TracingInterceptor intercepting sendBookingConfirmationMessage
    17:35:07,437 INFO  [STDOUT] *** OtherInterceptor intercepting sendBookingConfirmationMessage
    17:35:07,437 INFO  [STDOUT] *** AccountsConfirmInterceptor intercepting
    17:35:07,437 INFO  [STDOUT] *** AccountsConfirmInterceptor - recording confirmation
    17:35:07,437 INFO  [STDOUT] *** AccountsConfirmInterceptor - notifying accounts dept sendBookingConfirmationMessage
    17:35:07,437 INFO  [STDOUT] <In EmailSystemBean.sendBookingConfirmationMessage business method
    17:35:07,453 INFO  [STDOUT] *** DefaultInterceptor intercepting onMessage
    17:35:07,453 INFO  [STDOUT]
    ----------------
    AccountsMDB - Got message Confirming order 100
    ----------------
    17:35:07,453 INFO  [STDOUT] *** DefaultInterceptor exiting
    17:35:10,468 INFO  [STDOUT] Message sent successfully to remote queue.
    17:35:10,468 INFO  [STDOUT] Exiting EmailSystemBean.sendBookingConfirmationMessage business method>
    17:35:10,468 INFO  [STDOUT] *** AccountsConfirmInterceptor exiting
    17:35:10,468 INFO  [STDOUT] *** OtherInterceptor exiting
    17:35:10,468 INFO  [STDOUT] *** TracingInterceptor invocation of org.jboss.tutorial.interceptor.bean.EmailSystemBean.sendBookingCo
    nfirmationMessage() took 3031ms
    17:35:10,468 INFO  [STDOUT] *** DefaultInterceptor exiting
    17:35:10,468 INFO  [STDOUT] *** EmailMDB.mdbInterceptor intercepting
    17:35:10,468 INFO  [STDOUT]
    ----------------
    EMailMDB - Got message, sending email
    ----------------

Calling EmailSystemBean.sendBookingConfirmationMessage(), this will be aborted

    17:35:12,484 INFO  [STDOUT] *** DefaultInterceptor intercepting sendBookingConfirmationMessage
    17:35:12,484 INFO  [STDOUT] *** TracingInterceptor intercepting sendBookingConfirmationMessage
    17:35:12,484 INFO  [STDOUT] *** OtherInterceptor intercepting sendBookingConfirmationMessage
    17:35:12,484 INFO  [STDOUT] *** AccountsConfirmInterceptor intercepting
    17:35:12,484 INFO  [STDOUT] *** AccountsConfirmInterceptor - order has already been confirmed aborting
    17:35:12,500 INFO  [STDOUT] *** AccountsConfirmInterceptor exiting
    17:35:12,500 INFO  [STDOUT] *** OtherInterceptor exiting
    17:35:12,500 INFO  [STDOUT] *** TracingInterceptor invocation of org.jboss.tutorial.interceptor.bean.EmailSystemBean.sendBookingCo
    nfirmationMessage() took 16ms
    17:35:12,500 INFO  [STDOUT] *** DefaultInterceptor exiting

Calling EmailSystemBean.sendBookingCancellationMessage(), this will be aborted

    17:35:14,500 INFO  [STDOUT] *** AccountsInterceptor intercepting sendBookingCancellationMessage
    17:35:14,500 INFO  [STDOUT] *** AccountsCancelInterceptor intercepting sendBookingCancellationMessage
    17:35:14,500 INFO  [STDOUT] *** AccountsConfirmInterceptor - notifying accounts dept
    17:35:14,500 INFO  [STDOUT] *** DefaultInterceptor intercepting sendBookingCancellationMessage
    17:35:14,515 INFO  [STDOUT] *** OtherInterceptor intercepting sendBookingCancellationMessage
    17:35:14,515 INFO  [STDOUT] *** TracingInterceptor intercepting sendBookingCancellationMessage
    17:35:14,515 INFO  [STDOUT] <In EmailSystemBean.sendBookingCancellationMessage business method
    17:35:14,515 INFO  [STDOUT] *** DefaultInterceptor intercepting onMessage
    17:35:14,515 INFO  [STDOUT]
    ----------------
    AccountsMDB - Got message Cancelling order 100
    ----------------
    17:35:14,515 INFO  [STDOUT] *** DefaultInterceptor exiting
    17:35:17,625 INFO  [STDOUT] Message sent successfully to remote queue.
    17:35:17,625 INFO  [STDOUT] Exiting EmailSystemBean.sendBookingCancellationMessage business method>
    17:35:17,625 INFO  [STDOUT] *** TracingInterceptor invocation of org.jboss.tutorial.interceptor.bean.EmailSystemBean.sendBookingCa
    ncellationMessage() took 3110ms
    17:35:17,625 INFO  [STDOUT] *** OtherInterceptor exiting
    17:35:17,625 INFO  [STDOUT] *** DefaultInterceptor exiting
    17:35:17,625 INFO  [STDOUT] *** AccountsCancelInterceptor exiting
    17:35:17,640 INFO  [STDOUT] *** AccountsInterceptor exiting
    17:35:17,640 INFO  [STDOUT] *** EmailMDB.mdbInterceptor intercepting
    17:35:17,640 INFO  [STDOUT]
    ----------------
    EMailMDB - Got message, sending email
    ----------------

Calling EmailSystemBean.noop()

    17:35:19,640 INFO  [STDOUT] <In EmailSystemBean.noop business method
    17:35:19,640 INFO  [STDOUT] Exiting EmailSystemBean.noop business method>

Calling EmailSystemBean.noop2()

    17:35:21,640 INFO  [STDOUT] <In EmailSystemBean.noop2 business method
    17:35:21,640 INFO  [STDOUT] Exiting EmailSystemBean.noop2 business method>