How to access MBeanServerConnection from remote JMX Client for JBoss EAP 7.x/8.x

Solution Verified - Updated

Environment

  • Red Hat JBoss Enterprise Application Platform (EAP)
    • 7.x
    • 8.x

Issue

  • How to access MBeanServerConnection from remote JMX Client for JBoss EAP 7.x/8.x
  • I tried running same JMX client application described in this EAP 6 article against EAP 7 but it does not work. Is anything changed between EAP 6 and EAP 7? How can we access the javax.management.MBeanServerConnection in order to query JBoss EAP 7?
  • Is there a way to obtain the Redelivery Delay and Max Delivery Attempts of JBOSS configuration in the application java code? If there is way, can you please provide us some examples?

Resolution

You need to use the remote+http protocol and management-http port (9990 by default) in EAP 7 instead of using the remoting-jmx protocol and management-native port (9999 by default) in EAP 6.

So, you need to specify service:jmx:remote+http://127.0.0.1:9990 instead of service:jmx:remoting-jmx://127.0.0.1:9999. For example:

  • When JBoss run locally, you can access it from a local machine without credential by default:
import java.util.Set;
import javax.management.ObjectName;
import javax.management.MBeanServerConnection;
import javax.management.remote.JMXConnector;
import javax.management.remote.JMXConnectorFactory;
import javax.management.remote.JMXServiceURL;
 
public class JmxClientEAP7 { 
    public static void main(String[] args) throws Exception {
        String host = "localhost";
        int port = 9990;  // management-http port
        String urlString = "service:jmx:remote+http://" + host + ":" + port;
        System.out.println("\n\n\t****  urlString: "+urlString);;
        JMXServiceURL serviceURL = new JMXServiceURL(urlString);
        JMXConnector jmxConnector = JMXConnectorFactory.connect(serviceURL, null);
        MBeanServerConnection connection = jmxConnector.getMBeanServerConnection();
 
        // Invoke on the JBoss AS MBean server
        int count = connection.getMBeanCount();
        System.out.println("MBean Count = " + count);

        /*
        // If you want to output all MBean names, you can obtain it from queryNames():
        Set<ObjectName> objectNames = connection.queryNames(null, null);
        objectNames.forEach(System.out::println);

        // If you want to output all MBean names with attributes and operations, you can obtain them from MBeanInfo.
        Iterator<ObjectName> iterator = objectNames.iterator();
        while (iterator.hasNext()) {
            ObjectName name = iterator.next();
            System.out.println("Object Name: " + name.toString());
            MBeanInfo info = connection.getMBeanInfo(name);
            MBeanAttributeInfo[] attrs = info.getAttributes();
            if (attrs.length > 0) {
                // Arrays.stream(attrs).forEach(System.out::println);
                for (MBeanAttributeInfo item : attrs) {
                    System.out.println("- Attribute Name = " + item.getName());
                    System.out.println("     Description = " + item.getDescription());
                    // System.out.println("     Descriptor  = " + item.getDescriptor());
                }   
            }
            MBeanOperationInfo[] ops = info.getOperations();
            if (ops.length > 0) {
                // Arrays.stream(ops).forEach(System.out::println);
                for (MBeanOperationInfo item : ops) {
                    System.out.println("-  Operation Name = " + item.getName());
                    System.out.println("      Description = " + item.getDescription());
                    // System.out.println("      Descriptor  = " + item.getDescriptor());
                }   
            }   
            System.out.println("****************************************");
        }
        */

        ObjectName objectName = ObjectName.getInstance("jboss.as:management-root=server");
        String attributeName = "serverState";
        Object result = connection.getAttribute(objectName, attributeName);
        System.out.println(result);

        jmxConnector.close();
    }
}
  • When JBoss run remotely, you need to add the authentication credentials to access it. Note that the user and password are created via add-user.sh with Management Realm in standalone mode and Application Realm in domain mode (In Windows, use add-user.bat instead):
import java.util.HashMap;
import java.util.Map;
import java.util.Set;
import javax.management.ObjectName;
import javax.management.MBeanServerConnection;
import javax.management.remote.JMXConnector;
import javax.management.remote.JMXConnectorFactory;
import javax.management.remote.JMXServiceURL;

