JMX MBean services are the core building blocks of the JBoss Application Server. The success of the full Open Source J2EE stack lies with the use of Java Management Extension which provides a common spine that allows the user to integrate modules, containers, and plug-ins.

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. Moreover common IDE have showed a greater attention for other JEE components like EJB which can be developed using simple wizards.

 Until now! In the JBoss EJB 3.0 server, you can use simple annotations to configure POJOs and make them available as MBean services. In other words no mess with invasive frameworks, no configuration files: just a couple of annotations and you have your EJB 3.0's style MBean services.

Not only ! 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).

So how are my MBeans different from EJB services ?

The way you define them is very similar to how you define stateless or stateful session beans.

One very important difference is that there will only ever be ONE instance of the service bean. i.e. it is not pooled - the bean instance is a singleton. The singleton bean contains shared state, so data set by one client is accessible by other clients.

Example simple ServicePOJO. Let's see our first sample.

package sample.jmx;

import org.jboss.annotation.ejb.Service; 
import org.jboss.annotation.ejb.Management;

@Service (objectName="sampleJMX:service=calculateInterest") 
@Management(CalculateInterest.class) 
public class CalculateInterestMBean implements CalculateInterest {

 double interestRate;

 public void setInterestRate (double interestRate) { 
 this.interestRate = interestRate; 
 }

 public double getInterestRate () { 
 return interestRate; 
 }

 public double calculate (double saving, int days) { 
 double interest = (saving * days * this.interestRate)/36500; 
 return interest; 
 }

 // Lifecycle methods 
 public void create() throws Exception { 
 this.interestRate = 5; 
 System.out.println("CalculateInterestMBean - Creating"); 
 }

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

}

Just a plain POJO with @Service annotation: this defines CalculatorInterestMBean as a singleton service in JBoss. It defines the objectName for this MBean as "sampleJMX:service=calculateInterest".

The second annotation is @Management. When JBoss finds this annotation will inspect this interface, and create and install an MBean implementing the attributes and operations defined in the @Management interface.

And here's the implemented interface : no annotations are needed here.

package sample.jmx;

public interface CalculateInterest {

 public void setInterestRate (double interestRate); 
 public double getInterestRate ();

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

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


 

POJO Lifecycle methods

 Just as for "normal" MBeans in JBoss, Service POJOs support lifecycle management, but you don't need to create all these methods. You can pick and choose only those needed by your Service.

If  present in the service, the container will call these methods as follows:

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. At this point all the MBeans that depend on the

Packaging and deploying

Packaging your Service is just a matter of compiling the classes and putting them in a jar file (You can even choose to deploy them as exploder jar folder which is easier for development use)

If you're using an Eclipse based tool simply add to your Project--->Properties--->Java Build Path the library jboss-annotations-ejb3.jar which is found in your JBOSS_HOME/client folder.

If you're compiling with the console just throw a

javac -classpath c:\jboss-4.2.0.GA\client\jboss-annotations-ejb3.jar;. -d . *.java

(Change the JBoss location to your JBoss Home).

Now jar everything:

jar cvf Calculate.jar sample

and copy the Calculate.jar in the "deploy" directory of JBoss. If everything was done correctly you should see in the server logs...

11:03:02,546 INFO [JmxKernelAbstraction] installing MBean: jboss.j2ee:jar=Calculate.jar,name=CalculateInterestMBean,service=EJB3 with dependencies:
11:03:02,593 INFO [EJBContainer] STARTED EJB: sample.jmx.CalculateInterestMBean
ejbName: CalculateInterestMBean
11:03:02,609 INFO [STDOUT] CalculateInterestMBean - Creating
11:03:02,625 INFO [JmxKernelAbstraction]creating wrapper delegate for: org.jboss.ejb3.service.ServiceContainer
11:03:02,625 INFO [JmxKernelAbstraction] installing MBean: jboss.j2ee:jar=Calculate.jar,name=FinancialAdvisorMBean,service=EJB3 with dependencies:
11:03:02,625 INFO [JmxKernelAbstraction] sampleJMX:service=calculateInterest
11:03:02,687 INFO [EJBContainer] STARTED EJB: sample.jmx.FinancialAdvisorMBean ejbName: FinancialAdvisorMBean
11:03:02,703 INFO [STDOUT] FinancialAdvisorMBean - Creating
11:03:02,718 INFO [EJB3Deployer] Deployed: file:/C:/jboss-4.2.0.GA/server/default/deploy/Calculate.jar/

 


 

A minimal client

For the purpose of testing our MBean we'll write a simple JSP Client which will request to our Service the Calculation of an interest rate:

<%@ page import="javax.management.*,sample.jmx.*,org.jboss.mx.util.*" %>
<% CalculateInterest cal = null;

try {
MBeanServer server = MBeanServerLocator.locate();

cal = (CalculateInterest) MBeanProxyExt.create(
CalculateInterest.class,
"sampleJMX:service=calculateInterest",
server);
cal.setInterestRate(7.5); 
out.println("Amount of Interests: " +cal.calculate(10000, 180));

} catch (Exception e) {
e.printStackTrace ();
}
%> 

This will produce as output:

 

Amount of Interests: 369.86301369863014

 

Advanced Service POJOS concepts

