[ Team LiB ] Previous Section Next Section

A Basic MBean Example

To better understand how WebLogic uses JMX, it will be helpful to first develop our own simple Standard MBean example and see how it works. The main steps for creating a Standard MBean are as follows:

  1. Write the standard MBean interface.

  2. Write a class that implements the standard MBean interface. (If you want to turn some of your existing classes into MBeans, you would write a Standard MBean interface for the class and then have your class implement it.)

  3. Create a JMX agent to register the MBean and manage it.

Let's go over the steps in greater detail with the use of an example. Suppose that we have a climate control application, and we also have a simple class whose only purpose is to set and get the temperature as an integer value.

The first thing we'll do is to write our MBean interface ThermostatMBean.java. We'll use the standard MBean template, and in it we'll define methods to set the temperature, return the temperature, and display the temperature, as in Listing 37.1.

Listing 37.1 ThermostatMBean.java
public interface ThermostatMBean {

  // set the MBean's temperature value
  public void setTemp(int temp);

  // return the MBean's temperature value
  public int getTemp();

  // display the MBean's temperature value
  public void printTemp();

}

Next, we'll write the Thermostat class that provides the implementation for the MBean interface. When we speak of an MBean, we're referring to the class that implements the MBean interface. Remember that MBeans conform to the JavaBean specification, and like all JavaBeans, they should implement java.io.Serializable, and contain private attributes and public getter and setter methods for accessing and changing those attributes.

Our Thermostat class therefore implements ThermostatMBean and Serializable, and defines just one attribute, the temperature, as an integer value. We'll create two constructors: one that takes no object and defines the default temperature value at 0, and a second that takes an integer and sets the initial temperature value to that integer. Finally, we provide an implementation for the setter (setTemp(int temp)), getter (getTemp()), and display (printTemp()) methods in our MBean interface. The completed Thermostat class is shown in Listing 37.2.

Listing 37.2 Thermostat.java
public class Thermostat implements ThermostatMBean, java.io.Serializable {

  // declare an integer variable for the temperature
  private int temp;

  // first constructor
  public Thermostat() {
    this.temp = 0;
  }

  // second constructor
  public Thermostat(int temp) {
    this.temp = temp;
  }

  // set the MBean's temperature value
  public void setTemp(int temp) {
    this.temp = temp;
  }

  // return the MBean's temperature value
  public int getTemp() {
    return temp;
  }

  // print the MBean's temperature value
  public void printTemp() {
    System.out.println( "The temperature is " + temp + " degrees." );
  }

}

The resource we want to manage is the temperature given by the integer attribute. Now that we have our MBean, we must somehow make it available for management. To do that, we require a JMX agent.

Recall from our JMX architecture diagram that the Agent layer provides management services. The next class we create will be our JMX agent. The agent class will create an MBean server instance to contain the MBean, and will register a new instance of our Thermostat MBean.

Before we write the class, we must also think of how the users are going to interface with the MBean. Again, recall the architectural diagram's Distributed layer. The Distributed layer contains the protocols necessary to interact with the MBean, such as HTTP or SNMP.

We'll use a Web interface, so we want to use an HTML adaptor. But how? WebLogic's Administration Console contains the HTTP protocols in its own HTML adaptor for interacting with its MBeans but, unfortunately, it doesn't provide an implementation for our custom-made MBeans. We could spend a lot of time developing our own HTML adaptor, but that would be beyond the scope of this book.

Luckily, Sun provides a free HTML adaptor in its com.sun.jdmk.comm package as part of its JMX Instrumentation and Agent Reference Implementation. Note that this package is contained in the Sun JMX Reference Implementation, and is not part of the standard JMX API. It contains supporting extension classes for JMX. It also contains an HTML server and protocol adaptors necessary for us to view and manage our MBean via a browser interface. To download the Reference Implementation support classes, go to the Sun Web site at

http://java.sun.com/products/JavaManagement/download.html

From the link, download the binary code in the zip file JMX-1_1-ri.zip. After downloading, expand the file and add the .jar file to your system's CLASSPATH statement, such as in the following script:


Set CLASSPATH=%CLASSPATH%;C:\jmx_1.1_ri_bin\lib\jmxri.jar;
C:\jmx_1.1_ri_bin\lib\jmxtools.jar;

Now we can write our JMX agent class, which also contains the HTML adaptor through which we can manage the resource in our MBean. We create a class ThermostatAgent, which imports the javax.management and com.sun.jdmk.comm packages:


