0
votes

Need your help to understand why I am unable to connect from a client application to a server application using JMX. I have a Server application that is initiating a JMX Bean server and a client that is trying to connect to this Server using JMX. both app are ruining on local machine in windows. Jconsole is working just fine and I am able to connect with it to the Server. But when running the client it get "stuck" on line:

  JMXConnector jmxConnector = JMXConnectorFactory.connect(url, null);

Application side JMX Server init code:

    MyClass mc = new MyClass ();
    MBeanServer mbs = ManagementFactory.getPlatformMBeanServer();
    ObjectName obj = new ObjectName("JMX:name=MyClassJmx");
    mbs.registerMBean(mc, obj);

Application side JMX Server JVM params:

-Dcom.sun.management.jmxremote.port=10090
-Dcom.sun.management.jmxremote.authenticate=false
-Dcom.sun.management.jmxremote.ssl=false

My client connection to Application code :

  final JMXServiceURL url = new JMXServiceURL("service:jmx:jmxmp://127.0.0.1:10090");
  JMXConnector jmxConnector = JMXConnectorFactory.connect(url, null);
  jmxConnector.connect();

A note, using

service:jmx:rmi:///jndi/rmi://:10090/jmxrmi

is working.

1

1 Answers

0
votes

Java reference

The JMX Messaging Protocol (JMXMP) connector is a configuration of the generic connector where the transport protocol is based on TCP and the object wrapping is native Java serialization. Security is more advanced than for the RMI connector. Security is based on the Java Secure Socket Extension (JSSE), the Java Authentication and Authorization Service (JAAS), and the Simple Authentication and Security Layer (SASL).

The generic connector and its JMXMP configuration are optional, which means that they are not always included in an implementation of the JMX Remote API. The J2SE platform does not include the optional generic connector.

Note – If you want to use a JMXMP connector, download the JSR 160 Reference Implementation from http://java.sun.com/products/JavaManagement/download.html, and add the jmxremote_optional.jar file to your classpath.

Did you included jmxremote_optional.jar file in your server and client classpath?

I don't have prior experience with JMXMP Connector approach, I followed JMX documentation and tried to verify by writing the following example and it works.

JMX MBean interface

SystemConfigMBean.java

package jmx.learning;

public interface SystemConfigMBean {

    public void setThreadCount(int noOfThreads);
    public int getThreadCount();
    
    public void setSchemaName(String schemaName);
    public String getSchemaName();
    
    // any method starting with get and set are considered
    // as attributes getter and setter methods, so I am 
    // using do* for operation.
    public String doConfig();
}

A class to implement the JMX MBean interface

SystemConfig.java

package jmx.learning;

public class SystemConfig implements SystemConfigMBean {

    private int threadCount;
    private String schemaName;
    
    public SystemConfig(int numThreads, String schema){
        this.threadCount=numThreads;
        this.schemaName=schema;
    }
    
    @Override
    public void setThreadCount(int noOfThreads) {
        this.threadCount=noOfThreads;
    }


    @Override
    public int getThreadCount() {
        return this.threadCount;
    }


    @Override
    public void setSchemaName(String schemaName) {
        this.schemaName=schemaName;
    }


    @Override
    public String getSchemaName() {
        return this.schemaName;
    }
    
    @Override
    public String doConfig(){
        return "No of Threads="+this.threadCount+" and DB Schema Name="+this.schemaName;
    }

}

Creating and Registering the MBean in the MBean Server using JMXMP connector

SystemConfigManagement.java

package jmx.learning;

import java.io.IOException;

import javax.management.InstanceAlreadyExistsException;
import javax.management.MBeanRegistrationException;
import javax.management.MBeanServer;
import javax.management.MBeanServerFactory;
import javax.management.MalformedObjectNameException;
import javax.management.NotCompliantMBeanException;
import javax.management.ObjectName;
import javax.management.remote.JMXConnectorServer;
import javax.management.remote.JMXConnectorServerFactory;
import javax.management.remote.JMXServiceURL;

public class SystemConfigManagement {
    private static final int DEFAULT_NO_THREADS = 10;
    private static final String DEFAULT_SCHEMA = "default";

    public static void main(String[] args) throws MalformedObjectNameException,
            InterruptedException, InstanceAlreadyExistsException,
            MBeanRegistrationException, NotCompliantMBeanException, IOException {
        // Instantiate the MBean server
        MBeanServer mbs = MBeanServerFactory.createMBeanServer();

        // Create a JMXMP connector server
        JMXServiceURL url = new JMXServiceURL("jmxmp", null, 5555);
        JMXConnectorServer cs = JMXConnectorServerFactory
                .newJMXConnectorServer(url, null, mbs);
        cs.start();

        // register the MBean
        SystemConfig mBean = new SystemConfig(DEFAULT_NO_THREADS,
                DEFAULT_SCHEMA);
        ObjectName name = new ObjectName("jmx.learning:type=SystemConfig");
        mbs.registerMBean(mBean, name);
        do {
            Thread.sleep(3000);
            System.out.println("Thread Count=" + mBean.getThreadCount()
                    + " Schema Name=" + mBean.getSchemaName());
        } while (mBean.getThreadCount() != 0);

    }
}

JMXMP Connector Client

SystemConfigManagementClient.java

package jmx.learning;

import java.io.IOException;

import javax.management.MBeanServerConnection;
import javax.management.ObjectName;
import javax.management.remote.JMXConnector;
import javax.management.remote.JMXConnectorFactory;
import javax.management.remote.JMXServiceURL;

public class SystemConfigManagementClient {
    public static void main(String[] args) {
        JMXConnector jmxc = null;
        try {
            // Create a JMXMP connector client
            System.out.println("\nCreate a JMXMP connector client");
            JMXServiceURL url = new JMXServiceURL(
                    "service:jmx:jmxmp://localhost:5555");
            jmxc = JMXConnectorFactory.connect(url, null);
            // get MBeanServerConnection
            MBeanServerConnection serverConn = jmxc.getMBeanServerConnection();

            ObjectName objectName = new ObjectName(
                    "jmx.learning:type=SystemConfig");

            // Executing doConfig() method
            String value = (String) serverConn.invoke(objectName, "doConfig",
                    new Object[] {}, new String[] {});
            System.out.println(value);
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            if (jmxc != null) {
                try {
                    jmxc.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
    }
}

NOTE: I have downloaded jmxremote_optional.jar file and kept in project classpath.

Execution:

Server Output:

d:\Java\jdk1.8.0_261\bin\java.exe -cp .;d:\External_Library\jmxremote_optional.jar jmx.learning.SystemConfigManagement
Thread Count=10 Schema Name=default
Thread Count=10 Schema Name=default

Client Output:

d:\Java\jdk1.8.0_261\bin\java.exe -cp .;d:\External_Library\jmxremote_optional.jar jmx.learning.SystemConfigManagementClient

Create a JMXMP connector client
No of Threads=10 and DB Schema Name=default

I am not sure about the Server code you have written, looks like that code is expecting RMIConnector. Thus from Client the Connection attempt using RMI connector Java Remote Method Protocol (JRMP) is working.

Even you have passed property -Dcom.sun.management.jmxremote.port=portNum This property indicate, portNum is the port number through which you want to enable JMX RMI connections.

NOTE: For demo purpose I didn't show the secure handling stuff, in real code those need to be in place.