4 Accessing WebLogic Server MBeans with JMX

The following sections describe how to access WebLogic Server MBeans from a JMX client:

Set Up the Classpath for Remote Clients

If your JMX client runs in its own JVM (that is, a JVM that is not a WebLogic Server instance), include the following JAR file in the client's classpath:

WL_HOME\lib\wljmxclient.jar 

where WL_HOME is the directory in which you installed WebLogic Server.

This JAR contains Oracle's implementation of the HTTP and IIOP protocols. With Oracle's implementation, JMX clients send login credentials with their connection request and the WebLogic Server security framework authenticates the clients. Only authenticated clients can access MBeans that are registered in a WebLogic Server MBean server.

Note:

While Oracle recommends that you use its implementation of the HTTP and IIOP protocols, JMX clients can use the IIOP protocol that is defined in the standard JDK. See Remote Connections Using Only JDK Classes. If T3 protocol is specified, it is automatically converted by the client to use IIOP.

Make Remote Connections to an MBean Server

Each WebLogic Server domain includes three types of MBean servers, each of which provides access to different MBean hierarchies. See MBean Servers.

To connect to a WebLogic MBean server:

  1. Describe the address of the MBean server by constructing a javax.management.remote.JMXServiceURL object.

    Pass the following parameter values to the constructor (see JMXServiceURL in the Java SE 6.0 API Specification at https://download.oracle.com/javase/6/docs/api/javax/management/remote/JMXServiceURL.html):

    • One of the following values as the protocol for communicating with the MBean server:

      t3, t3s, http, https, iiop, iiops 
      
    • Listen address of the WebLogic Server instance that hosts the MBean server

    • Listen port of the WebLogic Server instance

    • Absolute JNDI name of the MBean server. The JNDI name must start with /jndi/ and be followed by one of the JNDI names described in Table 4-1.

    Table 4-1 JNDI Names for WebLogic MBean Servers

    MBean Server JNDI Name

    Domain Runtime MBean Server

    weblogic.management.mbeanservers.domainruntime
    

    Runtime MBean Server

    weblogic.management.mbeanservers.runtime
    

    Edit MBean Server

    weblogic.management.mbeanservers.edit
    

  2. Construct a javax.management.remote.JMXConnector object. This object contains methods that JMX clients use to connect to MBean servers.

    The constructor method for JMXConnector is:

    javax.management.remote.JMXConnectorFactory.
    connector(JMXServiceURL serviceURL, Map<String,?> environment) 
    

    Pass the following parameter values to the constructor (see JMXConnectorFactory in the Java SE 6.0 API Specification at https://download.oracle.com/javase/6/docs/api/javax/management/remote/JMXConnectorFactory.html):

    • The JMXServiceURL object you created in the previous step.

    • A hash map that contains the following name-value pairs:

      javax.naming.Context.SECURITY_PRINCIPAL, admin-user-name 
      
      javax.naming.Context.SECURITY_CREDENTIALS, admin-user-password 
      
      javax.management.remote.JMXConnectorFactory.PROTOCOL_PROVIDER_PACKAGES, 
      "weblogic.management.remote" 
      

    The weblogic.management.remote package defines the protocols that can be used to connect to the WebLogic MBean servers. Remote JMX clients must include the classes in this package on their classpath. See Set Up the Classpath for Remote Clients.

    Optionally include the following name-value pair in the hash map:

    jmx.remote.x.request.waiting.timeout, milliseconds 
    

    where milliseconds is a java.lang.Long object that contains the number of milliseconds that your JMX client waits for the invocation of an MBean-server method to return. If a method does not return by the end of the timeout period, the client moves to its next set of instructions. By default, a client waits indefinitely for a method to return; if the MBean server is unable to complete an invocation, the JMX client will hang indefinitely.

  3. Connect to the WebLogic MBean server by invoking the JMXConnector.getMBeanServerConnection() method.

    The method returns an object of type javax.management.MBeanServerConnection.

    The MBeanServerConnection object is your connection to the WebLogic MBean server. You can use it for local and remote connections. See MBeanServerConnection in the Java SE 6.0 API Specification at https://download.oracle.com/javase/6/docs/api/javax/management/MBeanServerConnection.html.

  4. Oracle recommends that when your client finishes its work, close the connection to the MBean server by invoking the JMXConnector.close() method.

Example: Connecting to the Domain Runtime MBean Server

Note the following about the code in Example 4-1:

  • The class uses global variables, connection and connector, to represent the connection to the MBean server. The initConnection() method, which assigns the value to the connection and connector variables, should be called only once per class instance to establish a single connection that can be reused within the class.

  • The initConnection() method takes the username and password (along with the server's listen address and listen port) as arguments that are passed when the class is instantiated. Oracle recommends this approach because it prevents your code from containing unencrypted user credentials. The String objects that contain the arguments will be destroyed and removed from memory by the JVM's garbage collection routine.

  • Because the client sets the jmx.remote.x.request.waiting.timeout environment parameter to 10000, all of its invocations of MBean server methods will time out if the method does not return within 10000 milliseconds of being invoked.

  • When the class finishes its work, it invokes JMXConnector.close() to close the connection to the MBean server. (See JMXConnector in the Java SE 6.0 API Specification at https://download.oracle.com/javase/6/docs/api/javax/management/remote/JMXConnector.html.)

Example 4-1 Connecting to the Domain Runtime MBean Server

public class MyConnection {

   private static MBeanServerConnection connection;
   private static JMXConnector connector;
   private static final ObjectName service;
   /*
   * Initialize connection to the Domain Runtime MBean Server.
   */
   public static void initConnection(String hostname, String portString,
      String username, String password) throws IOException,
      MalformedURLException {

      String protocol = "t3";
      Integer portInteger = Integer.valueOf(portString);
      int port = portInteger.intValue();
      String jndiroot = "/jndi/";
      String mserver = "weblogic.management.mbeanservers.domainruntime";
      JMXServiceURL serviceURL = new JMXServiceURL(protocol, hostname, port,
      jndiroot + mserver);

      Hashtable h = new Hashtable();
      h.put(Context.SECURITY_PRINCIPAL, username);
      h.put(Context.SECURITY_CREDENTIALS, password);
      h.put(JMXConnectorFactory.PROTOCOL_PROVIDER_PACKAGES,
         "weblogic.management.remote");
      h.put("jmx.remote.x.request.waiting.timeout", new Long(10000));
      connector = JMXConnectorFactory.connect(serviceURL, h);
      connection = connector.getMBeanServerConnection();
   }

   public static void main(String[] args) throws Exception {
      String hostname = args[0];
      String portString = args[1];
      String username = args[2];
      String password = args[3];

      MyConnection c= new MyConnection();
      initConnection(hostname, portString, username, password);
...
      connector.close();
   }
}

Best Practices: Choosing an MBean Server

A WebLogic Server domain maintains three types of MBean servers, each of which fulfills a specific function. Access MBeans through the MBean server that supports the task you are trying to complete:

  • To modify the configuration of the domain, use the Edit MBean Server.

  • To monitor changes to the pending hierarchy of configuration MBeans, use the Edit MBean Server.

  • To monitor only active configuration MBeans (and not run-time MBeans), use a Runtime MBean Server.

    Monitoring through a Runtime MBean Server requires less memory and network traffic than monitoring through the Domain Runtime MBean Server. (WebLogic Server does not initialize the Domain Runtime MBean Server until a client requests a connection to it.)

    In most cases, all server instances in the domain have the same set of configuration data and it therefore does not matter whether you monitor the Runtime MBean Server on the Administration Server or on a Managed Server. However, if you make a change that a server cannot consume until it is restarted, the server will no longer accept any changes and its configuration data could become outdated. In this case, monitoring this server's Runtime MBean Server indicates only the configuration for the specific server instance. To understand the process of changing a WebLogic Server domain and activating the changes, see "Managing Configuration Changes" in Understanding Domain Configuration for Oracle WebLogic Server.

  • If your client monitors run-time MBeans for multiple servers, or if your client runs in a separate JVM, Oracle recommends that you connect to the Domain Runtime MBean Server on the Administration Server instead of connecting separately to each Runtime MBean Server on each server instance in the domain.

    If you register a JMX listener and filter with an MBean in the Domain Runtime MBean Server, the JMX filter runs in the same JVM as the MBean it monitors. For example, if you register a filter with an MBean on a Managed Server, the filter runs on the Managed Server and forwards only messages that satisfy the filter criteria to the listener.

    In general, code that uses the Domain Runtime MBean Server is easier to maintain and is more secure for the following reasons:

    • Your code only needs to construct a single URL for connecting to the Domain Runtime MBean Server on the Administration Server. Thereafter, the code can look up values for all server instances and optionally filter the results.

    • If your code uses the Runtime MBean Server to read MBean values on multiple server instances, it must construct a URL for each server instance, each of which has a unique listen address/listen port combination.

    • You can route all administrative traffic in a WebLogic Server domain through the Administration Server's secured administration port, and you can use a firewall to prevent connections to Managed Server administration ports from outside the firewall.

    The trade off for directing all JMX requests through the Domain Runtime MBean Server is a slight degradation in performance due to network latency and increased memory usage. Connecting directly to each Managed Servers's Runtime MBean Server to read MBean values eliminates the network hop that the Domain Runtime MBean Server makes to retrieve a value from a Managed Server. However, for most network topologies and performance requirements, the simplified code maintenance and enhanced security that the Domain Runtime MBean Server enables is preferable.

Figure 4-1 Domain Runtime MBean Server versus Runtime MBean Server

Description of Figure 4-1 follows
Description of "Figure 4-1 Domain Runtime MBean Server versus Runtime MBean Server"

Remote Connections Using Only JDK Classes

Oracle recommends that you use WebLogic Server classes to connect from remote JMX clients. However, it is possible for remote JMX clients to connect to a WebLogic Server JMX agent using only the classes in the JDK. To do so:

  1. If wljmxclient.jar and wlclient.jar are not in the client classpath:

    1. Enable the IIOP protocol for the WebLogic Server instance that hosts your MBeans.

    2. Configure the default IIOP user to be a WebLogic Server user with Administrator privileges.

    See "Enable and Configure IIOP" in Administration Console Online Help.

    If wljmxclient.jar and wlclient.jar are in the client classpath, there is no need to enable the default IIOP user. Go to Step 2.

    Notes:

    wlclient.jar is included in wljmxclient.jar's MANIFEST ClassPath entry, so wlclient.jar and wljmxclient.jar need to be in the same directory, or both jars need to be specified on the classpath.

    Ensure that weblogic.jar or wlfullclient.jar is not included in the classpath if wljmxclient.jar is included. Only the thin client wljmxclient.jar/wlclient.jar or the thick client wlfullclient.jar should be used, but not a combination of both.

  2. In your JMX client, construct a javax.management.JMXConnector object as follows:

    String hostname = "WLS-host" 
    int port = WLS-port 
    String protocol = "iiop";
    String jndiroot= new String("/jndi/iiop://" + hostname + ":" + 
           port + "/");
    String mserver = "MBean-server-JNDI-name";
    JMXServiceURL serviceURL = new JMXServiceURL(protocol, hostname, port,
          jndiroot + mserver);
    Hashtable h = new Hashtable();
    h.put(Context.SECURITY_PRINCIPAL, username);
    h.put(Context.SECURITY_CREDENTIALS, password);
    connector = JMXConnectorFactory.connect(serviceURL, h); 
    

    where WLS-host and WLS-port are the listen address and listen port of a WebLogic Server instance and MBean-server-JNDI-name is one of the values listed in Table 4-1.

Note that the hash table you create does not include the name of a protocol package. By leaving this value as null, the JMX client uses the protocol definitions from the com.sun.jmx.remote.protocol package, which is in the JDK.

Make Local Connections to the Runtime MBean Server

Local clients can access a WebLogic Server instance's Runtime MBean Server through the JNDI tree instead of constructing a JMXServiceURL object.

Note:

Local clients can also access a WebLogic Server's Domain Runtime MBean Server through the JNDI tree, as described in Make Local Connections to the Domain Runtime MBean Server.

When accessed from JNDI, the Runtime MBean Server returns its javax.management.MBeanServer interface. This interface contains all of the methods in the MBeanServerConnection interface plus additional methods such as registerMBean(), which a local process can use to register custom MBeans. (See MBeanServer in the Java SE 6.0 API Specification at https://download.oracle.com/javase/6/docs/api/javax/management/MBeanServer.html.)

If the classes for the JMX client are located in a Java EE module, such as an EJB or Web application, then the JNDI name for the Runtime MBeanServer is:

java:comp/env/jmx/runtime

For example:

InitialContext ctx = new InitialContext();
server = (MBeanServer)ctx.lookup("java:comp/env/jmx/runtime"); 

If the classes for the JMX client are not part of a Java EE module, then the JNDI name for the Runtime MBean Server is:

java:comp/jmx/runtime 

Make Local Connections to the Domain Runtime MBean Server

Local clients can also access a WebLogic Server instance's Domain Runtime MBean Server through the JNDI tree instead of constructing a JMXServiceURL object.

When accessed from JNDI, the Domain Runtime MBean Server returns its javax.management.MBeanServer interface. This interface contains all of the methods in the MBeanServerConnection interface plus additional methods such as registerMBean(), which a local process can use to register custom MBeans, and other methods such as getMBeanCount(), instatiate(), and getClassLoader(). (See MBeanServer in the Java SE 6.0 API Specification at https://download.oracle.com/javase/6/docs/api/javax/management/MBeanServer.html.)

Note:

As a best practice, Oracle recommends that you use the Domain Runtime MBean Server only for MBeans that perform domain-wide operations. You should ensure that any MBean processing and network activity do not slow down the Administration Server and prevent it from processing administration operations.

If the classes for the JMX client are located in a Java EE module, such as an EJB or Web application, then the JNDI name for the Domain Runtime MBeanServer is:

java:comp/env/jmx/domainRuntime

For example:

InitialContext ctx = new InitialContext();
server = (MBeanServer)ctx.lookup("java:comp/env/jmx/domainRuntime"); 

If the classes for the JMX client are not part of a Java EE module, then the JNDI name for the Domain Runtime MBean Server is:

java:comp/jmx/domainRuntime 

The Domain Runtime MBean Server is present only on the Administration Server. Because the ctx.lookup() call returns a reference to the local MBeanServer, the lookup method can only be called when running on the Administration Server. If called when running on a Managed Server, a NameNotFound exception is thrown.

Navigate MBean Hierarchies

WebLogic Server organizes its MBeans in a hierarchical data model. (See WebLogic Server MBean Data Model.) In this model, all parent MBeans include attributes that contain the object names of their children. You use the child's object name in standard JMX APIs to get or set values of the child MBean's attributes or invoke its methods.

To navigate the WebLogic Server MBean hierarchy:

  1. Initiate a connection to an MBean server.

    See the previous section, Make Remote Connections to an MBean Server.

    Initiating the connection returns an object of type

    javax.management.MBeanServerConnection
    
  2. Obtain the object name for an MBean at the root of an MBean hierarchy by invoking the MBeanServerConnection.getAttribute(ObjectName object-name, String attribute) method where:

    • object-name is the object name of the service MBean that is registered in the MBean server. (See Service MBeans.)

      Table 2-3 describes the type of service MBeans that are available in each type of MBean server.

    • attribute is the name of a service MBean attribute that contains the root MBean.

  3. Successively invoke code similar to the following:

    ObjectName on = 
    MBeanServerConnection.getAttribute(object-name, attribute) 
    

    where:

    • object-name is the object name of the current node (MBean) in the MBean hierarchy.

    • attribute is the name of an attribute in the current MBean that contains one or more instances of a child MBean. If the attribute contains multiple children, assign the output to an object name array, ObjectName[].

To determine an MBean's location in an MBean hierarchy, refer to the MBean's description in Oracle WebLogic Server MBean Reference. For each MBean, the WebLogic Server MBean Reference lists the parent MBean that contains the current MBean's factory methods. For an MBean whose factory methods are not public, the Oracle WebLogic Server MBean Reference lists other MBeans from which you can access the current MBean.

Example: Printing the Name and State of Servers

The code example in Example 4-2 connects to the Domain Runtime MBean Server and uses the DomainRuntimeServiceMBean to get the object name for each ServerRuntimeMBean in the domain. Then it retrieves and prints the value of each server's ServerRuntimeMBean Name and State attributes.

Note the following about the code in Example 4-2:

  • In addition to the connection and connector global variables, the class assigns the object name for the WebLogic Server service MBean to a global variable. Methods within the class will use this object name frequently, and once it is defined it does not need to change.

  • The printServerRuntimes() method gets the value of the DomainRuntimeServiceMBean ServerRuntimes attribute, which contains an array of all ServerRuntimeMBean instances in the domain. (See "DomainRuntimeServiceMBean" in Oracle WebLogic Server MBean Reference.)

Example 4-2 Example: Print the Name and State of Servers

import java.io.IOException;
import java.net.MalformedURLException;
import java.util.Hashtable;
import javax.management.MBeanServerConnection;
import javax.management.MalformedObjectNameException;
import javax.management.ObjectName;
import javax.management.remote.JMXConnector;
import javax.management.remote.JMXConnectorFactory;
import javax.management.remote.JMXServiceURL;
import javax.naming.Context;

public class PrintServerState {

   private static MBeanServerConnection connection;
   private static JMXConnector connector;
   private static final ObjectName service;

   // Initializing the object name for DomainRuntimeServiceMBean
   // so it can be used throughout the class.
   static {
      try {
         service = new ObjectName(
            "com.bea:Name=DomainRuntimeService,Type=weblogic.management.
             mbeanservers.domainruntime.DomainRuntimeServiceMBean");
      }catch (MalformedObjectNameException e) {
         throw new AssertionError(e.getMessage());
      }
   }

   /*
   * Initialize connection to the Domain Runtime MBean Server
   */
   public static void initConnection(String hostname, String portString, 
      String username, String password) throws IOException,
      MalformedURLException { 
      String protocol = "t3";
      Integer portInteger = Integer.valueOf(portString);
      int port = portInteger.intValue();
      String jndiroot = "/jndi/";
      String mserver = "weblogic.management.mbeanservers.domainruntime";
      JMXServiceURL serviceURL = new JMXServiceURL(protocol, hostname,
         port, jndiroot + mserver);
      Hashtable h = new Hashtable();
      h.put(Context.SECURITY_PRINCIPAL, username);
      h.put(Context.SECURITY_CREDENTIALS, password);
      h.put(JMXConnectorFactory.PROTOCOL_PROVIDER_PACKAGES,
         "weblogic.management.remote");
      connector = JMXConnectorFactory.connect(serviceURL, h);
      connection = connector.getMBeanServerConnection();
   }

   /* 
   * Print an array of ServerRuntimeMBeans.
   * This MBean is the root of the runtime MBean hierarchy, and
   * each server in the domain hosts its own instance.
   */
   public static ObjectName[] getServerRuntimes() throws Exception {
      return (ObjectName[]) connection.getAttribute(service,
         "ServerRuntimes");
   }

   /* 
   * Iterate through ServerRuntimeMBeans and get the name and state
   */
   public void printNameAndState() throws Exception {
      ObjectName[] serverRT = getServerRuntimes();
      System.out.println("got server runtimes");
      int length = (int) serverRT.length;
      for (int i = 0; i < length; i++) {
         String name = (String) connection.getAttribute(serverRT[i],
            "Name");
         String state = (String) connection.getAttribute(serverRT[i],
            "State");
         System.out.println("Server name: " + name + ".   Server state: "
            + state);
      }
   }

   public static void main(String[] args) throws Exception {
      String hostname = args[0];
      String portString = args[1];
      String username = args[2];
      String password = args[3];

      PrintServerState s = new PrintServerState();
      initConnection(hostname, portString, username, password);
      s.printNameAndState();
      connector.close();
   }
}

Example: Monitoring Servlets

Each servlet in a Web application provides instance of ServletRuntimeMBean which contains information about the servlet's run-time state. (See "ServletRuntimeMBean" in Oracle WebLogic Server MBean Reference.)

In the WebLogic Server data model, the path to a ServletRuntimeMBean is as follows:

  1. The Domain Runtime MBean Server (for all servlets on all servers in the domain), or the Runtime MBean Server on a specific server instance.

  2. DomainRuntimeServiceMBean or RuntimeServiceMBean, ServerRuntimes attribute.

  3. ServerRuntimeMBean, ApplicationRuntimes attribute.

  4. ApplicationRuntimeMBean, ComponentRuntimes attribute.

    The ComponentRuntimes attribute contains many types of component run-time MBeans, one of which is WebAppComponentRuntimeMBean. When you get the value of this attribute, you use the child MBean's Type attribute to get a specific type of component run-time MBean.

  5. WebAppComponentRuntimeMBean, ServletRuntimes attribute.

The code in Example 4-3 navigates the hierarchy described in the previous paragraphs and gets values of ServletRuntimeMBean attributes.

Example 4-3 Monitoring Servlets

import java.io.IOException;
import java.net.MalformedURLException;
import java.util.Hashtable;

import javax.management.MBeanServerConnection;
import javax.management.MalformedObjectNameException;
import javax.management.ObjectName;
import javax.management.remote.JMXConnector;
import javax.management.remote.JMXConnectorFactory;
import javax.management.remote.JMXServiceURL;
import javax.naming.Context;

public class MonitorServlets {
   private static MBeanServerConnection connection;
   private static JMXConnector connector;
   private static final ObjectName service;

   // Initializing the object name for DomainRuntimeServiceMBean
   // so it can be used throughout the class.
   static {
      try {
         service = new ObjectName(
          "com.bea:Name=DomainRuntimeService,Type=weblogic.management.mbeanser
           vers.domainruntime.DomainRuntimeServiceMBean");
      }catch (MalformedObjectNameException e) {
         throw new AssertionError(e.getMessage());
      }
   }

   /*
   * Initialize connection to the Domain Runtime MBean Server
   */
   public static void initConnection(String hostname, String portString, 
      String username, String password) throws IOException,
      MalformedURLException { 
      String protocol = "t3";
      Integer portInteger = Integer.valueOf(portString);
      int port = portInteger.intValue();
      String jndiroot = "/jndi/";
      String mserver = "weblogic.management.mbeanservers.domainruntime";

      JMXServiceURL serviceURL = new JMXServiceURL(protocol, hostname,
         port, jndiroot + mserver);
      Hashtable h = new Hashtable();
      h.put(Context.SECURITY_PRINCIPAL, username);
      h.put(Context.SECURITY_CREDENTIALS, password);
      h.put(JMXConnectorFactory.PROTOCOL_PROVIDER_PACKAGES,
         "weblogic.management.remote");
      connector = JMXConnectorFactory.connect(serviceURL, h);
      connection = connector.getMBeanServerConnection();
   }

   /*
   * Get an array of ServerRuntimeMBeans
   */
   public static ObjectName[] getServerRuntimes() throws Exception {
      return (ObjectName[]) connection.getAttribute(service,
         "ServerRuntimes");
   }

   /*
   * Get an array of WebAppComponentRuntimeMBeans
   */
   public void getServletData() throws Exception {
      ObjectName[] serverRT = getServerRuntimes();
      int length = (int) serverRT.length;
      for (int i = 0; i < length; i++) {
         ObjectName[] appRT = 
            (ObjectName[]) connection.getAttribute(serverRT[i],
            "ApplicationRuntimes");
         int appLength = (int) appRT.length;
         for (int x = 0; x < appLength; x++) {
            System.out.println("Application name: " +
              (String)connection.getAttribute(appRT[x], "Name"));
            ObjectName[] compRT = 
               (ObjectName[]) connection.getAttribute(appRT[x],
               "ComponentRuntimes");
            int compLength = (int) compRT.length;
            for (int y = 0; y < compLength; y++) {
               System.out.println("  Component name: " +
                 (String)connection.getAttribute(compRT[y], "Name"));
               String componentType = 
                  (String) connection.getAttribute(compRT[y], "Type");
               System.out.println(componentType.toString());
               if (componentType.toString().equals("WebAppComponentRuntime")){
                  ObjectName[] servletRTs = (ObjectName[])
                     connection.getAttribute(compRT[y], "Servlets");
                  int servletLength = (int) servletRTs.length;
                  for (int z = 0; z < servletLength; z++) {
                     System.out.println("    Servlet name: " +
                        (String)connection.getAttribute(servletRTs[z],
                         "Name"));
                     System.out.println("       Servlet context path: " +
                        (String)connection.getAttribute(servletRTs[z],
                         "ContextPath"));
                     System.out.println("       Invocation Total Count : " +
                        (Object)connection.getAttribute(servletRTs[z],
                         "InvocationTotalCount"));
                  }
               }
            }
         }
      }
   }

   public static void main(String[] args) throws Exception {
      String hostname = args[0];
      String portString = args[1];
      String username = args[2];
      String password = args[3];

      MonitorServlets s = new MonitorServlets();
      initConnection(hostname, portString, username, password);
      s.getServletData();
      connector.close();
   }
}