import javax.management.*;
import com.sun.jdmk.comm.*;

Next, we create a class variable for the MBean server:


private MBeanServer mbs = null ;

Then we create the constructor, which creates the MBean server and HTML adaptor, registers and identifies the MBean, and registers and starts the HTML adaptor:


public ThermostatAgent() {

In the next line, we create the MBean server by calling the createMBeanServer() method of the MBeanServerFactory class and passing it a String value for the name of this agent's domain, ThermostatAgent. By specifying a JMX agent domain name, the JMX server is able to manage groups of MBeans belonging to that domain:


mbs = MBeanServerFactory.createMBeanServer("ThermostatAgent");

We next create the HTML adaptor:


HtmlAdaptorServer adaptor = new HtmlAdaptorServer();

Remember, we're using the Sun HTML adaptor implementation that provides not only the protocols to communicate with our MBean, but also a Web server to host the Web interface. Next, we create the Thermostat MBean instance:


Thermostat tstat = new Thermostat();

When registering MBeans, the MBean server needs a unique reference to every MBean it manages. We provide this by creating an instance of the javax.management.ObjectName class for every MBean that will be registered with that MBean server. In our example, we need two: one for the HTML adaptor (remember, it's an MBean itself) and one for our custom MBean Thermostat:


ObjectName adaptorName = null;
ObjectName thermostatName = null;

The MBean registrations and HTML adaptor start are done in a try/catch block:


try {

In the next line, we instantiate the ObjectName object. The MBean object name consists of two parts: the domain name and the key/value list. When we instantiated our MBean server, we defined the name of our JMX domain to be ThermostatAgent. The domain name really can be anything because it's used only to provide context for the JMX agent when other agents exist. This isn't related to the WebLogic Server domain entity. The second part of the object name is the key/value list. The key/value list is a mechanism to differentiate MBeans within an MBean server. It's therefore important that the key/value pairs be unique. For our example, we will define the key name and give it the value thermostat1, as in the following:


thermostatName = new ObjectName("ThermostatAgent:name=thermostat1");

We don't need to define our adaptorName object name because it defaults to the name of the class, HtmlAdaptorServer. Next, we can register our MBeans with the MBean server:


mbs.registerMBean(tstat, thermostatName) ;
mbs.registerMBean(adaptor, adaptorName);

We next set the port for the HTTP server provided in the Sun HTML adaptor. The default port is 8082:


adaptor.setPort(8082);

Finally, we can start our HTML adaptor:


    adaptor.start();
  }
  catch(Exception e) {
    e.printStackTrace();
  }
}

Now let's create our main() method. The main() method creates a new MBean agent by calling the ThermostatAgent() constructor:


public static void main(String[] args) {
  ThermostatAgent tagent = new ThermostatAgent();
  System.out.println("ThermostatAgent is running");
}

The complete code for our JMX agent, ThermostatAgent.java, is given in Listing 37.3.

Listing 37.3 ThermostatAgent.java
import javax.management.*;
import com.sun.jdmk.comm.*;

public class ThermostatAgent {

  // declare an MBean server class variable
  private MBeanServer mbs = null;

  // constructor
  public ThermostatAgent() {

    // instantiate the MBean server instance and its 
         //domain "ThermostatAgent"
    mbs = MBeanServerFactory.createMBeanServer("ThermostatAgent");

    // create the HTTP protocol adaptor MBean
    HtmlAdaptorServer adaptor = new HtmlAdaptorServer();

    // create an instance of the Thermostat MBean
    Thermostat tstat = new Thermostat();

    // create the object names for both the adaptor MBean
         // and Thermostat MBean
    ObjectName adaptorName = null;
    ObjectName thermostatName = null;

    try {
      // instantiate the ObjectName instance for Thermostat MBean
      thermostatName = new ObjectName
                ("ThermostatAgent:name=thermostat1");

      // register the Thermostat MBean with the MBean server
      mbs.registerMBean(tstat, thermostatName) ;

      // register the adaptor MBean with the MBean server
      mbs.registerMBean(adaptor, adaptorName);

      // set the adaptor's port (default = 8082)
      adaptor.setPort(8082);

      // start the Web server
      adaptor.start();
    }
    catch(Exception e) {
      e.printStackTrace();
    }
  }

  // main method calls the constructor
  public static void main(String[] args) {
    ThermostatAgent tagent = new ThermostatAgent();
    System.out.println("ThermostatAgent is running");
  }
}

To test our MBean, we can start the JMX agent in a command prompt window with


C:\>java ThermostatAgent

When the JMX agent is started, the Web server also starts. If you coded the example, you should see the ThermostatAgent is running message, as shown in Figure 37.2.

Figure 37.2. ThermostatAgent and HTTP Web server running.

graphics/37fig02.gif

Now that the Web server and JMX agent are running, we can open up a browser window and interact with the JMX server. The URL is host:port, where host is the server name and port is the port number (default = 8082). In our example, we use the hostname localhost and the default port http://localhost:8082, as shown in Figure 37.3.

Figure 37.3. Agent View page.

graphics/37fig03.gif

The default page for our HTML adaptor is the Agent View. The Agent View shows the name of the domain the agent is registered on and also shows all MBeans registered within that domain. In our example, there are three MBeans: the Java management implementation JImplementation, the HtmlAdaptorServer (default name value HtmlAdaptorServer), and our own Thermostat (which we gave the unique name value thermostat1). The Filter by Object Name field enables you to filter the MBean list.

From the Agent View, you can get to the MBean View pages by clicking on the name of the MBean and the Admin View page by clicking on the Admin button.

Let's take a look at the MBean View pages first. Under the JMImplementation domain, click on the MBeanServerDelegate MBean link. This will bring you to the MBean View page for MBeanServerDelegate. The MBean View page displays information such as the MBean's class name, its attributes, and its operations. The list of MBeanServerDelegate's attributes is shown in Figure 37.4.

Figure 37.4. MBean attributes for MBeanServerDelegate.

graphics/37fig04.jpg

The Name column refers to the attribute name, Type shows its object type, Access refers to read-write capability, and finally the Value column shows the present attribute value. Notice in the MBeanServerDelegate MBean that the access is read only (RO). This tells us that each attribute has exposed only its getter method. A write (RW) value would tell us that the setter method is also exposed, enabling us to change the value.

Now let's look at the MBean View page for the HtmlAdaptorServer MBean. From the Agent View page, click on the link for HtmlAdaptorServer under the ThermostatAgent domain. The list of HtmlAdaptorServer's attributes is shown in Figure 37.5.

Figure 37.5. MBean attributes for the HtmlAdaptorServer MBean.

graphics/37fig05.jpg

Notice that some of the attributes, such as Port, have write capability. Recall our adaptor.setPort(8082) method. Because we have write access to the Port attribute, we could change the port number on the fly from within our MBean View page.

Next, let's look at the MBean View page for our Thermostat MBean. From the Agent View page, click on the thermostat1 link under the ThermostatAgent domain. As shown in Figure 37.6, there's only one attribute, temp, for our temperature.

Figure 37.6. MBean attributes for the Thermostat MBean.

graphics/37fig06.gif

There is also one operation, printTemp, which we defined in our printTemp() method. The HTML adaptor Web page conveniently places the operation in a command button. Notice that we can change the value of the temp attribute to some integer, click Apply, and the change is committed. We can prove this by changing the default temp value of 0 to 37 and then clicking the printTemp operation. The printTemp() method is called and a confirmation page is displayed, as shown in Figure 37.7.

Figure 37.7. Operation Success page.

graphics/37fig07.gif

Proof that the value has changed can be seen in the output written to the command window, as in Figure 37.8.

Figure 37.8. Command window confirmation.

graphics/37fig08.gif

We now see the statement The temperature is 37 degrees. You can continue to change the temp attribute within the HTML adaptor Web page and see the results in the command window. If you put in a noninteger value, an InvalidAttributeValueException error is thrown.

The final page is the Admin View. From this page, you can create or unregister MBeans on the fly to the JMX agent without having to write any code. The domain name is given, and by adding the name and value as name=value, and specifying the Java class and class loader, you can create or unregister in the action field, as shown in Figure 37.9.

Figure 37.9. Agent Administration View page.

graphics/37fig09.gif

Registering Custom MBeans in the WebLogic MBean Server

WebLogic has its own built-in adaptors (both HTTP and SNMP) and MBean server that you can use to manage both your own custom MBeans and WebLogic's MBeans.

In the following example, we walk through registering our Thermostat MBean in the WebLogic MBean server. To do this, we create a client class that registers and manages our Thermostat MBean in the WebLogic Server MBean server. The client will be called by a main method, and may optionally take a single String argument representing an integer value to set the temp attribute.

In a text editor, create the client class ThermostatClient.java.

Import the necessary classes:


import weblogic.management.MBeanHome;
import weblogic.management.Helper;
import weblogic.management.RemoteMBeanServer;
import javax.management.*;

Next, our class declaration:


public class ThermostatClient {

Now we'll declare a main function. Recall that our Thermostat MBean has two constructors: one empty and one that takes an integer. In our ThermostatClient class, we can pass to our main method either a String representing an integer value for the temperature or nothing. A String parameter will set and return the Thermostat MBean's temp attribute to that value. Passing in no parameter will return either the Thermostat MBean's default temp value (which we defined in our code as 0) or the current attribute value if the MBean is already registered:


public static void main(String[] args) {

We now need to create an instance of the domain's administration server's MBeanHome. We'll do this through the use of the weblogic.management.Helper class. WebLogic Server provides the Helper class as a utility to obtain the server or administration MBeanHome. The getMBean() method in Helper takes the String values for username, password, and WebLogic Server URL, and the name of the target server in the domain. Our example uses the default username and password of weblogic and weblogic, the server's URL t3://localhost:7001, and the name of the target server, which we'll define as managed server myserver:

NOTE

The JMX specification defines standards for management objects. However, it does not provide a standard for accessing those objects. The server vendor defines how to access a particular MBeanServer. For example, WebLogic uses the Helper class for the server.

What does this do to your MBeans? They're still portable across any other J2EE server. So, you can potentially reuse them. However, the access mechanism changes on a new server.



MBeanHome mbh = Helper.getMBeanHome("weblogic", "weblogic",
"t3://localhost:7001", "myserver");

Next we use our instance of the MBeanHome to obtain an instance of the MBean server running in WebLogic Server. weblogic.management.RemoteMBeanServer implements the javax.management.MBeanServer class, adding the getMBeanServer() method:


RemoteMBeanServer mbs = mbh.getMBeanServer();

We can then call on the many methods contained in the javax.management.MBeanServer parent class to manage the MBean.

Now create an instance of our Thermostat MBean:


Thermostat tstat = new Thermostat();

Then create the object name for the Thermostat MBean:


ObjectName thermostatName = null;

Now, in a try/catch block, we perform the steps to register our MBean with the WebLogic MBean server. We first instantiate our ObjectName:


try {
  thermostatName = new ObjectName("ThermostatAgent:name=thermostat1");

Within the first try/catch block, we use another try/catch block to register the MBean. This will catch a javax.management.InstanceAlreadyExistsException error. When the MBean is registered for the first time, no parameter is sent to the Thermostat MBean class's constructor. The empty constructor is called and the MBean's temp attribute is set to its default value of 0:


Try {
  mbs.registerMBean(tstat, thermostatName);
}
catch(InstanceAlreadyExistsException ie) {
  System.out.println("MBean ("+thermostatName+") is already registered.");
}

Now our Thermostat MBean is registered on the WebLogic MBean server. The next lines of code check whether any String value was passed into the main method of our ThermostatClient class, and if so, change the temp attribute of the Thermostat MBean. This is done in another try/catch block to catch an ArrayIndexOutOfBoundsException error. If there is a passed-in parameter, the code will parse it for its Integer value. Remember, MBeans are managed through the MBean server. To change a runtime attribute value, we use the setAttribute method of the MBean server instance, passing it in the ObjectName value of the MBean, and an instance of the Attribute class.

The Attribute class is an object that contains the String value for the name of the attribute you want to modify along with the new value to which you want it changed. The parameters sent to the Attribute's constructor are important, and the source of some confusion. Let's look at the first parameter for Attribute's constructor, the String name of the attribute we want to manage in our MBean class.

In our example, we want to manage the attribute for the temperature. The String name we want to pass to the constructor is Temp. Recall that in our MBean we defined the private attribute with a lowercase letter t, as in temp. However, the name we're passing comes from the String value parsed from the public method, setTemp, not the attribute name of the lowercase temp! It's from setTemp that we therefore need the uppercase Temp.

Now let's take a look at the second parameter that we pass to Attribute's constructor. This is the Object value that we want to change the MBean attribute. The key here is Object value. Attribute's constructor takes an instance of the super class Object, but not primitives, such as int. That's no problem if you're dealing with an Object, like a String value. But the temp attribute in our MBean is the primitive int. Therefore, we must first convert the String argument passed into the client's main method into the Object class Integer instead of an int. We then pass the Integer value to Attribute's constructor. When passed to the MBean's constructor or setTemp() method, the Integer value will downcast appropriately to int.

Now that we've defined our Attribute object, we can modify our MBean via the MBean server's setAttribute method:


try {
  if(args[0]!=null) {
    Integer i = new Integer(args[0]);
    Attribute att = new Attribute("Temp", i);
    mbs.setAttribute(thermostatName, att);
  }
}
catch(ArrayIndexOutOfBoundsException ae) {
}

If no argument is passed to the client's main method, the attribute will not be modified.

Next we print out the current value of our Thermostat MBean's temperature value by invoking the getAttribute() method on the MBean server. The getAttribute() method takes two parameters: the ObjectName value thermostatName, and the String name of the attribute we want to get, Temp:



      System.out.println("Temperature = ("+thermostatName+") from MBeanServer = "+ mbs
graphics/ccc.gif.getAttribute
(thermostatName, "Temp"));
catch(Exception e) {
  e.printStackTrace();
}

The getAttribute() method, which RemoteMBeanServer inherits from MBeanServer, returns an object of type Object.

To unregister the MBean from the MBean server, we call the unregisterMBean method on the MBean server instance, passing the ObjectName as the parameter, such as:


mbs.unregisterMBean(thermostatName);

You might want to comment out the unregisterMBean method while you're testing. The finished ThermostatClient class is given in Listing 37.4.

Listing 37.4 ThermostatClient.java
import weblogic.management.MBeanHome;
import weblogic.management.Helper;
import weblogic.management.RemoteMBeanServer;
import javax.management.*;

public class ThermostatClient {

  public static void main(String[] args) {

    MBeanHome mbh = Helper.getMBeanHome("weblogic", "weblogic", "t3://localhost:7001",
graphics/ccc.gif "myserver");
    RemoteMBeanServer mbs = mbh.getMBeanServer();

    Thermostat tstat = new Thermostat();

    ObjectName thermostatName = null;

    try {
      thermostatName = new ObjectName("ThermostatDomain
                        :Name=thermostat1");

      try {
        mbs.registerMBean(tstat, thermostatName);
      }
      catch(InstanceAlreadyExistsException ie) {
        System.out.println("MBean ("+thermostatName+") is already registered.");
      }

      try {
        if(args[0]!=null) {
          Integer i = new Integer(args[0]);
          Attribute att = new Attribute("Temp", i);
          mbs.setAttribute(thermostatName, att);
              }
      }
      catch(ArrayIndexOutOfBoundsException ae) {
      }

      System.out.println("Temperature = ("+thermostatName+") from MBeanServer = " + mbs
graphics/ccc.gif.getAttribute(thermostatName, "Temp"));

      //mbs.unregisterMBean(thermostatName);
    }
    catch(Exception e)
    {
      e.printStackTrace();
    }

  }

}

Now let's test the ThermostatClient application in a running instance of WebLogic Server. The following steps register the Thermostat MBean on the WebLogic's MBean server instance, and enable us to test our client application:

  1. First, be sure that you've added our custom Thermostat classes in the WebLogic Server startup classpath.

  2. Now start your WebLogic Server.

  3. Open a new command window, and run the ThermostatClient application.

We have defined the usage as java ThermostatClient [integer]


C:\dev\src\jmx>java ThermostatClient

When ThermostatClient is first registered, it sets the Thermostat MBean's initial value to 0. If a value was passed to the client's main method, the setAttribute method is run on the MBean server instance, and the attribute is then assigned that value. In Figure 37.10, we see the result when no initial value was passed in (0).

Figure 37.10. Initial Thermostat MBean report.

graphics/37fig10.gif

If you've commented out the unregisterMBean method, the MBean remains registered on the MBean server. We can run the ThermostatClient application again, this time passing in a new temperature value to change it to. The application will report that the MBean is already registered, change the Thermostat MBean's temperature attribute to the new value, and then report the attribute's new value, as shown in Figure 37.11.

Figure 37.11. Subsequent Thermostat MBean report.

graphics/37fig11.gif

We've now seen how to create our own custom MBeans, register them in the WebLogic Server MBean server, and run a client that interacts with the MBean via the MBean server. In the next section, we look at how WebLogic Server uses JMX objects to manage its own resources, and how we can access WebLogic Server's own MBeans to use them in our own monitoring applications.

    [ Team LiB ] Previous Section Next Section