 In the previous chapters we have learnt how to develop JMX MBean services using simple EJB 3.0 style annotations. In this trail we'll see how services can collaborate with other services, in other words we'll define the dependencies between services.

Imagine our Interest Calculator application is part of a larger Service, for example

The dependancy of a Service on another Service can be coded with a simple annotation:


@Service (objectName="sampleJMX:service=financialAdvisor")                             
@Management(FinancialAdvisor.class)
@Depends ("sampleJMX:service=calculateInterest")
public class FinancialAdvisorMBean implements FinancialAdvisor { . . . }

The @Depends annotation specifies that this service depends on the service created for calculateInterest. i.e. it cannot be started until the service created for calculateInterest has been started.


What about if your service is dependant on an array of Services ? no problem, simply add a comma to specify the list of dependany services.


@Depends ({"sampleJMX:service=calculateInterest", "sampleJMX:service=calculateLoan"})

Depends injection

One particular type of dependancy is the "Dependancy Injection". With this Instead of annotating the dependancy at Class level the dependencies are specified on fields and setter methods.


@Depends ("sampleJMX:service=calculateInterest")
public void setCalculateInterest(CalculateInterest calculateService)
{
 this.calculateService = calculateService;
}

Here the effect of this annotation is the injection of the Service calculateInterest into our service through a setter method. Those familiar with framework like Spring will find familiar with this pattern.

So let's see a complete example of a Service which is dependant on another:

package sample.jmx;

import org.jboss.annotation.ejb.Depends;
import org.jboss.annotation.ejb.Service;
import org.jboss.annotation.ejb.Management;

@Service(objectName = "sampleJMX:service=financialAdvisor")
@Management(FinancialAdvisor.class)
public class FinancialAdvisorMBean implements FinancialAdvisor {

 private CalculateInterest calculateService;

 public String getAdvice() {

 if (calculateService.getInterestRate() < 5) {
 return "Today you invest with low interest rate";
 } else if (calculateService.getInterestRate() == 5) {
 return "Today you invest with ordinary interest rate";
 } else {
 return "Today you invest with high interest rate";
 }

}

 public CalculateInterest getCalculateInterest() {
 return calculateService;
 }

 @Depends("sampleJMX:service=calculateInterest")
 public void setCalculateInterest(CalculateInterest calculateService) {
 this.calculateService = calculateService;
 }

 public void create() throws Exception {

 System.out.println("FinancialAdvisorMBean - Creating");
 }

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

 

In order to test your application you need the calculateInterest service. In order to compile remember you need to add to the classpath jboss-annotations-ejb3.jar which can be found under JBOSS_HOME/client

javac -classpath c:\jboss-4.2.0.GA\client\jboss-annotations-ejb3.jar;. -d . *.java

now jar everything and deploy :

11:03:02,546 INFO [JmxKernelAbstraction] installing MBean: jboss.j2ee:jar=Calculate.jar,name=CalculateInterestMBean,service=EJB3 with dependencies:
11:03:02,593 INFO [EJBContainer] STARTED EJB: sample.jmx.CalculateInterestMBean
ejbName: CalculateInterestMBean
11:03:02,609 INFO [STDOUT] CalculateInterestMBean - Creating
11:03:02,625 INFO [JmxKernelAbstraction] creating wrapper delegate for: org.jboss.ejb3.service.ServiceContainer
11:03:02,625 INFO [JmxKernelAbstraction] installing MBean: jboss.j2ee:jar=Calculate.jar,name=FinancialAdvisorMBean,service=EJB3 with dependencies:
11:03:02,625 INFO [JmxKernelAbstraction] sampleJMX:service=calculateInterest
11:03:02,687 INFO [EJBContainer] STARTED EJB: sample.jmx.FinancialAdvisorMBean ejbName: FinancialAdvisorMBean
11:03:02,703 INFO [STDOUT] FinancialAdvisorMBean - Creating
11:03:02,718 INFO [EJB3Deployer] Deployed: file:/C:/jboss-4.2.0.GA/server/default/deploy/Calculate.jar/

 This simple application will yield a financial advice depending on the interest rate (which is set by CalculateInterestMBean)

Interceptors

You can define interceptors for your service beans in the same way as shown in EJB3 Interceptors. This example defines one in the ServiceThree bean class itself.   


@AroundInvoke    
public Object intercept(InvocationContext ctx) throws Exception     {       
 System.out.println("Calculator - Interceptor");       
 return ctx.proceed();    
} 



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.

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.

Download the code of this article here.

0
0
0
s2smodern

Related articles available on mastertheboss.com

How to a dump of JNDI tree with JMX console ?

#2 JBoss Howto. This is the recipe of the day

How to configure JBoss to bind to a different IP ?

  If you want to change the jboss.bind.address property use the 

How to shut down JBoss from remote ?

JBoss recipe of the day

How to create multiple instances of an Mbean?

  Supposing you need two instances of an MBean, let's say one fo

JBoss classloader issues

By default JBoss (prior to version 3.2) uses a flat class loading

jboss.xml reference

JBoss xml reference   JBoss AS uses a set of custom xml de