Sunday, July 25, 2010

JBoss: Trace interceptor

Now and then I enhance methods by some log-output like the following:
public void foo() {
logger.trace("--> foo");
try {
/* ... */
} finally {
logger.trace("<-- foo");
}
}
If you have multiple code-locations where you want to add trace-output like above you can do this a little bit easier by making use of interceptors (JBoss documentation).

First of all you may centralize both - the log-statements and the try-finally block - in one single class, let's call it the TraceInterceptor:
public class TraceInterceptor {
private static final Logger logger = Logger.getLogger(TraceInterceptor.class);

@AroundInvoke
public Object intercept(final InvocationContext ctx) throws Exception {
String logMsg = null;
if (logger.isTraceEnabled()) {
logMsg = ctx.getMethod().getDeclaringClass().getSimpleName()
+ "." + ctx.getMethod().getName();
logger.trace("--> " + logMsg);
}
try {
return ctx.proceed();
} finally {
if (logger.isTraceEnabled()) {
logger.trace("<-- " + logMsg);
}
}
}
}
Two things are important: The signature of the intercept-method must be exactly like this and it must be annotated with the @AroundInvoke annotation. When using this interceptor for a method foo of class Bar, the order is as follows:
  1. execute TraceInterceptor.intercept() and log "--> Bar.foo"
  2. ctx.proceed() passes on to the next interceptor or (if no other interceptor is registered) to the actual method being called
  3. after foo-method returns the finally block is executed and the interceptor logs "<-- Bar.foo"
So if we want the TraceInterceptor to intercept the method foo() of class Bar, we may annotate this at the foo() method:
public class Bar {
@Interceptors({ TraceInterceptor.class })
public void foo() {
/* ... */
}
}
Instead of annotating the method you may also place the annotation at class-level so every method would be intercepted. As you can see from the curly braces it is also possible to annotate more than only one interceptor.

JBoss/JMX: Create an MBean in 2 minutes

Components being used:
  • JBoss 5.1
  • JDK 6u20
Let's start by creating a plain interface containing the methods we want our MBean to expose, e.g.:
package de.ollinux.jmx.test;

public interface Test {
public void testSomething();
}
Next we need to create the MBean itself by implementing the above interface:
package de.ollinux.jmx.test;

public class TestMBean {
@Override
public void testSomething() {
/* ... */
}
}
So far so good. But how do we tell JBoss to register this MBean at its MBean-Server? Here we got two options: XML-descriptor vs. annotations. I prefer the second option cause it's less typing and I can specify the MBean-registration directly at my Java class. There are three things I need to describe:
  1. TestMBean is a Management-Bean
  2. Methods contained in the interface Test may be executed
  3. The MBean shall belong to the namespace de.ollinux and shall be called TheTestMBean
These three things may be specified at the MBean itself by using two annotations from the package org.jboss.ejb3.annotation:
@Service(objectName = "de.ollinux:service=TheTestMBean")
@Management(Test.class)
public class TestMBean {
@Override
public void testSomething() {
/* ... */
}
}
I package both class files in a service archive called TestMBean.sar, deploy it to my JBoss and finally the MBean shows up when I connect to the jmx-console and I may execute the testSomething method:

Saturday, July 24, 2010

JBoss: Inject EJB from different EAR

Background
I am currently working on a project using a Java EE 5 application running on JBoss 5.1. I was looking for a way to split this app up into multiple smaller parts to decouple things and to achieve a better modularity. Unfortunately I couldn't find any straight-forward answer to the question:
How to inject an EJB into another EJB if both do not reside in the same EAR?

After spending a couple of hours on research I figured out how to do this and would like to summarize the result hoping that others facing this problem may find this posting helpful.

Let's start...
First of all I start by creating the first EAR file containing the following local-interface and SLSB:
@Local
public interface FooService {
public void foo();
}

@Stateless(name="FooService")
public class FooServiceBean implements FooService {
@Override
public void foo() {
/* ... */
}
}
I package these files into the archive Foo.jar which in turn will be included into the first EAR called Foo.ear (including an appropriate descriptor resources/application.xml).

Next I want to create a second EAR (Bar.ear) which depends upon the one I just packaged. Again there is a local-interface and the appropriate SLSB - both stored within Bar.ear:
@Local
public interface BarService {
public void bar();
}

@Stateless(name="BarService")
public class BarServiceBean implements BarService {
@Override
public void bar() {
/* ... */
}
}


Problem with injection
Now I would like to use FooService (contained in Foo.ear) from my BarServiceBean (contained in Bar.ear). A simple injection like the following

@EJB
private FooService fooService;

is not sufficient and will result in an exception when deploying the Bar.ear:

[org.jboss.kernel.plugins.dependency.AbstractKernelController] (HDScanner) Error installing to Start: name=jboss.j2ee:ear=Bar.ear,jar=Bar.jar,name=BarService,service=EJB3 state=Create
java.lang.NullPointerException
at org.jboss.ejb3.proxy.factory.ProxyFactoryHelper. getRemoteAndBusinessRemoteInterfaces(ProxyFactoryHelper.java:613)


The solution
The dependency to FooService cannot be resolved as it resides in a different EAR file. Therefore I must point my finger to the other EAR when trying to inject the EJB (watch the @EJB annotation):
@Stateless(name="BarService")
public class BarServiceBean implements BarService {

@EJB(mappedName="Foo/FooService/local")
private FooService fooService;

@Override
public void bar() {
this.fooService.foo();
}
}