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.
Advertisement
Answer
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:Javajdk1.8.0_261binjava.exe -cp .;d:External_Libraryjmxremote_optional.jar jmx.learning.SystemConfigManagement Thread Count=10 Schema Name=default Thread Count=10 Schema Name=default
Client Output:
d:Javajdk1.8.0_261binjava.exe -cp .;d:External_Libraryjmxremote_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.