JBoss EJB 3.0 and Extensions

  JMX Service Objects
Introduction

JMX MBean services are the core building blocks of the JBoss Application Server. Developers can specify dependency between MBean services so that they are started in a particular order when the server starts, which makes them especially suitable for implementing the server's internal infrastructure services. A lot of JBoss internal services are implemented as MBeans. They communicate with each other via the internal JMX bus (i.e., the JBoss JMX Microkernel). MBeans also provide a unified management interface for JBoss administrators to manage the JBoss internal services.

Different from EJB services, which are provided by a pool of managed objects, a JMX MBean service is provided by a singleton object in the server JVM. This service object is stateful and has an application-wide scope.

While MBean services are very useful, developing them is not trivial. In a regular JMX server environment, you need to extend numerous framework classes and work with reflection-like APIs. However, in the JBoss EJB 3.0 server, you can use simple annotations to configure POJOs and make them available as MBean services. In this trail, you will learn how to develop EJB 3.0 style MBean services. The annotations covered in this trail are JBoss-specific. They are beyond the scope of the official EJB 3.0 specification.

The Sample Application

In this trail, we create a MBean service to perform the investment calculation. To illustrate the manageability aspect of the service, the calculator has a fixed investment growth rate. The growth rate can be changed by an administrator via the JMX management server.

The client application obtains a reference of the MBean singleton object from the container via the JMX API and makes use of its calculation services. Click on the following button to open calculator application in a new window, the JSP page connects to the session bean and uses it to calculate the investment.

To change the growth rate of the calculator (i.e., manage the service), you need to use the JMX management console. Since most server's JMX console is secured, it is difficult to demonstrate this feature on a hosted server. Instead, I made a flash movie to show how to use the JMX console to manage the calculator application and change the growth rate (or interest rate). Please click on the button below to view the movie.

If you deploy the TrailBlazer application on your own server and have access to the JMX console, you can find the calculator MBean at the bottom of the page http://localhost:8080/jmx-console/ and scroll all the way down to the bottom. You can also perform the investment calculation directly from the JMX interface by invoking the calculate() method with appropriate parameters.

The MBean management interface

The MBeans management interface is the outward interface of the MBean service. It exposes all the attributes and methods that can be accessed by the MBean service client as well as the JMX management console. Under the EJB 3.0 programming model, an MBean management interface is just a plain old Java interface similiar to a session bean interface. The following code snippet shows that the Calculator interface defines a Growthrate MBean attribute and a calculate() MBean method.


public interface Calculator {

  // Attribute
  public void setGrowthrate (double g);
  public double getGrowthrate ();

  // The management method
  public double calculate (int start, int end, double saving);

  // Life cycle method
  public void create () throws Exception;
  public void destroy () throws Exception;
}

The management interface also defines MBean life cycle methods. You can define any combination of the following methods.

  • create() -- called by the server when the service is created and all the services it depends upon have been created too. At this point the service (and all the services it depends on) is installed in the JMX server, but is not yet fully functional.
  • start() -- called by the server when the service is started and all the services it depends upon have been started too. At this point the service (and all the services it depends on) is fully functional.
  • stop() -- called by the server when the service is stopped. At this point the service (and all the services that depend on it) is no longer fully operational.
  • destroy() -- called by the server when the service is destroyed and removed from the MBean server.
The MBean implementation

The MBean implementation class simply implements the MBean management interface. It has to be annotated with the @Service tag, so that JBoss knows to register it with the JMX server. The objectName annotation attribute specifies the service name under which this MBean service registers. The @Management annotation specifies which interface is the management interface. This way, you can have multiple local, remote, and management interfaces for the same bean class. So, from the JMX console, you can find this MBean via the name trail:service=calculator.


@Service (objectName="trail:service=calculator")
@Management(Calculator.class)
public class CalculatorMBean implements Calculator {

  double growthrate;

  public void setGrowthrate (double growthrate) {
    this.growthrate = growthrate;
  }

  public double getGrowthrate () {
    return growthrate;
  }

  public double calculate (int start, int end, double saving) {
    double tmp =
        Math.pow(1. + growthrate / 12., 12. * (end - start) + 1);
    return saving * 12. * (tmp - 1) / growthrate;
  }

  // Lifecycle methods
  public void create() throws Exception {
    growthrate = 0.08;
    System.out.println("Calculator - Creating");
  }

  public void destroy() {
    System.out.println("Calculator - Destroying");
  }
}

The create() method is called by the JMX server to set the initial values of the Growthrate attribute when the MBean service singleton is created.

Use the MBean service

To use the MBean service, you first need to find its service singleton stub (or "proxy") via the service name. JBoss JMX provides several convenient methods to do that as shown below.


private Calculator cal = null;

public void jspInit () {
    try {
        MBeanServer server = MBeanServerLocator.locate();

        cal = (Calculator) MBeanProxyExt.create(
            Calculator.class,
            "trail:service=calculator",
            server);
    } catch (Exception e) {
        e.printStackTrace ();
    }
}

Now, you can simply invoke the MBean's service and management methods.


result = nf.format(cal.calculate(start, end, saving));
Dependency between MBeans

An important feature of MBean services is that you can specify the dependency between MBeans so that certain services are only started after other services have already successfully started. You can use the @Depends annotation to declare that an MBean is dependent on another MBean.


@Service (objectName="trail:service=investmentAdvisor")
@Depends ("trail:service=calculator")
public class InvestmentAdvisorMBean implements InvestmentAdvisor {
    // ... ...
}

Or, an MBean can be dependent on a list of other MBeans.


@Service (objectName="trail:service=investmentAdvisor")
@Depends ({"trail:service=calculator",
           "trail:service=riskAnalysis"})
public class InvestmentAdvisorMBean implements InvestmentAdvisor {
    // ... ...
}

If an attribute of an MBean itself is another MBean, the @Depends annotation on the attribute setter method would cause the container to automatically inject the dependent MBean object (setter dependency injection). In the following example, the container calls the setCalculator() method with the right parameter once the trail:service=calculator MBean is started. The Calculator attribute in the InvestmentAdvisor MBean automatically has the correct value without any explicit lookup code.


@Service (objectName="trail:service=investmentAdvisor")
public class InvestmentAdvisorMBean implements InvestmentAdvisor {

    @Depends ("trail:service=calculator")
    public void setCalculator (Calculator calculator) {
      this.calculator = calculator;
    }

    // ... ...
}
Complete code reference

JMX server

JMX client

Summary

In this trail, you learned how to develop JMX MBean services using simple EJB 3.0 style annotations. MBean services are very useful when you need to provide manageable services to other components or services inside the JBoss application server. In the next trail, we discuss another type services: message driven services.