Model MBeans





Introduction

Creating instrumentation with MBeans from scratch can be time-consuming and tedious. The JMX model MBean specification[1] provides generic instrumentation that can be quickly customized for many resources. This chapter describes the model MBean in detail and provides multiple examples of its use in practice.

A model MBean is a fully customizable dynamic MBean. The RequiredModelMBean class, which implements the ModelMBean interface, is guaranteed to exist on every JMX agent. A model MBean implements the ModelMBean interface that extends a set of interfaces including DynamicMBean, PersistentMBean, and ModelMBeanNotificationBroadcaster.

Like the open MBean, the model MBean has it's own extended MBeanInfo interface called ModelMBeanInfo. ModelMBeanInfo associates new, extensible metadata objects called descriptors with the management interface. Descriptors add additional information about the managed resource and are also used to customize the behavior of a RequiredModelMBean instance. In this chapter, when we say simply "model MBeans" we are referring to implementations of the model MBean or RequiredModelMBean. When we are referring to the ModelMBean interface, we will say "the ModelMBean interface."

Model MBeans were added to JMX for several reasons:

  • Ease of use for developers. Because model MBeans have an actual implementation class, RequiredModelMBean, as part of every JMX implementation, developers don't need to write their entire MBean and address all of the accompanying support for logging, notifications, errors, persistence, and so on. All of this is provided as part of the RequiredModelMBean implementation. Because it is an actual implementation, you can create subclasses for it and override its behavior with your own. Model MBeans make it possible to instrument your managed resource in as little as five lines of code (not including configuration of the model MBean).

  • Ease of support by development tools. Because model MBeans are fully configurable through metadata kept in descriptors, the creation of ModelMBeanInfo requires either a lot of programmatic setting of metadata or a lot of XML[2] in a file. However, the use of metadata with a portable XML file or API to create it makes it much easier to create and maintain model MBeans with development tools. Part of the intent for model MBeans was to enable the creation of management objects during development by development tools and wizards. Eventually we hope that developing the management objects and interfaces for your application will be as much a part of your application development cycle as developing remote interfaces and logging or tracing support.

  • Common services. Model MBeans support a common set of behaviors in all implementations, including logging, generic notifications, attribute change notifications, persistence, and value caching. These behaviors can be customized and overridden.

  • Dynamic behavior. Model MBeans are completely customized during development or during runtime. During development, the ModelMBeanInfo class supports APIs to customize the management interface and behavior of the model MBean. During runtime, external files, properties files, or XML files can be used to customize the model MBean. Likewise the resource may use the ModelMBeanInfo APIs to customize the model MBean so that it conforms to its own runtime factors.

  • Isolation. Model MBeans isolate the application manageability instrumentation from differences in Java runtimes and JMX implementations. Manageable components today may be installed and used in different editions of Java: J2SE,[3] J2EE,[4] and eventually J2ME.[5] These different JVMs may use different approaches when providing common services to model MBeans. For example, a J2SE JMX RequiredModelMBean implementation may support persistence by writing the data to files. If persistence to a database were required, then RequiredModelMBean would use JDBC[6] directly. However, a J2EE JMX RequiredModelMBean may be implemented as a local EJB[7] or wrapped as a remote EJB and use container-managed persistence. As JMX becomes more pervasive in the J2ME JVMs, these differences in MBean behavior will become more apparent.

    In a J2ME JVM, persistence and logging may not be allowed at all if the JVM is run on a diskless device. Even value caching in memory may be too costly. If you were writing your own MBeans for your component, you would have to write very different MBeans for each of these scenarios. However, because you use the MBeanServer as a factory to instantiate the RequiredModelMBean class that has been supplied by the JMX implementation, your use of the MBean in your managed resource does not change. The JMX implementation is required to make sure that the RequiredModelMBean implementation is appropriate for the installation and current JVM environment. Your investment in instrumentation of your managed resources is protected and requires less development and maintenance.

1 The Simplest Model MBean Example

