JBoss.org Community Documentation
This section develops a simple MBean that binds a 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.
Version one of the classes, shown in Example 3.14, “JNDIMapMBean interface and implementation based on the service interface method pattern”, is based on the service interface method pattern. This version of the interface declares the start
and stop
methods needed to start up correctly without using any JBoss-specific classes.
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(); } } }
Example 3.14. JNDIMapMBean interface and implementation based on the service interface method pattern
Version two of the classes, shown in Example 3.14, “JNDIMapMBean interface and implementation based on the service interface method pattern”, use the JBoss 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 3.4.2, “JBoss MBean Services”.
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); } } }
Example 3.15. JNDIMap MBean interface and implementation based on the ServiceMBean interface and ServiceMBeanSupport class
The source code for these MBeans along with the service descriptors is located in the examples/src/main/org/jboss/book/jmx/{ex1,ex2}
directories.
The jboss-service.xml descriptor for the first version is shown below.
<!-- 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>
The JNDIMap MBean binds a 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");