Thursday, 26 July 2018

JMX: Creating custom client

In my previous posts, I explained how to connect to JMX application using jconsole. In this post, I am going to build a JMX client programatically.

Below step-by-step procedure explains how to create custom JMX client.

Step 1: Create an RMI Connector client and connect it to the RMI connector server.
JMXServiceURL url = new JMXServiceURL("service:jmx:rmi:///jndi/rmi://:9999/jmxrmi");
JMXConnector jmxc = JMXConnectorFactory.connect(url, null);

9999 is port number, where RMI connector server is listening to.

Step 2: Get an instance of MBeanServerConnection from JMXConnector
MBeanServerConnection mbsc = jmxc.getMBeanServerConnection();

Step 3: Get the MBean instance using the object name.
ObjectName mbeanName = new ObjectName("com.sample.mbeans:type=SystemStatisticsMBean");
SystemStatisticsMBean mbeanProxy = JMX.newMBeanProxy(mbsc, mbeanName, SystemStatisticsMBean.class, true);

That’s it, now you can perform operations on SystemStatisticsMBean object.

Find the below working application.

CRUDStatistics.java
package com.sample.model;

import java.io.Serializable;

/**
 * Since it is consumed by JMX client, we need to serialize it.
 * 
 * @author Krishna
 *
 */
public class CRUDStatistics implements Serializable {

 private static final long serialVersionUID = 1L;
 private int readCount = 0;
 private int writeCount = 0;

 public int getReadCount() {
  return readCount;
 }

 public void setReadCount(int readCount) {
  this.readCount = readCount;
 }

 public int getWriteCount() {
  return writeCount;
 }

 public void setWriteCount(int writeCount) {
  this.writeCount = writeCount;
 }

}

SystemStatisticsMBean.java
package com.sample.mbeans;

import com.sample.model.CRUDStatistics;

public interface SystemStatisticsMBean {

 public void setReadCount(int readCount);
 
 public void setWriteCount(int writeCount);
 
 public CRUDStatistics getAppStats();

}

SystemStatistics.java

package com.sample.mbeans;

import javax.management.Notification;
import javax.management.NotificationBroadcasterSupport;

import com.sample.model.CRUDStatistics;

public class SystemStatistics extends NotificationBroadcasterSupport implements SystemStatisticsMBean {
 private CRUDStatistics appStats = new CRUDStatistics();
 private static int sequenceNumber = 0;

 @Override
 public void setReadCount(int readCount) {
  Notification notification = new Notification("com.sample.mbeans.SystemStatistics", this, ++sequenceNumber,
    System.currentTimeMillis(), "Read Count is set to " + readCount);
  sendNotification(notification);

  appStats.setReadCount(readCount);
 }

 @Override
 public void setWriteCount(int writeCount) {
  Notification notification = new Notification("com.sample.mbeans.SystemStatistics", this, ++sequenceNumber,
    System.currentTimeMillis(), "Write Count is set to " + writeCount);
  sendNotification(notification);

  appStats.setWriteCount(writeCount);
 }

 @Override
 public CRUDStatistics getAppStats() {
  return appStats;
 }

}


StatsAgent.java
package com.sample.agents;

import java.io.IOException;
import java.lang.management.ManagementFactory;

import javax.management.InstanceAlreadyExistsException;
import javax.management.MBeanRegistrationException;
import javax.management.MBeanServer;
import javax.management.MalformedObjectNameException;
import javax.management.NotCompliantMBeanException;
import javax.management.ObjectName;

import com.sample.mbeans.SystemStatistics;

public class StatsAgent {
 private MBeanServer mbs;
 private SystemStatistics mbean;

 public StatsAgent() throws MalformedObjectNameException, InstanceAlreadyExistsException, MBeanRegistrationException,
   NotCompliantMBeanException, IOException {
  ObjectName name = new ObjectName("com.sample.mbeans:type=SystemStatisticsMBean");
  mbean = new SystemStatistics();

  mbs = ManagementFactory.getPlatformMBeanServer();
  mbs.registerMBean(mbean, name);
 }

}

Application.java

package com.sample.app;

import com.sample.agents.StatsAgent;

public class Application {

 public static void main(String[] args) throws Exception {
  new StatsAgent();

  System.out.println("Waiting forever...");
  Thread.sleep(Long.MAX_VALUE);

 }

}

JMXClient.java

package com.sample.clients;

import java.io.IOException;
import java.util.Arrays;
import java.util.Set;
import java.util.TreeSet;

import javax.management.JMX;
import javax.management.MBeanServerConnection;
import javax.management.Notification;
import javax.management.NotificationListener;
import javax.management.ObjectName;
import javax.management.remote.JMXConnector;
import javax.management.remote.JMXConnectorFactory;
import javax.management.remote.JMXServiceURL;

import com.sample.mbeans.SystemStatisticsMBean;

public class JMXClient {

 public static class ClientListener implements NotificationListener {
  public void handleNotification(Notification notification, Object handback) {
   System.out.println("***********************************");
   System.out.println(notification.getMessage());
   System.out.println("***********************************");
  }
 }