In this section we will look at a simple example of how to use a model MBean. This example shows how to make a resource manageable in as little as five lines of code. In this example we expose attributes and operations of the managed resource and send a notification upon an error condition.

Recall from Chapter 3, on MBeans, that the Apache server application had its own standard MBean. Let's look at what it would take to create a model MBean for the Apache server. We will have to write a Java utility, ApacheServer, to get the information from the Apache module and return it to the model MBean. In our scenario, the ApacheServer class is similar to the Apache implementation, but it does not implement the ApacheMBean class, and it does not have to support value caching (see Code Block 3 in the text that follows). The model MBean will provide caching support at a much finer grain. The caching policy will be defined in the attribute descriptors in ModelMBeanInfo. Therefore, we don't support the isCaching(), getCacheLifetime(), setCacheLifetime(), getCaching(), and setCaching() methods in the original standard MBean interface. The ApacheServer class is the managed resource.

The first code block that follows shows how to find the MBeanServer, instantiate the model MBean, instantiate ApacheServer, associate it with the model MBean, configure the model MBean, and send a notification if the server is down at this time. The second code block shows how to configure the model MBean through ModelMBeanInfo. Notice that we can selectively cache the data from the Apache server, choosing not to cache some of the more time-sensitive counters. The third code block shows the slightly modified Apache class from Chapter 3. All of the examples in this book (plus some others) are available on the book's Web site: http://www.awprofessional.com/titles/0672324083.

Code Block 1

package jnjmx.ch4; 

import javax.management.*;
import javax.management.modelmbean.*;
import java.lang.reflect.Constructor;
import java.util.ArrayList;

/**
 * @author Heather Kreger
 * Chapter 4:  Java and JMX Building Manageable Systems
 * ApacheServerManager: Manages the ApacheServer as a managed
 * resource using a model MBean.
 *
 * ModelMBeanInfo is created using ModelMBeanInfo APIs
 * rather than an XML file.
 */

public class ApacheServerManager {

  public static void main(String[] args) {
    boolean tracing = false;
    String serverURL = "";
    try {

      if (args.length != 0) {
        System.out.println(args[0]);
        if (args[0] != null)
          serverURL = serverURL.concat(args[0]);
        else
          serverURL = "http://www.apache.org/server-status?auto";
      }
      // This serverURL default mechanism is just for this example
      // We would not recommend this in a real application
      if (!serverURL.startsWith("http"))
        serverURL = "http://www.apache.org/server-status?auto";

      /** Find an MBeanServer for our MBean */
      MBeanServer myMBS = MBeanServerFactory.createMBeanServer();

      /** Instantiate an unconfigured RequiredModelMBean in the MBeanServer */
      RequiredModelMBean apacheMMBean =
        (RequiredModelMBean) myMBS.instantiate(
          "javax.management.modelmbean.RequiredModelMBean");

      /** Create a name for the MBean
       * domain = apacheManager
       * one attribute: id = ApacheServer*/
      ObjectName apacheMBeanName =
        new ObjectName("apacheManager: id=ApacheServer");

      /** Instantiate the ApacheServer utility to be delegated to */
      jnjmx.ch4.ApacheServer myApacheServer =
        new jnjmx.ch4.ApacheServer(serverURL);

      /** Set the configuration of the ModelMBean through the ModelMBeanInfo
       ** This method is below */
      ApacheServerManager asmgr = new ApacheServerManager();
      ModelMBeanInfo apacheMMBeanInfo =
        asmgr.createApacheModelMBeanInfo(
          myApacheServer,
          apacheMBeanName);
      apacheMMBean.setModelMBeanInfo(apacheMMBeanInfo);

      // ** Set the ApacheServer as the managed resource
      apacheMMBean.setManagedResource(myApacheServer, "ObjectReference");

      // ** Register the ModelMBean instance that is now ready to run with the
      // MBeanServer
      ObjectInstance registeredApacheMMBean =
        myMBS.registerMBean((Object) apacheMMBean, apacheMBeanName);

      // ** Use the ModelMBean to send the notification into JMX where it gets
      // sent to a manager adapter that is registered for notifications from the
      // Apache MBeans and sends them to a pager system

      String apacheStatus =
        (String) apacheMMBean.invoke("getState", null, null);
      if ((apacheStatus.equals("DOWN"))
        || (apacheStatus.equals("NOT_RESPONDING"))) {
        System.out.println("Apache Server is Down");
        apacheMMBean.sendNotification("Apache Server is Down");
        /*  You could create monitor to notify when up
         * again so Web traffic can be routed back to it */
      } else
        System.out.println("Apache Server is " + apacheStatus);
    } catch (Exception e) {
      System.out.println(
        "Apache Server Manager failed with " + e.getMessage());
    }
    System.exit(0);
  }

Because model MBeans support the NotificationBroadcaster interface, when the getStatus() method returns Down or Not Responding, we have the model MBean send a notification to the MBeanServer, which in turn sends it to all registered notification listeners. This is fairly simple to do; we merely

