3.2 MBean Construction

Now that we understand the place of MBeans in the world, we're ready to work through the details of implementing them. We'll look at standard MBeans first because their construction is straightforward; then we'll explore the implementation of dynamic MBeans.

3.2.1 Standard MBeans

According to the JMX specification, the Java class of a standard MBean "must implement a Java interface named after the class." We've already seen a couple of standard MBeans in Chapter 2's Quick Tour of JMX (Section 2.6). Let's take another look at the todd Server MBean. The Unified Modeling Language (UML) diagram in Figure 3.3 shows these two components and the relationship between them.

Figure 3.3. The Two Components of a Standard MBean: The Java Class That Represents the Managed Resource and the Interface That Defines the Management Interface to That Resource

graphics/03fig03.gif

The first thing to note is that like every other standard MBean, the Server MBean has two components. The first is the Java class, in this case named Server , and the second is the interface whose name is the corresponding Java class name followed by MBean ” thus ServerMBean in this instance ”which defines the MBean's management interface. Here is the ServerMBean interface:

 public interface ServerMBean {    void shutdown();   void start();   void stop();   Integer getConnections();   Integer getSessions();   Long getUptime(); } 

Applying the JMX specification's lexical design patterns to this interface yields three attributes.

  1. Connections , an Integer -valued, read-only attribute

  2. Sessions , an Integer -valued, read-only attribute

  3. Uptime , a Long -valued, read-only attribute

Figure 3.4 illustrates the application of the lexical design patterns to the interface declarations.

Figure 3.4. Derivation of MBean Attributes and Their Types

graphics/03fig04.gif

Because the other three methods in the ServerMBean interface ” shutdown() , start() , and stop() ”don't fit the attribute pattern, they become the management interface's operations.

The MBeanInfo structure that describes the Server MBean is illustrated in Figure 3.5.

Figure 3.5. The MBeanInfo Object That Describes the Server MBean's Management Interface

graphics/03fig05.gif

Note that all of the Description fields are null. This is one of the drawbacks of standard MBeans: There is no way to provide descriptive information about the management interface ”an attribute's units, its upper or lower bounds, valid parameter values, and so on. This limitation makes it difficult for a GUI to present a useful view of a standard MBean.

Another thing to note about the Server MBean is that it provides a management interface to a resource that exists in the same JVM. That is, the Server class, along with its management interface, is an essential part of the todd application. This arrangement is a common one, but it is not the only possibility. Management applications often need to monitor and control resources "from the outside"; that is, the management application runs in a separate process and accesses the resource via the management interfaces native to the resource, which may include proprietary remote interfaces, command-line utilities, and so on. Mapping those native management interfaces into MBeans provides a uniform access mechanism for management applications.

To see how this works in practice, we'll develop an MBean for the Apache HTTP daemon. Note that although Apache isn't even written in Java, we can use its native management information to create an MBean that provides a JMX-based management application with a wealth of information about a running Apache instance. So exactly what native management information does Apache provide, and how do we access it? The Apache HTTP daemon provides a module, mod_status , that allows administrators to check on the server's performance via a Web browser. When a browser accesses the "server status" page on an Apache server, the server returns an HTML page with the current server statistics. For example, entering the URL http://www.apache.org/server-status in a browser returned the following results:

 Current Time: Saturday, 01-Jun-2002 11:30:42 PDT  Restart Time: Saturday, 25-May-2002 18:46:07 PDT Parent Server Generation: 9 Server uptime: 6 days 16 hours 44 minutes 35 seconds Total accesses: 20035080 - Total Traffic: 1189.8 GB CPU Usage: u149.07 s279.266 cu278.867 cs45.4219 - .13% CPU load 34.6 requests/sec - 2.1 MB/second - 62.3 kB/request 149 requests currently being processed, 43 idle workers 

To simplify things further, you can request the status information in a more "machine-friendly" format by appending ?auto to the URL. Entering http://www.apache.org/server-status?auto in a browser yielded this response:

 Total Accesses: 16019131  Total kBytes: 1297434471 CPULoad: .0984651 Uptime: 520751 ReqPerSec: 30.7616 BytesPerSec: 2551260 BytesPerReq: 82936.6 BusyWorkers: 200 IdleWorkers: 25 Scoreboard: KWKCWWWWWCW_KWWKKKW_WWWWWWWKWKWWKKW_... 

Because fetching URLs is simple in Java and the machine-friendly format is easily parsed, creating a very useful Apache MBean is pretty straightforward. As usual, we start by defining the Apache management interface:

 package net.jnjmx.ch3;  public interface ApacheMBean }   public String DOWN = "DOWN";   public String NOT_RESPONDING = "NOT_RESPONDING";   public String RUNNING = "RUNNING";   public String UNKNOWN = "UNKNOWN";   public int getBusyWorkers() throws ApacheMBeanException;   public int getBytesPerSec()throws ApacheMBeanException;   public float getBytesPerReq()throws ApacheMBeanException;   public long getCacheLifetime();   public float getCpuLoad()throws ApacheMBeanException;   public int getIdleWorkers()throws ApacheMBeanException;   public float getReqPerSec()throws ApacheMBeanException;   public String getScoreboard()throws ApacheMBeanException;   public String getServer();   public String getState();   public int getTotalAccesses()throws ApacheMBeanException;   public long getTotalKBytes()throws ApacheMBeanException;   public long getUptime(throws ApacheMBeanException);   public boolean isCaching();   public void setCacheLifetime(long lifetime);   public void setCaching(boolean caching);   public void setServer(String url) throws MalformedURLException,     IllegalArgumentException;   public int start()throws ApacheMBeanException;   public int stop()throws ApacheMBeanException; } 

The bulk of the management interface expressed by ApacheMBean consists of attributes. Most of the ApacheMBean attributes ” BusyWorkers , BytesPerReq , BytesPerSec , CpuLoad , IdleWorkers , ReqPerSec , Scoreboard , TotalAccesses , TotalKBytes , and Uptime ” are read-only attributes that reflect the values returned by the server-status?auto request. Table 3.1 describes the other four ApacheMBean attributes.

Table 3.1. ApacheMBean Attributes Not Associated with mod_status Information

Attribute

Type

Description

CacheLifetime

Read/write

Gives the length of time, in milliseconds , that the Apache MBean caches information returned by a mod_status request.

Caching

Read/write

Indicates whether or not information returned by a mod_status request will be cached by the Apache MBean. Its value is true by default.

State

Read-only

Represents the Apache MBean's current assumption about the execution state of the Apache server that it's associated with.

Server

Read/write

Holds the URL of the server that the Apache MBean's mod_status requests are directed toward.