 private static void printAvailableDomains(MBeanServerConnection mbsc) throws IOException {
  System.out.println("\nDomains:");
  String domains[] = mbsc.getDomains();
  Arrays.sort(domains);
  for (String domain : domains) {
   System.out.println("\tDomain = " + domain);
  }

  System.out.println("\nMBeanServer default domain = " + mbsc.getDefaultDomain());
 }

 private static void printAllMBeans(MBeanServerConnection mbsc) throws IOException {

  int totalMBeans = mbsc.getMBeanCount();

  System.out.println("Total MBeans : " + totalMBeans);

  System.out.println("\nQuering MBeanServer MBeans:");
  Set<ObjectName> names = new TreeSet<ObjectName>(mbsc.queryNames(null, null));
  for (ObjectName name : names) {
   System.out.println("\tObjectName = " + name);
  }

 }

 public static void main(String[] args) throws Exception {

  /* Create an RMI Connector client and connect it to the RMI connector server */
  JMXServiceURL url = new JMXServiceURL("service:jmx:rmi:///jndi/rmi://:9999/jmxrmi");
  JMXConnector jmxc = JMXConnectorFactory.connect(url, null);

  System.out.println("\nGetting an MBeanServerConnection");
  MBeanServerConnection mbsc = jmxc.getMBeanServerConnection();

  printAvailableDomains(mbsc);
  printAllMBeans(mbsc);

  /* Get SystemStatisticsMBean */
  ObjectName mbeanName = new ObjectName("com.sample.mbeans:type=SystemStatisticsMBean");
  SystemStatisticsMBean mbeanProxy = JMX.newMBeanProxy(mbsc, mbeanName, SystemStatisticsMBean.class, true);

  /* Add notification listener */
  ClientListener listener = new ClientListener();
  mbsc.addNotificationListener(mbeanName, listener, null, null);

  System.out.println("\nRead Count = " + mbeanProxy.getAppStats().getReadCount());
  System.out.println("\nWrite Count = " + mbeanProxy.getAppStats().getWriteCount());

  System.out.println("Setting readCount to 50 and writeCount to 100");
  mbeanProxy.setReadCount(50);
  mbeanProxy.setWriteCount(100);

  /* Wait for 2 seconds to receive notification */
  Thread.sleep(2000);

  System.out.println("\nRead Count = " + mbeanProxy.getAppStats().getReadCount());
  System.out.println("\nWrite Count = " + mbeanProxy.getAppStats().getWriteCount());

  jmxc.close();
  System.out.println("\nBye! Bye!");
 }

}


Run Application.java, using below VM arguments.

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

If you are running in Eclipse, follow below steps to pass above arguments.
Right click on Application.java.


Run As -> Run Configurations…

In VM arguments: filed, add below arguments.
-Dcom.sun.management.jmxremote.port=9999 -Dcom.sun.management.jmxremote.authenticate=false -Dcom.sun.management.jmxremote.ssl=false

Click on Run button.

Run JMXClient.java, you can able to see below messages in console.

Getting an MBeanServerConnection

Domains:
 Domain = JMImplementation
 Domain = com.sample.mbeans
 Domain = com.sun.management
 Domain = java.lang
 Domain = java.nio
 Domain = java.util.logging

MBeanServer default domain = DefaultDomain
Total MBeans : 23

Quering MBeanServer MBeans:
 ObjectName = JMImplementation:type=MBeanServerDelegate
 ObjectName = com.sample.mbeans:type=SystemStatisticsMBean
 ObjectName = com.sun.management:type=DiagnosticCommand
 ObjectName = com.sun.management:type=HotSpotDiagnostic
 ObjectName = java.lang:type=ClassLoading
 ObjectName = java.lang:type=Compilation
 ObjectName = java.lang:type=GarbageCollector,name=PS MarkSweep
 ObjectName = java.lang:type=GarbageCollector,name=PS Scavenge
 ObjectName = java.lang:type=Memory
 ObjectName = java.lang:type=MemoryManager,name=CodeCacheManager
 ObjectName = java.lang:type=MemoryManager,name=Metaspace Manager
 ObjectName = java.lang:type=MemoryPool,name=Code Cache
 ObjectName = java.lang:type=MemoryPool,name=Compressed Class Space
 ObjectName = java.lang:type=MemoryPool,name=Metaspace
 ObjectName = java.lang:type=MemoryPool,name=PS Eden Space
 ObjectName = java.lang:type=MemoryPool,name=PS Old Gen
 ObjectName = java.lang:type=MemoryPool,name=PS Survivor Space
 ObjectName = java.lang:type=OperatingSystem
 ObjectName = java.lang:type=Runtime
 ObjectName = java.lang:type=Threading
 ObjectName = java.nio:type=BufferPool,name=direct
 ObjectName = java.nio:type=BufferPool,name=mapped
 ObjectName = java.util.logging:type=Logging

Read Count = 0

Write Count = 0
Setting readCount to 50 and writeCount to 100
***********************************
Read Count is set to 50
***********************************
***********************************
Write Count is set to 100
***********************************

Read Count = 50

Write Count = 100

Bye! Bye!


Previous                                                 Next                                                 Home

No comments:

Post a Comment