  1. Find our MBeanServer.

  2. Instantiate the RequiredModelMBean class using the MBeanServer.

  3. Customize RequiredModelMBean in two steps:

    1. Set up the ModelMBeanInfo instance.

    2. Associate the model MBean with the access to the actual managed resource.

  4. Register RequiredModelMBean with the MBeanServer.

  5. Invoke the model MBean to get the Status attribute.

  6. Send the notification if the status is Down or Stopped. In the downloadable examples for the book, we provide an example of a notification listener for this event that you can experiment with.

Here's how we set the ModelMBeanInfo instance that we used to customize this model MBean. The ModelMBeanInfo object created for the ApacheServer managed application used in the Apache model MBean defines the following:

  • String attributes that are read-only: BusyWorkers, BytesPerSec, BytesPerReq, IdleWorkers, ReqPerSec, Scoreboard, State, TotalAccesses, TotalKBytes, and Uptime

  • String attributes that are read/write: Server

  • Operations: start and stop

  • Notification: ApacheServer Down

  • Operations to support the attributes on the ApacheServer class: getBusyWorkers(), getBytesPerReq(), getBytesPerSec(), getIdleWorkers(), getReqPerSec(), getScoreboard(), getServer(), getState(), getTotalAccesses(), getTotalKBytes(), getUptime(), setServer(String URL)

Code Block 2 illustrates the programmatic way to create a ModelMBeanInfo instance. ModelMBeanInfo can also be initialized from data saved in a file. This is shown in the XML primer examples later in this chapter (see Section 4.7). It is much simpler code, but it requires the use of an XML service that is not a standard service of JMX. This entire method is relatively lengthy, but it is very simple to program and it is easy for tools to generate. The method in its entirety is listed here. We will explain how to set an attribute, an operation, and a notification in the next section.

Code Block 2

// Create the ModelMBeanInfo for the Apache server 
  ModelMBeanInfo createApacheModelMBeanInfo(
    ApacheServer managedApache,
    ObjectName apacheMBeanName) {

    // Set the ApacheServer's class name, there are other
    // more flexible ways to do this
    Class apacheClass = null;
    try {
      apacheClass = Class.forName("jnjmx.ch4.ApacheServer");
    } catch (Exception e) {
      System.out.println("ApacheServer Class not found");
    }

    // Set the MBean's descriptor with default policies
    // MBean name is apacheMBeanName
    // logging notifications to jmxmain.log
    // caching attributes for 10 seconds
    Descriptor apacheDescription =
      new DescriptorSupport(
        new String[] {
          ("name=" + apacheMBeanName),
          "descriptorType=mbean",
          ("displayName=ApacheServerManager"),
          "type=jnjmx.ch4.ApacheServer",
          "log=T",
          "logFile=jmxmain.log",
          "currencyTimeLimit=10" });

    // Define attributes in ModelMBeanAttributeInfo instances

    ModelMBeanAttributeInfo[] apacheAttributes =
      new ModelMBeanAttributeInfo[11];

    // Declare BusyWorkers attribute
    // cache BusyWorkers for 3 seconds,
    // use get method
    Descriptor busyWorkersDesc =
      new DescriptorSupport(
        new String[] {
          "name=BusyWorkers",
          "descriptorType=attribute",
          "displayName=Apache BusyWorkers",
          "getMethod=getBusyWorkers",
          "currencyTimeLimit=3" });

    apacheAttributes[0] =
      new ModelMBeanAttributeInfo(
        "BusyWorkers",
        "int",
        "Apache Server Busy Workers",
        true,
        false,
        false,
        busyWorkersDesc);

    // Declare BytesPerSec attribute
    // Cache ByetesperSec for 10 seconds
    Descriptor bytesPerSecDesc =
      new DescriptorSupport(
        new String[] {
          "name=BytesPerSec",
          "descriptorType=attribute",
          "displayName=Apache BytesPerSec",
          "getMethod=getBytesPerSec",
          "currencyTimeLimit=10" });

    apacheAttributes[1] =
      new ModelMBeanAttributeInfo(
        "BytesPerSec",
        "int",
        "Apache Server Bytes Per Sec",
        true,
        false,
        false,
        bytesPerSecDesc);

    // Declare BytesPerReq attribute
    Descriptor bytesPerReqDesc =
      new DescriptorSupport(
        new String[] {
          "name=BytesPerReq",
          "descriptorType=attribute",
          "displayName=Apache BytesPerReq",
          "getMethod=getBytesPerReq",
          "currencyTimeLimit=10" });

    apacheAttributes[2] =
      new ModelMBeanAttributeInfo(
        "BytesPerReq",
        "int",
        "Apache Server Bytes Per Request",
        true,
        false,
        false,
        bytesPerReqDesc);

    // Declare IdleWorkers attribute
    Descriptor idleWorkersDesc =
      new DescriptorSupport(
        new String[] {
          "name=IdleWorkers",
          "descriptorType=attribute",
          "displayName=Apache IdleWorkers",
          "getMethod=getIdleWorkers",
          "currencyTimeLimit=10" });

    apacheAttributes[3] =
      new ModelMBeanAttributeInfo(
        "IdleWorkers",
        "int",
        "Apache Server Idle Workers",
        true,
        false,
        false,
        idleWorkersDesc);

    // Declare ReqPerSec attribute
    Descriptor reqPerSecDesc =
      new DescriptorSupport(
        new String[] {
          "name=ReqPerSec",
          "descriptorType=attribute",
          "displayName=Apache ReqPerSec",
          "getMethod=getReqPerSec",
          "currencyTimeLimit=5" });

    apacheAttributes[4] =
      new ModelMBeanAttributeInfo(
        "ReqPerSec",
        "int",
        "Apache Server Requests Per Second",
        true,
        false,
        false,
        reqPerSecDesc);

    // Declare Scoreboard attribute
    Descriptor ScoreboardDesc =
      new DescriptorSupport(
        new String[] {
          "name=Scoreboard",
          "descriptorType=attribute",
          "displayName=Apache Scoreboard",
          "getMethod=getScoreboard",
          "currencyTimeLimit=10" });

    apacheAttributes[5] =
      new ModelMBeanAttributeInfo(
        "Scoreboard",
        "java.lang.String",
        "Apache Server Scoreboard",
        true,
        false,
        false,
        ScoreboardDesc);

    // Declare TotalAccesses attribute
    // Do not cache TotalAccesses
    Descriptor totalAccessesDesc =
      new DescriptorSupport(
        new String[] {
          "name=TotalAccesses",
          "descriptorType=attribute",
          "displayName=Apache TotalAccesses",
          "getMethod=getTotalAccesses",
          "currencyTimeLimit=-1" });

    apacheAttributes[6] =
      new ModelMBeanAttributeInfo(
        "TotalAccesses",
        "int",
        "Apache Server total accesses",
        true,
        false,
        false,
        totalAccessesDesc);

    // Declare TotalKBytes attribute
    // Do not cache TotalKBytes
    Descriptor totalKBytesDesc =
      new DescriptorSupport(
        new String[] {
          "name=TotalKBytes",
          "descriptorType=attribute",
          "displayName=Apache TotalKBytes",
          "getMethod=getTotalKBytes",
          "currencyTimeLimit=-1" });

    apacheAttributes[7] =
      new ModelMBeanAttributeInfo(
        "TotalKBytes",
        "int",
        "Apache Server total KiloBytes",
        true,
        false,
        false,
        totalKBytesDesc);

    // Declare Uptime attribute
    Descriptor uptimeDesc =
      new DescriptorSupport(
        new String[] {
          "name=Uptime",
          "descriptorType=attribute",
          "displayName=Apache Uptime",
          "getMethod=getUptime",
          "currencyTimeLimit=10" });
    apacheAttributes[8] =
      new ModelMBeanAttributeInfo(
        "Uptime",
        "java.lang.String",
        "Apache Server Up Time",
        true,
        false,
        false,
        uptimeDesc);

    // Declare State attribute
    // State has a getMethod
    Descriptor stateDesc =
      new DescriptorSupport(
        new String[] {
          "name=State",
          "descriptorType=attribute",
          "displayName=Apache State",
          "getMethod=getState",
          "currencyTimeLimit=10" });

    apacheAttributes[9] =
      new ModelMBeanAttributeInfo(
        "State",
        "java.lang.String",
        "Apache Server state",
        true,
        false,
        false,
        stateDesc);

    // Declare Server attribute
    // Server has a getMethod and a setMethod
    Descriptor serverDesc =
      new DescriptorSupport(
        new String[] {
          "name=Server",
          "descriptorType=attribute",
          "displayName=Apache Server URL",
          "getMethod=getServer",
          "setMethod=setServer",
          "currencyTimeLimit=10" });

      apacheAttributes[10] =
        new ModelMBeanAttributeInfo(
          "Server",
          "java.lang.String",
          "Apache Server Busy Workers",
          true,
          true,
          false,
          serverDesc);

    // Declare constructors for the managed resource
    // one constructor which accepts one parameter,
    // a String URL
    Constructor[] myConstructors = apacheClass.getConstructors();

    ModelMBeanConstructorInfo[] apacheConstructors =
      new ModelMBeanConstructorInfo[1];

    MBeanParameterInfo[] constructorParms =
      new MBeanParameterInfo[] {
        (new MBeanParameterInfo("serverURL",
        "java.lang.String",
        "Apache Server URL"))};

    Descriptor apacheBeanDesc =
      new DescriptorSupport(
        new String[] {
          "name=ApacheServer",
          "descriptorType=operation",
          "role=constructor" });

    apacheConstructors[0] =
      new ModelMBeanConstructorInfo(
        "Apache",
        "ApacheServer(): Constructs an ApacheServer utility class",
        constructorParms,
        apacheBeanDesc);

    // Define operations in ModelMBeanOperationInfo instances
    /* Operations: getBusyWorkers, getBytesPerSec, getBytesPerReq,
      * getIdleWorkers, getReqPerSec, getScoreboard, getTotalAccesses,
      * getTotalKBytes, getUptime are satisfied by getValue, getState,
      * getServer, setServer(String URL), start, stop have own operations */

    // Declare getValue operation String getValue()
    // Set parameter array
    ModelMBeanOperationInfo[] apacheOperations =
      new ModelMBeanOperationInfo[6];
    MBeanParameterInfo[] getParms = new MBeanParameterInfo[0];

    MBeanParameterInfo[] getValueParms =
      new MBeanParameterInfo[] {
        (new MBeanParameterInfo("FieldName",
        "java.lang.String",
        "Apache status field name"))};

    Descriptor getValueDesc =
      new DescriptorSupport(
        new String[] {
          "name=getValue",
          "descriptorType=operation",
          "class=ApacheServer",
          "role=operation" });

    apacheOperations[0] =
      new ModelMBeanOperationInfo(
        "getValue",
        "getValue(): get an apache status field",
        getValueParms,
        "java.lang.String",
        MBeanOperationInfo.INFO,
        getValueDesc);

    Descriptor getStateDesc =
      new DescriptorSupport(
        new String[] {
        "name=getState",
        "descriptorType=operation",
        "class=ApacheServer",
        "role=operation" });


    apacheOperations[1] =
      new ModelMBeanOperationInfo(
        "getState",
        "getState(): current status of apache server",
        getParms,
        "java.lang.String",
        MBeanOperationInfo.INFO,
        getStateDesc);

    Descriptor getServerDesc =
      new DescriptorSupport(new String[] {"name=getServer",
         "descriptorType=operation",
         "class=ApacheServer",
         "role=operation" });

    apacheOperations[2] =
      new ModelMBeanOperationInfo("getServer",
        "getServer(): URL of apache server",
        getParms,
        "java.lang.Integer",
        MBeanOperationInfo.INFO,
        getServerDesc);

    MBeanParameterInfo[] setParms =
      new MBeanParameterInfo[] {
        (new MBeanParameterInfo("url",
        "java.lang.String",
        "Apache Server URL"))};

    Descriptor setServerDesc =
      new DescriptorSupport(new String[] {"name=getServer",
         "descriptorType=operation",
         "class=ApacheServer",
         "role=operation" });

    apacheOperations[3] =
      new ModelMBeanOperationInfo("setServer",
        "getServer(): URL of apache server",
        setParms,
        "java.lang.String",
        MBeanOperationInfo.ACTION,
        setServerDesc);

    MBeanParameterInfo[] startParms = new MBeanParameterInfo[0];

    Descriptor startDesc =
      new DescriptorSupport(new String[] {"name=start",
        "descriptorType=operation",
        "class=ApacheServer",
        "role=operation" });

    apacheOperations[4] = new ModelMBeanOperationInfo("start",
      "start(): start apache server",
      startParms,
      "java.lang.Integer",
      MBeanOperationInfo.ACTION,
      startDesc);

    MBeanParameterInfo[] stopParms = new MBeanParameterInfo[0];
    Descriptor stopDesc = new DescriptorSupport(new String[] {"name=stop",
       "descriptorType=operation",
       "class=ApacheServer",
       "role=operation" });

    apacheOperations[5] = new ModelMBeanOperationInfo("stop",
      "stop(): start apache server",
      stopParms,
      "java.lang.Integer",
      MBeanOperationInfo.ACTION,
      stopDesc);

    /* getters/setters for operations */
    //    MBeanParameterInfo[] getParms = new MBeanParameterInfo[0];

    Descriptor bytespsDesc =
      new DescriptorSupport(new String[] {"name=getBytesPerSecond",
      "descriptorType=operation",
      "class=ApacheServer",
      "role=operation" });

    apacheOperations[6] =
      new ModelMBeanOperationInfo("getBytesPerSecond",
        "number of bytes per second processed",
        getParms,
        "int",
        MBeanOperationInfo.ACTION,
        bytespsDesc);

    // Define notifications in ModelMBeanNotificationInfo
    // declare an "Apache Server Down" notification
    ModelMBeanNotificationInfo[] apacheNotifications =
      new ModelMBeanNotificationInfo[1];

    Descriptor apacheDownEventDesc =
      new DescriptorSupport(
        new String[] {
          "descriptorType=notification",
          "name=jmx.ModelMBean.General.Apache.Down",
          "severity=1",
          "MessageId=Apache001" });

    apacheNotifications[0] =
      new ModelMBeanNotificationInfo(
        new String[] {"jmx.ModelMBean.General.Apache.Down" },
        "jmx.ModelMBean.General",
        "Apache Server Down",
        apacheDownEventDesc);

    // Create the ModelMBeanInfo
    ModelMBeanInfo apacheMMBeanInfo =
      new ModelMBeanInfoSupport(
        "Apache",
        "ModelMBean for managing an Apache Web Server",
        apacheAttributes,
        apacheConstructors,
        apacheOperations,
        apacheNotifications);

    // Set the MBean's Descriptor for the ModelMBeanInfo
    try {
      apacheMMBeanInfo.setMBeanDescriptor(apacheDescription);
    } catch (Exception e) {
      System.out.println("CreateMBeanInfo failed with " + e.getMessage());
    }
    return apacheMMBeanInfo;
  }

Finally, just to complete the example, even though this is basically what's in Chapter 3 as the Apache class, here is the ApacheServer class for getting the data for the Apache server resource we are managing:

Code Block 3

package jnjmx.ch4; 

/**
 * @author Heather Kreger
 * Chapter 4:  Java and JMX: Building Manageable Systems
 * ApacheServer: interacts with an Apache server through a URL
 */

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;
import javax.management.*;

public class ApacheServer {
  // 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;