The impact of management on a resource should be minimized whenever possible; resources exist to provide a business function, not to generate data for management applications. To that end the Apache MBean supports caching of the results of a mod_status request; when caching is in effect, requests for Apache- related attribute values that occur close together can be satisfied from the cache, reducing the load that the management application imposes on the server and improving the management application's performance. The Caching attribute determines whether or not mod_status results are cached, and the CacheLifetime attribute indicates how long the results are valid.

The State attribute provides a "best guess" at the state of the Apache server with which the MBean is associated. When the MBean is created, the value of the State attribute is ApacheMBean.UNKNOWN . When mod_status results are successfully retrieved, the MBean's State attribute changes to ApacheMBean.RUNNING . What happens when an error ”for example, "unable to connect" or "connection timeout" ”occurs in the course of making a mod_status request? The first time an error occurs, the value of the State attribute becomes ApacheMBean.NOT_RESPONDING ; after three consecutive errors the MBean's State attribute changes to ApacheMBean.DOWN .

Finally, we need a way to tell the Apache MBean where to send its mod_status requests. The Server attribute holds the URL of the Apache instance with which an Apache MBean is associated. The Server attribute is read/write, so this association can change over the course of an Apache MBean's lifetime.

The management interface also specifies two operations: start() and stop() . These methods perform the actions that their names imply, but only if the server is running on the same machine as the management application.

Now that the management interface is fully defined, all we have to do is implement it:

 import java.io.BufferedReader;  import java.io.IOException; import java.io.InputStreamReader; import java.net.MalformedURLException; import java.net.URL; import java.net.URLConnection; import java.util.HashMap; import java.util.StringTokenizer; public class Apache implements ApacheMBean {   // String constants for each of the Apache-related attributes   private static final String BUSY_WORKERS = "BusyWorkers";   private static final String BYTES_PER_REQ = "BytesPerReq";   private static final String BYTES_PER_SEC = "BytesPerSec";   private static final String CPU_LOAD = "CPULoad";   private static final String IDLE_WORKERS = "IdleWorkers";   private static final String REQ_PER_SEC = "ReqPerSec";   private static final String SCOREBOARD = "Scoreboard";   private static final String TOTAL_ACCESSES = "Total Accesses";   private static final String TOTAL_KBYTES = "Total kBytes";   private static final String UPTIME = "Uptime";   private static final int MAX_FAILURES = 3;   private boolean caching = true;   private int failures = 0;   private long lifetime = 1000;   private String state = ApacheMBean.UNKNOWN;   private HashMap status;   private long tzero;   private URL url;   public Apache(String url) throws MalformedURLException,       IllegalArgumentException {     setServer(url);   } 

There are a couple of things to notice about this part of the implementation. The first is that we create a set of String constants, one for each of the Apache attributes that mod_status returns. These constants will be used as keys into the hash map ( java.util.HashMap ) that contains the attribute values. The second is that we have to associate the Apache MBean with an Apache instance when we create it.

Next comes the implementation of the methods specified by the ApacheMBean interface:

 public int getBusyWorkers() throws ApacheMBeanException {    return getIntValue(BUSY_WORKERS); } public int getBytesPerSec() throws ApacheMBeanException {   return getIntValue(BYTES_PER_SEC); } public float getBytesPerReq() throws ApacheMBeanException {   return getFloatValue(BYTES_PER_REQ); } public long getCacheLifetime() {   return this.lifetime; } public float getCpuLoad() throws ApacheMBeanException {   return getFloatValue(CPU_LOAD); } public int getIdleWorkers() throws ApacheMBeanException {   return getIntValue(IDLE_WORKERS); } public float getReqPerSec() throws ApacheMBeanException {   return getFloatValue(REQ_PER_SEC); } public String getScoreboard() throws ApacheMBeanException {   return getStringValue(SCOREBOARD); } public String getServer() {   return this.url.toString(); } public int getState() {   return this.state; } public int getTotalAccesses() throws ApacheMBeanException {   return getIntValue(TOTAL_ACCESSES); } public long getTotalKBytes() throws ApacheMBeanException {   return getLongValue(TOTAL_KBYTES); } public long getUptime() throws ApacheMBeanException {   return getLongValue(UPTIME); } public boolean isCaching() {   return this.caching; } public void setCacheLifetime(long lifetime) {   this.lifetime = lifetime; } public void setCaching(boolean caching) {   this.caching = caching; } public void setServer(String url) throws MalformectURLException,     IllegalArgumentException {   this.url = new URL(url);   if (isStatusUrl(this.url) == false) {     throw new IllegalArgumentException(url.toString()));   }   this.status = new HashMap();   this.state = ApacheMBean.UNKNOWN; } 

There's not much to the implementation of the attribute-related methods. For the most part either they return the value of an instance variable or they call a get Type Value() method; we'll look at the latter in a moment. The most interesting attribute method is setServer() , which is responsible for checking whether the given URL is an appropriate mod_status URL and initializing the hash map of attribute values and the State attribute. Note that in the interest of simplicity, this implementation is not thread-safe; if one thread sets the Server attribute while another thread is fetching attributes, the latter thread will get inconsistent results.