public class JmxClientEAP7 { 
    public static void main(String[] args) throws Exception {
        String host = "remote-hostname";
        int port = 9990;  // management-http port
        String urlString = "service:jmx:remote+http://" + host + ":" + port;
        System.out.println("\n\n\t****  urlString: "+urlString);;
        JMXServiceURL serviceURL = new JMXServiceURL(urlString);

        Map<String, Object> map = new HashMap<>();
        String[] credentials = new String[] { "user", "password" };
        map.put("jmx.remote.credentials", credentials);
        JMXConnector jmxConnector = JMXConnectorFactory.connect(serviceURL, map);

        MBeanServerConnection connection = jmxConnector.getMBeanServerConnection();

        // Invoke on the JBoss AS MBean server
        int count = connection.getMBeanCount();
        System.out.println("MBean Count = " + count);

        /*
        // If you want to output all MBean names, you can obtain it from queryNames():
        Set<ObjectName> objectNames = connection.queryNames(null, null);
        objectNames.forEach(System.out::println);

        // If you want to output all MBean names with attributes and operations, you can obtain them from MBeanInfo.
        Iterator<ObjectName> iterator = objectNames.iterator();
        while (iterator.hasNext()) {
            ObjectName name = iterator.next();
            System.out.println("Object Name: " + name.toString());
            MBeanInfo info = connection.getMBeanInfo(name);
            MBeanAttributeInfo[] attrs = info.getAttributes();
            if (attrs.length > 0) {
                // Arrays.stream(attrs).forEach(System.out::println);
                for (MBeanAttributeInfo item : attrs) {
                    System.out.println("- Attribute Name = " + item.getName());
                    System.out.println("     Description = " + item.getDescription());
                    // System.out.println("     Descriptor  = " + item.getDescriptor());
                }   
            }
            MBeanOperationInfo[] ops = info.getOperations();
            if (ops.length > 0) {
                // Arrays.stream(ops).forEach(System.out::println);
                for (MBeanOperationInfo item : ops) {
                    System.out.println("-  Operation Name = " + item.getName());
                    System.out.println("      Description = " + item.getDescription());
                    // System.out.println("      Descriptor  = " + item.getDescriptor());
                }   
            }   
            System.out.println("****************************************");
        }
        */

        ObjectName objectName = ObjectName.getInstance("jboss.as:management-root=server");
        String attributeName = "serverState";
        Object result = connection.getAttribute(objectName, attributeName);
        System.out.println("serverState = " + result);

        jmxConnector.close();
    }   
}

Note: To run the above sample programs, make sure to add $JBOSS_HOME/bin/client/jboss-cli-client.jar on the JMX client's CLASSPATH because this requires the remoting+http protocol which is not available in standard java libraries:

javac JmxClientEAP7.java
java -cp .:$JBOSS_HOME/bin/client/jboss-cli-client.jar JmxClientEAP7

Note: If your Java program runs on Java 11+ with jboss-cli-client.jar from old versions, notice that you will see the following ERROR output from JBoss LogManager:

ERROR: The LogManager accessed before the "java.util.logging.manager" system property was set to "org.jboss.logmanager.LogManager". Results may be unexpected.

Please use $JBOSS_HOME/bin/client/jboss-cli-client.jar from the latest CP version of JBoss EAP 7.4. Because this has been fixed by This content is not included.MODULES-441 "Lazily initialize System.Logger's in the ModuleLoggerFinder" included in EAP 7.4.13+.


This knowledge article is for remote JMX Client. If you want to connect to the JBoss EAP instance itself from a deployed application on the JBoss EAP instance, you can simply obtain javax.management.MBeanServer from ManagementFactory.getPlatformMBeanServer() without using the above API. See also this knowledge article.

Components
Category

This solution is part of Red Hat’s fast-track publication program, providing a huge library of solutions that Red Hat engineers have created while supporting our customers. To give you the knowledge you need the instant it becomes available, these articles may be presented in a raw and unedited form.