  // state constants for the Apache Server (brought over from ApacheMBean interface
  public String DOWN = "DOWN";
  public String NOT_RESPONDING = "NOT_RESPONDING";
  public String RUNNING = "RUNNING";
  public String UNKNOWN = "UNKNOWN";

  private int failures = 0;
  private String state = UNKNOWN;
  private long tzero;
  private URL url;

  // constructor that accepts the URL for the Apache server to be managed
  public ApacheServer(String url)
    throws MalformedURLException, IllegalArgumentException {
    setServer(url);
    // test the ability to communicate using the URL
    try {
      getValue(UPTIME);
    } catch (Exception e) {
      System.out.println(
        "Apache server at " + url + " does not respond.");
    }
  }

  // Return the URL of the Apache server being managed
  // Server is a readable and writable attribute because
  // it has a getter and setter
  public String getServer() {
    return this.url.toString();
  }

  // Set the URL of the Apache server being managed
  public void setServer(String url)
    throws MalformedURLException, IllegalArgumentException {
    this.url = new URL(url);
    // test to be sure the URL is really an Apache server URL
    if (isStatusUrl(this.url) == false) {
      throw new IllegalArgumentException(url.toString());
    }
    this.state = ApacheMBean.UNKNOWN;
  }

  // return the current state of the Apache server
  public String getState() {
    return this.state;
  }