The ApacheMBean management interface has only two operations:

 public int start() {    // platform-specific code to exececute a command shell and   // start Apache   return RUNNING; } public int stop() {   // platform-specific code to exececute a command shell and   // start Apache   return DOWN; } 

The Apache MBean operations start() and stop() work only if the Apache instance the MBean is associated with is running on the same machine as the MBean. If the Apache MBean and its associated Apache instance are collocated, then we can use java.lang.Runtime 's exec () method to execute the appropriate shell command to start or stop the instance.

Now let's look at the private methods where all the work gets done:

 private boolean isStatusUrl(URL url) {    return url.toString().endsWith("server-status?auto"); } 

The isStatusUrl() method just checks to see if the URL under consideration ends in server-status?auto.

The getValue() method is responsible for making mod_status requests, via fetchStatus() , when necessary and retrieving the specified attribute from the hash map of attribute values:

 private String getValue(String value)    throws ApacheMBeanException, NoSuchFieldException, IOException {    String result;    if (updateStatus()) fetchStatus();    if ((result = (String) this.status.get(value)) == null) {      throw new NoSuchFieldException(value);    }    return result; } private float getFloatValue(String value) throws       ApacheMBeanException {   float result;   try {     result = Float.parseFloat((String) getValue(value));   } catch (IOException x) {     throw new ApacheMBeanException(x);   } catch (NoSuchFieldException x) {     throw new ApacheMBeanException(x);     }     return result; } private int getIntValue(String value) throws       ApacheMBeanException {   int result;   try {     result = Integer.parseInt((String) getValue(value));   } catch (IOException x) {     throw new ApacheMBeanException(x);   } catch (NoSuchFieldException x) {     throw new ApacheMBeanException(x);   }   return result; } private long getLongValue(String value) throws       ApacheMBeanException {   long result;   try {     result = Long.parseLong((String) getValue(value));   } catch (IOException x) {     throw new ApacheMBeanException(x);   } catch (NoSuchFieldException x) {     throw new ApacheMBeanException(x);   }   return result; } private String getStringValue(String value) throws       ApacheMBeanException {   String result;   try {     result = (String) getValue(value);   } catch (IOException x) {     throw new ApacheMBeanException(x);   } catch (NoSuchFieldException x) {     throw new ApacheMBeanException(x);   }   return result; } 

The get Type Value() methods call getValue() to retrieve the required attribute and then transform the resulting String value into the appropriate return type. As we saw in the implementation of the Apache-related attribute methods, this suite of methods is the core of the Apache MBean implementation.

Last but not least is the code that actually sends the mod_status request and parses the result into the hash map of attribute values:

 private void fetchStatus() throws ApacheMBeanException,          IOException {     URLConnection k = establishConnection();     readStatus(k);   }   private URLConnection establishConnection()     throws IOException, ApacheMBeanException {     URLConnection k = this.url.openConnection();     try {       k.connect();       this.failures = 0;       this.state = ApacheMBean.RUNNING;     } catch (IOException x) {       if (++this.failures > MAX_FAILURES) {         this.state = ApacheMBean.DOWN;       } else {         this.state = ApacheMBean.NOT_RESPONDING;       }       throw new ApacheMBeanException("state: " + this.state);     }     return k;   }   private void readStatus(URLConnection k) throws IOException {     BufferedReader r = new BufferedReader         (new InputStreamReader(k.getInputStream()));     for (String l = r.readLine(); l != null; l = r.readLine()) {       StringTokenizer st = new StringTokenizer(l, ":");       this.status.put(st.nextToken().trim(),         st.nextToken().trim());     }     r.close();     this.tzero = System.currentTimeMillis();   }   private boolean updateStatus() throws IOException {     boolean result = true;     if (this.caching) {       long now = System.currentTimeMillis();       result = ((now - this.tzero) > this.lifetime);     }     return result;   } } 

The establishConnection() method is responsible for setting up a URLConnection object and for managing the value of the ApacheMBean State attribute on success and failure. The readStatus() method parses the response and populates the hash map. Note that we have hard-coded each of the mod_status attribute labels into our implementation; if they ever change, our code will need to be updated and recompiled.

3.2.2 Dynamic MBeans

Now let's look at dynamic MBeans. To be recognized as a dynamic MBean, the underlying Java class, or one of its ancestors , must implement the DynamicMBean interface. As we saw earlier, this interface consists of six methods that get and set an attribute, or sets thereof, invoke a method, and retrieve the MBean's MBeanInfo metadata.

Standard MBeans assume that the management information associated with the resources they represent is well known in advance ”that is, at development time ”and is relatively static. By contrast, a dynamic MBean can support resource management information that is known only at runtime and is relatively dynamic.

3.2.2.1 MBeanInfo Classes

Figure 3.5 depicts the MBeanInfo structure associated with an MBean. The MBeanServer uses the introspection algorithm described in Section 3.1.2 to construct this structure for standard MBeans. A dynamic MBean is responsible for building its own MBeanInfo structure. This added responsibility creates extra work for developers, but it also makes it possible to present a more flexible management interface. For example, a dynamic MBean representing a service might make a start operation available only when the service is not running and a stop operation available when the service is running. This section describes the classes that dynamic-MBean developers use to construct an MBeanInfo structure that represents a dynamic MBean's management interface.

The MBeanInfo class itself is just a collection of arrays, along with the name of the class that implements the DynamicMBean interface and a human-readable description of the MBean:

 public class MBeanInfo implements Cloneable, Serializable {    public MBeanInfo(String classname,                    String description,                    MBeanAttributeInfo[] attributes,                    MBeanConstructorInfo[] constructors,                    MBeanOperationInfo[] operations,                    MBeanNotificationInfo[] notifications)   { ... }   public Object clone() { ... }   public MBeanAttributeInfo[] getAttributes() { ... }   public MBeanContsturctorInfo[] getConstructors() { ... }   public String getDescription() { ... }   public MBeanNotificationInfo[] getNotifications() { ... }   public MBeanOperationInfo[] getOperations() { ... } } 

All the management interface information is supplied in the constructor and then returned by the getters.

There is a separate array for each of the features of an MBean: attributes, constructors, notifications, and operations. A single base class, MBeanFeatureInfo , captures the information that is common to each of these MBean features ”that is, the feature name and a human-readable description of it:

 public class MBeanFeatureInfo implements Serializable {    public MBeanFeatureInfo(String name, String description) { ... }   public getDescription() { ... }   public getName() { ... } } 

The MBeanAttributeInfo class extends MBeanFeatureInfo with information about the attribute's type and indications of the kind of access ”read, write, or both ”that is provided for the attribute's value:

 public class MBeanAttributeInfo extends MBeanFeatureInfo      implements Cloneable, Serializable {   public MBeanAttributeInfo(String name,                             String descriptions,                             Method getter,                             Method setter)   { ... }   public MBeanAttributeInfo(String name,                             String type,                             String description,                             boolean isReadable,                             boolean isWriteable,                             boolean isIs)   { ... }   public Object clone() { ... }   public String getType() { ... }   public boolean isIs() { ... }   public boolean isReadable() { ... }   public boolean isWriteable() { ... } } 

The first constructor is the only mysterious part of this class definition. It allows developers to supply a reference to the MBean's get and set methods shift the responsibility for figuring out the attribute's type and accessibility to the constructor.

The MBeanConstructorInfo class extends MBeanFeatureInfo with information about the signature of the MBean's constructor:

 public class MBeanConstructorInfo extends MBeanFeatureInfo      implements Cloneable, Serializable {   public MBeanConstructorInfo(String description,     Constructor constructor) { ... }   public MBeanConstructorInfo(String name,                               String description,                               MBeanParameterInfo[] parameters)   { ... }   public Object clone() { ... }   public MBeanParameterInfo[] getSignature() { ... } } 

Again the first constructor takes a reference to the MBean's actual constructor, leaving it up to the MBeanConstructorInfo constructor to figure out the signature information. Note that the signature information is expressed as an array of MBeanParameterInfo instances. The MBeanParameterInfo class extends MBeanFeatureInfo with information about the parameter's type:

 public class MBeanParameterInfo extends MBeanFeatureInfo      implements Cloneable, Serializable {   public MBeanParameterInfo(String name,                             String type,                             String description)   { ... }   public Object clone() { ... }   public String getType() { ... } } 

