Posts tagged ‘jmx’

JBoss JMX extensions to EJB3

I don’t particularly like developing on JBoss - I think its bloated and slow. But with EJB3 the platform has become more viable. The turn around time to get a relatively complex application with web services etc. done is great.

One thing I like about JBoss 5.x are the JMX extensions to EJB3. Its really amazing how simple installing a JMX MBean is. Let’s say I have to write  a CalculatorService represented by this interface:

package net.ahlawat.cricket;

import javax.ejb.Remote;

import org.jboss.ejb3.annotation.Management;

@Management
@Remote
public interface CalculatorService {
	public double add(double a, double b);
	public double subtract(double a, double b);
	public double performOperation(double a, double b);
	public String getDefaultOperation();
	public void setDefaultOperation(String operation);
}

The interesting annotations here are @Management which tells JBoss deployer that the interface is to be bound as a JMX MBean. The implementation of this bean can be simple pojo - listed here.

package net.ahlawat.cricket;

import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.math.BigDecimal;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.jboss.ejb3.annotation.Service;

@Service(objectName = "ahlawat:service=CalculatorService")
public class CalculatorServiceImpl implements CalculatorService {
	static Log logger = LogFactory.getLog(CalculatorServiceImpl.class);

	Method defaultOperation;

	@Override
	public double add(double a, double b) {
		return a+b;
	}

	@Override
	public String getDefaultOperation() {
		return defaultOperation.getName();
	}

	@Override
	public double performOperation(double a, double b) {
		try {
			BigDecimal bd = (BigDecimal) defaultOperation.invoke(new BigDecimal(a), new BigDecimal(b));
			return bd.doubleValue();
		} catch (IllegalArgumentException e) {
			e.printStackTrace();
		} catch (IllegalAccessException e) {
			e.printStackTrace();
		} catch (InvocationTargetException e) {
			e.printStackTrace();
		}

		return Double.NaN;
	}

	@Override
	public void setDefaultOperation(String operation) {
		try {
			Method m = BigDecimal.class.getMethod(operation, BigDecimal.class);
			logger.info("Setting default operation to " + operation);
			defaultOperation = m;
		} catch (SecurityException e) {
			e.printStackTrace();
		} catch (NoSuchMethodException e) {
			e.printStackTrace();
		}

	}

	@Override
	public double subtract(double a, double b) {
		return a-b;
	}

	//lifecycle methods
	public void create() throws Exception {
		logger.info("Creating service");
	}

	public void start() throws Exception {
		logger.info("Starting service");
		setDefaultOperation("add");
	}
}

The only interesting thing here is @Service - which tells Jboss that this is a singleton bean. And the fact that MBean lifecycle methods like create() and start() are available to be implemented here.

The complete list of life cycle methods are:

   void create() throws Exception;
   void start() throws Exception;
   void stop();
   void destroy();

Once this is jar’d up and deployed to Jboss - you can go to jmx-console and see that the service is visible:

jmx-console

jmx-console

You can also look up the bean using the default JNDI name CalculatorServiceImpl/remote

public class Main {
	public static void main(String[] args) throws Exception {
		InitialContext ctx = new InitialContext();

		CalculatorService cs = (CalculatorService)ctx.lookup("CalculatorServiceImpl/remote");

		System.out.println(cs.add(2.1, 3.2));
	}
}

Here is the jndi.properties:

#jboss JNDI properties
java.naming.factory.initial=org.jnp.interfaces.NamingContextFactory
java.naming.provider.url=jnp://localhost:1099
java.naming.factory.url.pkgs=org.jnp.interfaces

And you can also inject the referece to another EJB using the @EJB annotation like this:

@Stateless
public class PlayerServiceImpl implements PlayerService {
	static Log logger = LogFactory.getLog(PlayerServiceImpl.class);

	@PersistenceContext(unitName = "default")
	EntityManager entityManager;

	@EJB
	CalculatorService calculatorService;

	@PostConstruct
	public void gotCalculator() {
		System.out.println(">>>>>>>>>>>>>>>>>> " + calculatorService.add(1.0, 1.0));
	}

...
}

Really small amount of code and guess what - no XML. I really like it.