  // Example operation for start
  // If this were running in the same JVM, this is
  // where the apache process initialzation would go
  public String start() {
    this.state = RUNNING;
    return this.state;
  }

  // Sample operation for stop
  // If this were running in the same JVM, this is
  // where the Apache process initialization would go
  public String stop() {
    this.state = DOWN;
    return this.state;
  }

  // Validate that the URL is an Apache server status URL
  private boolean isStatusUrl(URL url) {
    return url.toString().endsWith("server-status?auto");
  }

  // Get methods for metrics retrieved via the Apache URL
  // These are read-only attributes because no "setters" are
  // defined for them

  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 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 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);
  }

  // These methods are used as internal utilities by the getter methods
  // There is one for each type returning the base Java type

  private String getValue(String value)
    throws ApacheMBeanException, NoSuchFieldException, IOException {
    String result;
    URLConnection k = establishConnection();

    result = (String) readStatus(k, value);

    if (result == 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;
  }

  // Establishes the connection to the URL
  // If the connection fails, then the state
  // is changed to DOWN or NOT_RESPONDING

  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 = DOWN;
      } else {
        this.state = NOT_RESPONDING;
      }
      throw new ApacheMBeanException("state: " + this.state);
    }
    return k;
  }

  // Parses the data returned from the URL

  private String readStatus(URLConnection k, String value)
    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, ":");
      if (st.nextToken().trim().equals(value)) {
        // if it's the right value
        return (String) (st.nextToken().trim()); // get wanted value
      } else {
        st.nextToken(); // past unwanted value
      }
    }
    return "";
  }

}

Now, let's look at the capabilities of model MBeans in detail.


     Python   SQL   Java   php   Perl 
     game development   web development   internet   *nix   graphics   hardware 
     telecommunications   C++ 
     Flash   Active Directory   Windows