The MBeanNotificationInfo class extends MBeanFeatureInfo with information about the notification types that the MBean may send:

 public class MBeanNofiticationInfo extends MBeanFeatureInfo      implements Cloneable, Serializable {   public MBeanNotificationInfo(String[] types,                                String name,                                String description) { ... }   public Object clone() { ... }   public String[] getNotifTypes() { ... } } 

We will discuss JMX Notifications in detail at the end of this chapter.

Finally, the MBeanOperationInfo class extends MBeanFeatureInfo with information about the operation: its impact, its return type, and its signature:

 public class MBeanOperationInfo extends MBeanFeatureInfo      implements Cloneable, Serializable {   public MBeanOperationInfo(String description, Method method) { ... }   public MBeanOperationInfo(String name,                             String description,                             MBeanParameterInfo[] signature,                             String returnType,                             int impact)   { ... }   public Object clone() { ... }   public int getImpact() { ... }   public String getReturnType() { ... }   public MBeanParameterInfo[] getSignature() { ... } } 

Like MBeanAttributeInfo and MBeanConstructorInfo , the first MBeanOperationInfo constructor takes a Method reference, so it makes the constructor responsible for determining the signature and return type information. As with constructors, an operation's signature is described by an array of MBeanParameterInfo instances. What about the impact aspect of MBeanOperationInfo ? The impact attribute indicates the impact of the operation on the MBean and can have one of four values:

  • MBeanOperationInfo.ACTION indicates that the operation modifies the MBean's state in some way, typically by modifying a value or altering the configuration.

  • MBeanOperationInfo.ACTION_INFO indicates that the operation modifies the MBean as described for the ACTION impact, and that it returns information regarding the modification. For example, an operation that sets the value of a particular field and returns the field's old value has ACTION_INFO impact.

  • MBeanOperationInfo. INFO indicates that the operation returns some information about the MBean without altering its state.

  • MBeanOperationInfo.UNKNOWN indicates that the nature of the operation's impact is unknown.

We'll see how these classes are used to create a dynamic MBean's MBeanInfo in the next section. Basically we will just use the various constructors to build up the appropriate arrays. Management consoles typically use the get methods provided by these classes to obtain the information they need to create graphical representations of a system's MBeans.

3.2.2.2 Using Dynamic MBeans

Suppose that the resource we're interested in managing is a server-side container that provides a context for services like an HTTP daemon, a servlet engine, or an e-mail transfer agent. Let's suppose further that containers are not one-size-fits-all; a given container might provide features beyond hosting services ”for example, replication, fault tolerance, security.

Using standard MBeans, either we could design a lowest-common-denominator MBean interface, or we could create MBean interfaces that capture each of the extended feature sets. A lowest -common-denominator approach wouldn't allow the management system to manage replication or security features effectively, and the separate-interfaces approach works only if the features can't be composed ”that is, you can't have a secure, replicated container.

