5.4.3. Writing JBoss MBean Services
org.jboss.system.Service interface pattern if the custom service is dependent on other services. When a custom MBean depends on other MBean services you cannot perform any service dependent initialization in any of the javax.management.MBeanRegistration interface methods since JMX has no dependency notion. Instead, you must manage dependency state using the Service interface create and/or start methods. You can do this using any one of the following approaches:
- Add any of the
Servicemethods that you want called on your MBean to your MBean interface. This allows your MBean implementation to avoid dependencies on JBoss specific interfaces. - Have your MBean interface extend the
org.jboss.system.Serviceinterface. - Have your MBean interface extend the
org.jboss.system.ServiceMBeaninterface. This is a subinterface oforg.jboss.system.Servicethat addsgetName(),getState(),getStateString()methods.
org.jboss.system.ServiceMBean and your MBean implementation class extend from the abstract org.jboss.system.ServiceMBeanSupport class. This class implements the org.jboss.system.ServiceMBean interface. ServiceMBeanSupport provides implementations of the create, start, stop, and destroy methods that integrate logging and JBoss service state management tracking. Each method delegates any subclass specific work to createService, startService, stopService, and destroyService methods respectively. When subclassing ServiceMBeanSupport, you would override one or more of the createService, startService, stopService, and destroyService methods as required
5.4.3.1. A Standard MBean Example
HashMap into the JBoss JNDI namespace at a location determined by its JndiName attribute to demonstrate what is required to create a custom MBean. Because the MBean uses JNDI, it depends on the JBoss naming service MBean and must use the JBoss MBean service pattern to be notified when the naming service is available.
start and stop methods needed to start up correctly without using any JBoss-specific classes.
Example 5.14. JNDIMapMBean interface and implementation based on the service interface method pattern
package org.jboss.book.jmx.ex1;
// The JNDIMap MBean interface
import javax.naming.NamingException;
public interface JNDIMapMBean
{
public String getJndiName();
public void setJndiName(String jndiName) throws NamingException;
public void start() throws Exception;
public void stop() throws Exception;
}
package org.jboss.book.jmx.ex1;
// The JNDIMap MBean implementation
import java.util.HashMap;
import javax.naming.InitialContext;
import javax.naming.Name;
import javax.naming.NamingException;
import org.jboss.naming.NonSerializableFactory;
public class JNDIMap implements JNDIMapMBean
{
private String jndiName;
private HashMap contextMap = new HashMap();
private boolean started;
public String getJndiName()
{
return jndiName;
}
public void setJndiName(String jndiName) throws NamingException
{
String oldName = this.jndiName;
this.jndiName = jndiName;
if (started) {
unbind(oldName);
try {
rebind();
} catch(Exception e) {
NamingException ne = new NamingException("Failedto update jndiName");
ne.setRootCause(e);
throw ne;
}
}
}
public void start() throws Exception
{
started = true;
rebind();
}
public void stop()
{
started = false;
unbind(jndiName);
}
private void rebind() throws NamingException
{
InitialContext rootCtx = new InitialContext();
Name fullName = rootCtx.getNameParser("").parse(jndiName);
System.out.println("fullName="+fullName);
NonSerializableFactory.rebind(fullName, contextMap, true);
}
private void unbind(String jndiName)
{
try {
InitialContext rootCtx = new InitialContext();
rootCtx.unbind(jndiName);
NonSerializableFactory.unbind(jndiName);
} catch(NamingException e) {
e.printStackTrace();
}
}
}
ServiceMBean interface and ServiceMBeanSupport class. In this version, the implementation class extends the ServiceMBeanSupport class and overrides the startService and stopService methods. JNDIMapMBean also implements the abstract getName method to return a descriptive name for the MBean. The JNDIMapMBean interface extends the org.jboss.system.ServiceMBean interface and only declares the setter and getter methods for the JndiName attribute because it inherits the service life cycle methods from ServiceMBean. This is the third approach mentioned at the start of the Section 5.4.2, “JBoss MBean Services”.
Example 5.15. JNDIMap MBean interface and implementation based on the ServiceMBean interface and ServiceMBeanSupport class
package org.jboss.book.jmx.ex2;
// The JNDIMap MBean interface
import javax.naming.NamingException;
public interface JNDIMapMBean extends org.jboss.system.ServiceMBean
{
public String getJndiName();
public void setJndiName(String jndiName) throws NamingException;
}
package org.jboss.book.jmx.ex2;
// The JNDIMap MBean implementation
import java.util.HashMap;
import javax.naming.InitialContext;
import javax.naming.Name;
import javax.naming.NamingException;
import org.jboss.naming.NonSerializableFactory;
public class JNDIMap extends org.jboss.system.ServiceMBeanSupport
implements JNDIMapMBean
{
private String jndiName;
private HashMap contextMap = new HashMap();
public String getJndiName()
{
return jndiName;
}
public void setJndiName(String jndiName)
throws NamingException
{
String oldName = this.jndiName;
this.jndiName = jndiName;
if (super.getState() == STARTED) {
unbind(oldName);
try {
rebind();
} catch(Exception e) {
NamingException ne = new NamingException("Failed to update jndiName");
ne.setRootCause(e);
throw ne;
}
}
}
public void startService() throws Exception
{
rebind();
}
public void stopService()
{
unbind(jndiName);
}
private void rebind() throws NamingException
{
InitialContext rootCtx = new InitialContext();
Name fullName = rootCtx.getNameParser("").parse(jndiName);
log.info("fullName="+fullName);
NonSerializableFactory.rebind(fullName, contextMap, true);
}
private void unbind(String jndiName)
{
try {
InitialContext rootCtx = new InitialContext();
rootCtx.unbind(jndiName);
NonSerializableFactory.unbind(jndiName);
} catch(NamingException e) {
log.error("Failed to unbind map", e);
}
}
}
examples/src/main/org/jboss/book/jmx/{ex1,ex2} directories.
<!-- The SAR META-INF/jboss-service.xml descriptor -->
<server>
<mbean code="org.jboss.book.jmx.ex1.JNDIMap"
name="j2eechap2.ex1:service=JNDIMap">
<attribute name="JndiName">inmemory/maps/MapTest</attribute>
<depends>jboss:service=Naming</depends>
</mbean>
</server>
HashMap object under the inmemory/maps/MapTest JNDI name and the client code fragment demonstrates retrieving the HashMap object from the inmemory/maps/MapTest location. The corresponding client code is shown below.
// Sample lookup code
InitialContext ctx = new InitialContext();
HashMap map = (HashMap) ctx.lookup("inmemory/maps/MapTest");

Where did the comment section go?
Red Hat's documentation publication system recently went through an upgrade to enable speedier, more mobile-friendly content. We decided to re-evaluate our commenting platform to ensure that it meets your expectations and serves as an optimal feedback mechanism. During this redesign, we invite your input on providing feedback on Red Hat documentation via the discussion platform.