The DynamicMBean interface allows us to extend the Container management interface as we extend the feature set. Here is one possible structure for this approach:

 public class Container implements DyanmicMBean {    // Container class and instance variables   ...   // data structures describing the Container management interface   ...   public Container() {     // initialize the instance variables for the base Container     // features     // initialize the data structures for the base management     // interface   }   // Implement the DynamicMBean interface by mapping the data   // structures describing the container management interface into   //  the corresponding MBeanInfo structures   public Object getAttribute(String attrname) { ... }   public AttributeList getAttributes(String[] attrnames) { ... }   public MBeanInfo getMBeanInfo() { ... }   public Object invoke(String method, Object[] params,     String[] signature) { ... }   public void setAttribute(Attribute attr) { ... }   public AttributeList setAttributes(AttributeList attrs) { ... }   // other Container-specific methods used by server applications   ... } public class SimpleSecureContainer extends Container {   // SecureContainer class and instance variables   ...   public SecureContainer() {     super();     // initialization of SecureContainer     // Add information about SecureContainer's management     // interface to the management interface data structures     // The DynamicMBean methods inherited from the base class     // will reflect this additional information in the     // management interface they present to clients   }   // SecureContainer methods   ... } public class ExtendedContainer extends SecureContainer {   // ExtendedContainer class and instance variables   ...   public ExtendedContainer(ContainerExtensionList extensions) {     super();     // initialization of ExtendedContainer     // Add information about ExtendedContainer's management     // interface to the management interface data structures     // The DynamicMBean methods inherited from the base class     // will reflect this additional information in the     // management interface they present to clients }   // ExtendedContainer methods   ... } 

Each Container subclass is an MBean and so can be registered with an MBeanServer. Once a subclass is registered, its MBeanInfo is available to management systems that connect to its MBeanServer. A management console could use MBeanInfo to render a different GUI for SecureContainer and ExtendedContainer objects. Container-aware management systems could inspect MBeanInfo and take advantage of additional capabilities like replication if they are part of the management interface.

Another, simpler, use of the DynamicMBean interface is to implement a management interface for a class that doesn't follow the lexical design patterns of standard MBeans. Recall that the time of day daemon (todd) in the previous chapter's Quick Tour of JMX (Section 2.6) used a queue, implemented by java.util.SortedSet , to hold incoming connection requests. Suppose we wanted to monitor the number of pending requests in the queue so that we could grow the session pool when that number passed a specified threshold. We could create a subclass of SortedSet , making it a standard MBean, or we could use the DynamicMBean interface:

 public class ConnectionQueue implements DynamicMBean {    private SortedSet queue;   private int capacity;   /**    * Construct a new ConnectionQueue instance    * @param queue  a SortedSet that holds incoming connection    * requests    * @param capacity  the maximum capacity of the queue    */   public ConnectionQueue(SortedSet queue, int capacity) {     this.queue = queue;     this.capacity = capacity;   }   /**    * Retrieve the value of the named attribute    * @param attr  name of the attribute of interest    * @return value associated with the named attribute    * @exception AttributeNotFoundException    */   public Object getAttribute(String attr) throws Exception {     Object value = null;     if (attr.compareTo("Length") == 0)         value = new Integer(queue.size());     else if (attr.compareTo("Capacity") == 0)         value = new Integer(capacity);     else throw new AttributeNotFoundException("No such attribute: " + attr);     return value;   }   /**    * Retrieve the values of the named attributes    * @param attrs  array of names of attributes of interest    * @return AttributeList containing an Attribute for each value    * retrieved    */   public AttributeList getAttributes(String[] attrs) {     AttributeList result = new AttributeList();     for (int i = 0; i < attrs.length; i++) {       try {         result.add(new Attribute(attrs[i],             getAttribute(attrs[i]));       } catch (AttributeNotFoundException x) {         System.err.println("No such attribute: " + attrs[i]);       } catch (Exception x) {         System.err.println(x.toString());       }     }     return result;   }   /**    * Retrieve the MBeanInfo metadata for this MBean    * @return ConnectionQueue MBeanInfo instance    */   public javax.management.MBeanInfo getMBeanInfo() {     MBeanAttributeInfo[] attributes = attributeInfo();     MBeanConstructorInfo[] constructors = constructorInfo();     MBeanOperationInfo[] operations = operationInfo();     MBeanNotificationInfo[] notifications = notificationInfo();     return new MBeanInfo("net.jmx.todd.ConnectionQueue",       "todd ConnectionQueue MBean",       attributes,       constructors,       operations,       notifications);   }   /**    * Invoke the named operation    * @param operation  name of the operation to invoke    * @param params  array of parameters to be passed to named    * operation    * @param signature  fully qualified type names for each    * Parameter    * @return result of invocation or 'null' if the operations    * return type is void    */   public Object invoke(String operation, Object[] params,         String[] signature)     throws Exception {     if (operation.compareTo("clear") == 0) {       queue.clear();     }     return null;   }   /**    * Update the value of the named attribute    * @param attr  attribute name and value    */   public void setAttribute(Attribute attr) throws Exception {     if (attr.getName().compareTo("Length") == 0) {       throw new MBeanException(new IllegalArgumentException("Length is read-only"));     } else if (attr.getName().compareTo("Capacity") == 0) {       capacity = ((Integer) attr.getValue()).intValue();     } else throw new AttributeNotFoundException("No such attribute: " + attr.getName());   }   /**    * Update the values of the named attributes    * @param attrs  AttributeList of attribute names and values    * @return AttributeList of the updated names and values    */   public AttributeList setAttributes(AttributeList attrs) {     AttributeList attrsSet = new AttributeList();     ListIterator li = attrs.listIterator();     while (li.hasNext()) {       try {         Attribute attr = (Attribute) li.next();         setAttribute(attr);         attrsSet.add(attr);       } catch (Exception x) {         System.err.println(x.toString());       }     return attrsSet;   }   private MBeanAttributeInfo[] attributeInfo() {     MBeanAttributeInfo[] attributes = new MBeanAttributeInfo[2];     attributes[0] = new MBeanAttributeInfo("Capacity",             "java.lang.Integer",             "Capacity of the Connection queue",             true,             true,             false);     attributes[1] = new MBeanAttributeInfo("Length",             "java.lang.Integer",              "Number of entries currently in the Connection queue",             true,             false,             false);     return attributes;   }   private MBeanConstructorInfo[] constructorInfo() {     MBeanConstructorInfo[] constructors = new MBeanConstructorInfo[1];     MBeanParameterInfo[] signature = new MBeanParameterInfo[2];     signature[0] = new MBeanParameterInfo("requestQueue",               "java.util.SortedSet",               "The Connection queue");     signature[1] = new MBeanParameterInfo("Capacity",               "int",               "The Connection queue capacity");     constructors[0] = new MBeanConstructorInfo("ConnectionQueue",               "Constructor for ConnectionQueue MBeans",               signature);     return constructors;   }   private MBeanNotificationInfo[] notificationInfo() {     return null;   }   private MBeanOperationInfo[] operationInfo() {     MBeanOperationInfo[] operations = new MBeanOperationInfo[1];     operations[0] = new MBeanOperationInfo("clear",               "Remove all entries from the Connection queue",               null,               "void",               MBeanOperationInfo.ACTION);     return operations;   } } 

In the time of day daemon (todd) code, after the Connection queue was instantiated we would register the ConnectionQueue MBean as follows :

 mbs.registerMBean("net.jmx.todd.ConnectionQueue",                    cqobjname,                   new Object[] {connectionQueue },                   new String[] {"java.util.SortedSet" }); 

Once that was done, we could add a monitor that would trigger a notification if the ConnectionQueue 's Length attribute exceeded a specified threshold.

The thing to note here is that the DynamicMBean interface has allowed us to expose certain aspects of the connection queue to a management system without requiring any change to the implementation of the connection queue itself or the code that uses it.

3.2.3 Active MBeans

So far all the MBeans we have seen have been "passive" MBeans. They provide attributes and operations that management systems can use, but they don't take any initiative themselves . For example, the ConnectionQueue class that we created in the previous section doesn't do anything when its capacity is exceeded. If a management system wanted to react to that situation, it would have to create a monitor to check the Capacity attribute periodically. In many cases this sort of separation of concerns reflects a good design. But sometimes an MBean needs to be proactive.

MBeans become "active" through implementation of the NotificationBroadcaster interface:

 public interface NotificationBroadcaster {    void addNotificationListener(NotificationListener listener,                                NotificationFilter filter,                                Object handback);   MBeanNotificationInfo[] getNotificationInfo();   void removeNotificationListener(NotificationLIstener listener); } 

Listeners, classes that implement the NotificationListener interface that we will describe momentarily, may register and deregister interest in an MBean's notifications via the addNotificationListener() and removeNotificationListener() methods. The getNotificationInfo() method returns information about the notifications that an MBean may generate.

JMX provides an implementation of NotificationBroadcaster called NotificationBroadcasterSupport that provides a standard implementation of each of the NotificationBroadcaster methods and an additional sendNotification() method:

 void sendNotification(Notification notification); 

Active MBeans can take advantage of NotificationBroadcasterSupport by using it as a base class that they extend with the methods defined by their MBean interface. We'll see how to do just that with the Apache MBean in a moment. First we need to explain the JMX notification model.

3.2.3.1 JMX Notifications

The JMX notification model has four components:

  1. Notification , a generic class that can be used to signal any sort of management event

  2. NotificationListener , an interface that is implemented by objects that want to receive MBean notifications

  3. NotificationFilter , an interface that is implemented by objects that filter notifications before they are delivered to listeners

  4. NotificationBroadcaster , the interface that we just discussed

The Notification class extends the java.util.EventObject class and serves as a base class for all the other notification subclasses that the JMX specification defines: AttributeChangeNotification , MBeanServerNotification , MonitorNotification , RelationNotification , and TimerNotification . The subclasses will be described in later chapters; the Notification class has the following form:

 public class Notification extends java.util.EventObject {    public Notification(String type, Object source, long seqno) {}   public Notification(String type, Object source, long seqno,     long timestamp) {}   public Notification(String type, Object source, long seqno,     long timestame, String msg) {}   public Notification(String type, Object source, long seqno,     String msg) {}   public String getMessage() {}   public long getSequenceNumber() {}   public Object getSource() {}   public long getTimeStamp() {}   public String getType() {}   public Object getUserData() {}   public void setSequenceNumber(long seqno) {}   public void setSource(Object source) {}   public void setTimeStamp(long timestamp) {}   public void setUserData(Object userdata) {} } 

Here are the pertinent aspects of this set of methods:

  • The source of the message is a reference to either the MBean that is sending the notification or the object name of the MBean sending the notification. Which one it is depends on whether the listener to which the notification is being delivered registered its interest via the MBean itself or via the MBeanServer. In the former case, the source is an object reference; in the latter it is an object name.

  • The message can be any string that the sending MBean wants to deliver to the listener.

  • The user data likewise can be any Java object that the sending MBean wants to deliver to the listener.

  • The time stamp has the obvious meaning: the time, in milliseconds, when the notification was sent.

  • The sequence number requires a little more explanation. The JMX specification defines it as "a serial number identifying a particular instance of notification in the context of the notification broadcaster ."

  • Finally, we have the type of the notification. The type string provides a mechanism that distinguishes one kind of notification from another. The JMX specification defines the type as a set of components separated by dots (.). Taken together, the components convey the meaning of the particular notification. For example, the notification type jmx.monitor.counter.threshold indicates that a counter monitor threshold has been exceeded. All notifications defined by the JMX specification are prefixed by jmx; with the exception of that prefix, MBean developers are free to define additional notification types as appropriate for their applications.

The NotificationListener interface defines a single method:

 public interface NotificationListener {    void handleNotification(Notification notification,     Object handback); } 

When an MBean sends a notification, handleNotification() is called on each of the objects that have expressed interest in the MBean's notifications. The notification that the MBean sent is passed as the first argument, and the object that the listener passed in when it registered its interest is "handed back" to the listener in the second parameter. The listener can use the handback to create additional context regarding the source of the notification.

A listener might not be interested in every notification that an MBean may send. The NotificationFilter interface can be used to filter out notifications that are not of interest:

 public interface NotificationFilter {    boolean isNotificationEnabled(Notification notification); } 

When a listener registers interest in an MBean's notifications, it may specify a filter, a class that implements NotificationFilter . Before a notification is delivered to any listener, the MBean checks to see if the listener has an associated filter. If it does, the notification is delivered only if isNotificationEnabled() returns true .

3.2.3.2 Activating the Apache MBean

Although our Apache MBean is a perfectly good standard MBean, it would be even more useful if a management application could be notified immediately of changes in the State attribute. For example, we might want to page an administrator if the value of the State attribute became ApacheMBean.DOWN . The NotificationBroadcasterSupport class makes it easy to get that behavior:

 public class Apache extends NotificationBroadcasterSupport    implements ApacheMBean { ... // Only the establishConnection method requires a change   private URLConnection establishConnection() throws IOException,         ApacheMBeanException {     String oldstate = this.state;     URLConnection k = this.url.openConnection();     try {       k.connect();       this.failures = 0;       this.state = ApacheMBean.RUNNING;     } catch (IOException x) {       if (++this.failures > MAX_FAILURES) {         this.state = ApacheMBean.DOWN;       } else {         this.state = ApacheMBean.NOT_RESPONDING;       }       throw new ApacheMBeanException("state: " + this.state);     } finally {       if (this.state.compareTo(oldstate) != 0) {         Notification n = new Notification("apache.state." +             this.state,             this,             0);         sendNotification(n);       }     }     return k;   } } 

The ApacheMgr code shows how listening works in this simple example:

  import  java.text.DateFormat;  import  java.util.Date;  import  javax.management.Attribute;  import  javax.management.MBeanServer;  import  javax.management.MBeanServerFactory;  import  javax.management.Notification;  import  javax.management.NotificationListener;  import  javax.management.ObjectName;  public   class  ApacheMgr {  public   static   void  main(String[] args)  throws  Exception {     // Create an MBeanServer to host an ApacheMBean; then create     // an ApacheMBean instance     MBeanServer mbs = MBeanServerFactory.createMBeanServer();     ObjectName apacheon =  new  ObjectName("book/ch3:id=ApacheExample");     mbs.createMBean("net.jnjmx.ch3.Apache",       apacheon,       new Object[] {"http://www.apache.org/server-status?auto" },       new String[] {"java.lang.String" });     // apacheListener will receive the ApacheMBean State change     // notification     NotificationListener apacheListener =  new  NotificationListener() {  public   void  handleNotification(Notification notification,             Object handback) {             // Do something useful here when the notification is             // received         }};     // Listen for the ApacheMBean's State change notification     mbs.addNotificationListener(apacheon, apacheListener,  null,   new  Object());     // At this point the value of State is ApacheMBean.UNKNOWN;     // successfully fetching one of the Apache-related attributes     // will cause it to become ApacheMBean.RUNNING and will     //  result in a notification that will trigger apacheListener     int accesses = mbs.getAttribute(apacheon, "TotalAccesses");     ...  // remainder of the ApacheMgr application   } } 

The main() method of the ApacheMgr class creates an MBeanServer and then creates an instance of Apache ” that is, an Apache MBean ”in the MBeanServer. After that it creates an instance of NotificationListener to respond to Apache MBean State change notifications. In this simple example we just used an anonymous inner class; in a more complex example we might have created a separate class.

3.2.4 Open MBeans

Open MBeans and model MBeans are both types of dynamic MBeans. Model MBeans will be covered in Chapter 4. JMX implementations (1.0 and 1.1) are not required to implement support for open MBeans. The open-MBean interfaces may change in JSR 160 and subsequent JSRs. The JMX 1.0 reference implementation does not provide an implementation of open MBeans. We will give an overview of open MBeans in this chapter, but we will not provide working examples. Programming with open MBeans is much like programming with other dynamic MBeans.

Open MBeans are dynamic MBeans that restrict the allowed data types for their attributes, constructors, and operations to Java primitive types, their respective wrapper objects, String , CompositeData , TabularData , ObjectName , and ArrayType . Using these limited basic types enables serialization and mapping to XML representations. It also removes the need for class loading and proxy coordination between the MBeanServer and remote users of the MBeans. However, it does not remove the need for the program that is processing the open MBean to understand the semantics of the fields. The getMBeanInfo() method of open MBeans returns instances that implement the OpenMBeanInfo interface, which is a specialization of the MBeanInfo class. OpenMBeanInfo adds additional metadata for attributes, operations, and parameters, and it restricts the allowed data types.

3.2.4.1 Basic Data Types

Open MBeans restrict their data to the basic data types, which must be described by OpenType instances in OpenMBeanInfo . The OpenType class is defined as follows:

 public abstract class  OpenType  extends Object implements    Serializable {     protected  OpenType  (String className, String typeName, String       description) {}     abstract boolean  equals  (Object obj) {}     String  getClassName  (){}     String  getDescription  (){}     String  getTypeName  (){}     abstract int  hashCode  (){}     abstract boolean  isArray  (){}     abstract String  toString  (){} 

The basic data types for open MBeans can be divided into four categories: primitives, primitive objects, aggregate types, and ObjectName .

Primitives

Valid primitive Java data types, or scalars, are valid open MBean basic data types, including void , null , integer , byte , short , long , double , float , bool , and char . We describe primitives using the SimpleType class. Here is SimpleType 's definition:

 public final class  SimpleType  extends OpenType implements Serializable {      public static SimpleType  VOID  public static SimpleType  BOOLEAN  public static SimpleType  CHARACTER  public static SimpleType  BYTE  public static SimpleType  SHORT  public static SimpleType  INTEGER  public static SimpleType  LONG  public static SimpleType  FLOAT  public static SimpleType  DOUBLE  public static SimpleType  STRING  public static SimpleType  BIGDECIMAL  public static SimpleType  BIGINTEGER  public static SimpleType  OBJECTNAME  public boolean  isValue  (Object obj)  {}     public boolean  equals  (Object obj) {}     public int  hashCode  () {}     public String  toString  () {}     public Object  readResolve  () throws ObjectStreamException  {} } 
Primitive Objects

Any of the object wrappers for the Java primitive objects are valid open-MBean basic data types. We describe wrappers using the SimpleType class as well. Here is the list of the supported object wrappers:

  • java.lang.Void

  • java.lang.Byte

  • java.lang.Short

  • java.lang.Integer

  • java.lang.Long

  • java.lang.Double

  • java.lang.Float

  • java.lang.Boolean

  • java.lang.Character

  • java.lang.String

Aggregate Types

The aggregate types allow the representation of complex data types. Aggregate data types may contain only other basic data types, including other aggregate types. Therefore aggregate data types can be predictably decomposed into the Java primitive types. Because these are required, standard interfaces and a known set of contained types, programs can process and parse aggregate types, and therefore open MBeans, without having access to any classes beyond the ones supported by JMX itself. This reduces the coordination of class distribution and installation. All aggregate types inherit from the OpenType abstract class. The OpenType interface describes the basic data type and gives you access to its type, description, and class name.

These are the aggregate types:

  • Composite . Hash tables are represented by instances of javax.management.openmbean.CompositeData . Composites may contain any valid basic data type. Values are retrieved by a String name. Values can be set only during instantiation, meaning that once CompositeData is instantiated, it is immutable. CompositeData also contains a method to get the type of the value elements in the hash table. Each value element must be a basic data type. The JMX reference implementation contains an implementation called CompositeDataSupport . CompositeDataSupport has one complete constructor that contains all of its initialization values and one that accepts a Map instance. Here is the CompositeData interface:

     Public interface CompositeData {      public CompositeType getCompositeType()     public Object get(String key) throws     IllegalArgumentException, InvalidKeyException     public Object[] getAll(String[]  keys) throws       IllegalArgumentException, InvalidKeyException     public Collection values()     public boolean containsKey(String key)     public boolean containsValue(Object value)     public boolean equals(Object obj)     public int hashCode()     public String toString() } 
  • These methods are all typical of hash table implementations. Values are retrieved via get() , getAll() , and values() . The values() method returns a collection of the basic data types in the CompositeData instance. The containsValue() and containsKey() methods test if a value or key exists in the CompositeData instance.

  • CompositeData is described by the CompositeType instance that is returned by the getCompositeType() method. CompositeType has one full constructor:

     CompositeType (String typeName,      String description,     String[] itemNames,     String[] itemDescriptions,     OpenType[] itemTypes) 

    The CompositeType interface is

     Public interface CompositeType {      public OpenType getType(String itemName)     public String getDescription(Stirng itemName);     public boolean containsKey(String key)     public boolean isValue(Object obj)public Collection         values()     public boolean equals(Object obj)     public int hashCode()     public Set keySet()     public String toString() } 
  • Table . Tables are represented by instances of javax.management.openmbean.TabularData . Tables are arrays of CompositeData data types. Tables can be modified after instantiation. The TabularData interface is

     public interface  TabularData {  public TabularType  getTabularType  ();     public Object[]  calculateIndex  (CompositeData  value);     public int  size  ();     public boolean  isEmpty  ();     public boolean  containsKey  (Object[]  key);     public boolean  containsValue  (CompositeData value);     public CompositeData  get  (Object[]  key);     public void  put  (CompositeData value);     public CompositeData  remove  (Object[]  key);     public void  putAll  (CompositeData[]  values);     public void  clear  ();     public Set  keySet  ();     public Collection  values  ();     public boolean  equals  (Object obj);     public int  hashCode  ();     public String  toString  (); } 

    These methods are typical methods for accessing tables. The few interesting methods are values() , which returns a collection of the CompositeData instances, and getTabularType() , which returns a TabularType instance . The TabularType instance describes the data in the table. It is immutable for an instance of TabularData .

  • Array . Java array types are described with javax.management.openmbean.ArrayType . All elements in the array must be of the same type. Here is the definition of the class ArrayType :

     public class ArrayType extends OpenType, implements Serializable {      ArrayType(int dimension, OpenType elementType) throws       IllegalArgumentException,       OpenDataException {}     public int getDimension() {}     public OpenType getElementOpenType(){}     public boolean isValue(Object obj) {}     public boolean equals(Object obj) {}     public int hashCode() {}     public String toString() {} } 
ObjectName

The ObjectName type is the javax.management.ObjectName class. This means that open MBeans can refer to other MBeans.

3.2.4.2 OpenMBeanInfo

Open MBeans have their own extension of the MBeanInfo implementation: OpenMBeanInfo . OpenMBeanInfo is an interface with the same methods as MBeanInfo . Because MBeanInfo does not have an interface to accompany it, some strange interfaces are created for OpenMBeanInfo classes that now must define the methods of MBeanInfo and OpenMBeanInfo . This arrangement of interfaces may change in the next major version of JMX, where appropriate interfaces can be developed for the MBeanInfo classes. An OpenMBeanInfo implementation ” OpenMBeanInfoSupport , for example ”must extend MBeanInfo and implement OpenMBeanInfo .

The MBeanAttributeInfo , MBeanOperationInfo , and MBeanConstructorInfo arrays returned by the OpenMBeanInfo instance must be implementations of OpenMBeanAttributeInfo , OpenMBeanOperationInfo , and OpenMBeanConstructorInfo interfaces, respectively. Likewise, MBeanParameterInfo instances returned by MBeanOperationInfo and MBeanConstructorInfo must implement the OpenMBeanParameterInfo interface. However, the MBeanNotificationInfo array still returns MBeanNotificationInfo instances. MBeanNotificationInfo was not extended by the open MBean specification.

One notable quirk of open MBeans is that the OpenMBeanAttributeInfo interface extends the OpenMBeanParameterInfo interface. This relationship between MBeanAttributeInfo and MBeanParameterInfo does not exist in the base MBeanInfo class. Another important quirk is that the OpenMBeanInfo variation consists of a set of interfaces. This is different from MBeanInfo and ModelMBeanInfo , each of which is strictly a set of classes, except for the ModelMBeanInfo interface itself. All OpenMBeanInfo implementations should provide a fully defined constructor:

 OpenMBeanInfoSupport(String className,    String description,   OpenMBeanAttributeInfo[] openAttributes,   OpenMBeanConstructorInfo[] openConstructors,   OpenMBeanOperationInfo[] openOperations,   MBeanNotificationInfo[] notifications); 

Note that the arrays passed in must be of the OpenMBeanInfo types. Here is the OpenMBeanInfo interface:

 public interface  OpenMBeanInfo {  public String  getClassName  ();   public String  getDescription  ();   public MBeanAttributeInfo[]  getAttributes  ();   public MBeanOperationInfo[]  getOperations  ();   public MBeanConstructorInfo[]  getConstructors  ();   public MBeanNotificationInfo[]  getNotifications  ();   public boolean  equals  (Object obj);   public int  hashCode  ();   public String  toString  (); } 

Let's look at the extensions that have been added to the metadata in each of the MBeanInfo elements, MBeanParameterInfo , MBeanAttributeInfo , MBeanConstructorInfo , and MBeanOperationInfo .

  • OpenMBeanParameterInfo

    Some of the methods in this interface reflect the attributes that were already in the MBeanParameterInfo class: name and description . The type attribute in MBeanParameterInfo has been replaced by OpenType . Here is the interface for OpenMBeanParameterInfo :

     public interface OpenMBeanParameterInfo {      public String getDescription();     public String getName();     public OpenType getOpenType();     public Object getDefaultValue();     public Set getLegalValues();     public Comparable getMinValue();     public Comparable getMaxValue();     public boolean hasDefaultValue();     public boolean hasLegalValues();     public boolean hasMinValue();     public boolean hasMaxValue();     public boolean isValue(Object obj);     public boolean equals(Object obj);     public int hashCode();     public String toString(); } 

    You can see that the open MBean adds the DefaultValue , LegalValues , MaxValue , MinValue , and OpenType attributes to MBeanPropertyInfo . In the model MBean, these attributes are captured in the descriptor. The model MBean also adds some simple testers: hasLegalValues() , hasMaxValue() , and hasMinValue() . One interesting method is isValue() , which validates an input object as a legal value for this parameter; it does not test if the parameter has a value. OpenMBeanParameterInfo is used to describe the input parameters for the constructors and operations described by OpenMBeanConstructorInfo and OpenMBeanOperationInfo . Any implementation of OpenMBeanParameterInfo must inherit from MBeanParameterInfo and implement OpenMBeanParameterInfo .

  • OpenMBeanAttributeInfo

    OpenMBeanAttributeInfo inherits from OpenMBeanParameterInfo . The OpenMBeanAttributeInfo interface defines the attributes supported by MBeanAttributeInfo : name , description , type , getter , and setter ; and operations: isIs() , isReadable() , isWritable() . The OpenMBeanAttributeInfo interface adds these operations as extensions to OpenMBeanParameterInfo :

     Public interface OpenMBeanAttributeInfoSupport        extends OpenMBeanParameterInfo {       public boolean  isReadable  ();       public boolean  isWritable  ();       public boolean  isIs  ();       public boolean  equals  (Object obj);       public int  hashCode  ();       public String  toString  (); } 

    The effect is to add the ability to define metadata about attributes like we can about parameters: legal values, default values, minimum value, and maximum value. The operation isValue() also applies to attributes, which permits validation of the attribute values before they are being set. Any implementation of OpenMBeanAttributeInf o must inherit from MBeanAttributeInfo and implement OpenMBeanAttributeInfo .

  • OpenMBeanConstructorInfo

    The OpenMBeanConstructorInfo interface defines all the methods that were defined in MBeanConstructorInfo . No additional metadata is added to MBeanConstructorInfo by OpenMBeanConstructorInfo . Here is the interface for OpenMBeanConstructorInfo :

     public interface OpenMBeanConstructorInfo {      public String getDescription();     public String getName();     public MBeanParameterInfo[] getSignature();     public boolean equals(Object obj);     public int hashCode();     public String toString(); } 

    You should instantiate and use OpenMBeanConstructorInfoSupport implementations just as you do ModelMBeanConstructorInfo implementations. Note that the input signature to the constructor ”that is, the MBeanParameterInfo array ”must contain instances that implement the OpenMBeanParameterInfo array. Any implementation of OpenMBeanConstructorInfo must inherit from MBeanConstructorInfo and implement OpenMBeanConstructorInfo .

  • OpenMBeanOperationInfo

    OpenMBeanOperationInfo defines all the methods from the ModelMBeanInfo class and adds one piece of additional metadata: ReturnOpenType . Here is the interface for OpenMBeanOperationInfo :

     public interface OpenMBeanOperationInfo {  public String getDescription(); public String getName(); public MBeanParameterInfo[] getSignature(); public int getImpact(); public String getReturnType(); public OpenType getReturnOpenType(); public boolean equals(Object obj); public int hashCode(); public String toString(); } 

    Note that the input signature ”that is, the MBeanParameterInfo array ”must contain instances that implement the OpenMBeanParameterInfo array. Any implementation of OpenMBeanOperationInfo must inherit from MBeanOperationInfo and implement OpenMBeanOperationInfo .

3.2.4.3 Using Open MBeans

Programming with open MBeans is very similar to programming with other dynamic MBeans, except that additional data is supplied to the OpenMBeanInfo instance construction. All attributes, constructor parameters, operation parameters, and operation return types must be compliant with the open-MBean basic data types described earlier. It is the responsibility of the developer who creates the open MBeans to comply with these restrictions.

To summarize, the restricted data types and extended metadata facilitate several kinds of functions:

  • Decomposability into Java primitives ensures that open MBeans are easily mapped into XML for portability and remote access.

  • Extended metadata for value checking and validation means that open MBeans are easier to represent in generated management consoles.

  • A limited set of well- understood data types makes open MBeans easier to understand by remote applications without having to import special classes and address the remote class-loading issues for the open MBean

Once the open MBeans specification is finalized and a required part of the specification, they will be a very valuable tool for building MBeans.



Java and JMX. Building Manageable Systems
Javaв„ў and JMX: Building Manageable Systems
ISBN: 0672324083
EAN: 2147483647
Year: 2000
Pages: 115

flylib.com © 2008-2017.
If you may any questions please contact us: flylib@qtcs.net