How to get a list of clients connected to the Gemfire Cluster via code
search cancel

How to get a list of clients connected to the Gemfire Cluster via code

book

Article ID: 294415

calendar_today

Updated On:

Products

VMware Tanzu Gemfire

Issue/Introduction

When implementing some code via managementService or commandService.processCommand (“list clients”) etc., the Gemfire API getting the list of clients which are connected to cache in cacheserver project (using Spring boot annotation @CacheServerApplication) failed with null object. While running the gfsh command, “list clients” via gfsh console, it will return the correct client list output:
GemFireCache gemFireCache;
ManagementService managementService = ManagementService.getManagementService((Cache) gemFireCache);
log.info("getDistributedSystemMXBean:: {}",managementService.getDistributedSystemMXBean());
// Returning null
CommandService commandService = CommandService.createLocalCommandService((Cache) gemFireCache);
Result regionListResult = commandService.processCommand("list clients");
System.out.println("---------Print csresult start----------");
System.out.println(csresult.toString());
//Error while processing command <list clients> Reason : null

Some sample logs / stack trace when returning null object:
2021-05-25 12:18:11.515  INFO 1880 --- [           main] o.s.data.gemfire.CacheFactoryBean        : Created new VMware Tanzu GemFire version [9.10.6] Cache [SpringBasedCacheServerApplication]
2021-05-25 12:18:12.127  INFO 1880 --- [           main] o.a.g.m.i.cli.remote.CommandExecutor     : Executing command: list clients
2021-05-25 12:18:12.140 ERROR 1880 --- [           main] o.a.g.m.i.cli.remote.CommandExecutor     : Could not execute "list clients".
java.lang.NullPointerException: null
        at org.apache.geode.management.internal.cli.commands.ListClientCommand.listClient(ListClientCommand.java:51) ~[geode-gfsh-9.10.6.jar:na]
        at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) ~[na:1.8.0_211]
        at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62) ~[na:1.8.0_211]
        at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) ~[na:1.8.0_211]
        at java.lang.reflect.Method.invoke(Method.java:498) ~[na:1.8.0_211]
        at org.springframework.util.ReflectionUtils.invokeMethod(ReflectionUtils.java:282) ~[spring-core-5.2.15.RELEASE.jar:5.2.15.RELEASE]
        at org.apache.geode.management.internal.cli.remote.CommandExecutor.callInvokeMethod(CommandExecutor.java:138) [geode-gfsh-9.10.6.jar:na]
        at org.apache.geode.management.internal.cli.remote.CommandExecutor.invokeCommand(CommandExecutor.java:148) [geode-gfsh-9.10.6.jar:na]
        at org.apache.geode.management.internal.cli.remote.CommandExecutor.execute(CommandExecutor.java:76) [geode-gfsh-9.10.6.jar:na]
        at org.apache.geode.management.internal.cli.remote.CommandExecutor.execute(CommandExecutor.java:61) [geode-gfsh-9.10.6.jar:na]
        at org.apache.geode.management.internal.cli.remote.OnlineCommandProcessor.executeCommand(OnlineCommandProcessor.java:132) [geode-gfsh-9.10.6.jar:na]
        at org.apache.geode.management.internal.cli.remote.OnlineCommandProcessor.executeCommandReturningJson(OnlineCommandProcessor.java:138) [geode-gfsh-9.10.6.jar:na]
        at org.apache.geode.management.internal.cli.remote.MemberCommandService.processCommand(MemberCommandService.java:56) [geode-gfsh-9.10.6.jar:na]
        at org.apache.geode.management.internal.cli.remote.MemberCommandService.processCommand(MemberCommandService.java:50) [geode-gfsh-9.10.6.jar:na]
        at org.apache.geode.examples.MBeanRetrieve.MBeanRetrieveApplication.getMetrics(MBeanRetrieveApplication.java:44) [classes/:na]
        at org.apache.geode.examples.MBeanRetrieve.MBeanRetrieveApplication$$EnhancerBySpringCGLIB$$f65714c1.CGLIB$getMetrics$0(<generated>) [classes/:na]
        at org.apache.geode.examples.MBeanRetrieve.MBeanRetrieveApplication$$EnhancerBySpringCGLIB$$f65714c1$$FastClassBySpringCGLIB$$b8ebb8dd.invoke(<generated>) [classes/:na]
        at org.springframework.cglib.proxy.MethodProxy.invokeSuper(MethodProxy.java:244) [spring-core-5.2.15.RELEASE.jar:5.2.15.RELEASE]
        at org.springframework.context.annotation.ConfigurationClassEnhancer$BeanMethodInterceptor.intercept(ConfigurationClassEnhancer.java:331) [spring-context-5.2.15.RELEASE.jar:5.2.15.RELEASE]
        at org.apache.geode.examples.MBeanRetrieve.MBeanRetrieveApplication$$EnhancerBySpringCGLIB$$f65714c1.getMetrics(<generated>) [classes/:na]
        at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) ~[na:1.8.0_211]
        at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62) ~[na:1.8.0_211]
        at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) ~[na:1.8.0_211]
        at java.lang.reflect.Method.invoke(Method.java:498) ~[na:1.8.0_211]
        at org.springframework.beans.factory.support.SimpleInstantiationStrategy.instantiate(SimpleInstantiationStrategy.java:154) [spring-beans-5.2.15.RELEASE.jar:5.2.15.RELEASE]
        at org.springframework.beans.factory.support.ConstructorResolver.instantiate(ConstructorResolver.java:652) [spring-beans-5.2.15.RELEASE.jar:5.2.15.RELEASE]
        at org.springframework.beans.factory.support.ConstructorResolver.instantiateUsingFactoryMethod(ConstructorResolver.java:637) [spring-beans-5.2.15.RELEASE.jar:5.2.15.RELEASE]
        at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.instantiateUsingFactoryMethod(AbstractAutowireCapableBeanFactory.java:1341) [spring-beans-5.2.15.RELEASE.jar:5.2.15.RELEASE]
        at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBeanInstance(AbstractAutowireCapableBeanFactory.java:1181) [spring-beans-5.2.15.RELEASE.jar:5.2.15.RELEASE]
        at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:556) [spring-beans-5.2.15.RELEASE.jar:5.2.15.RELEASE]
        at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:516) [spring-beans-5.2.15.RELEASE.jar:5.2.15.RELEASE]
        at org.springframework.beans.factory.support.AbstractBeanFactory.lambda$doGetBean$0(AbstractBeanFactory.java:324) [spring-beans-5.2.15.RELEASE.jar:5.2.15.RELEASE]
        at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:234) ~[spring-beans-5.2.15.RELEASE.jar:5.2.15.RELEASE]
        at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:322) [spring-beans-5.2.15.RELEASE.jar:5.2.15.RELEASE]
        at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:202) [spring-beans-5.2.15.RELEASE.jar:5.2.15.RELEASE]
        at org.springframework.beans.factory.support.DefaultListableBeanFactory.preInstantiateSingletons(DefaultListableBeanFactory.java:897) ~[spring-beans-5.2.15.RELEASE.jar:5.2.15.RELEASE]
        at org.springframework.context.support.AbstractApplicationContext.finishBeanFactoryInitialization(AbstractApplicationContext.java:879) ~[spring-context-5.2.15.RELEASE.jar:5.2.15.RELEASE]
        at org.springframework.context.support.AbstractApplicationContext.refresh(AbstractApplicationContext.java:551) ~[spring-context-5.2.15.RELEASE.jar:5.2.15.RELEASE]
        at org.springframework.boot.SpringApplication.refresh(SpringApplication.java:755) ~[spring-boot-2.3.11.RELEASE.jar:2.3.11.RELEASE]
        at org.springframework.boot.SpringApplication.refresh(SpringApplication.java:747) ~[spring-boot-2.3.11.RELEASE.jar:2.3.11.RELEASE]
        at org.springframework.boot.SpringApplication.refreshContext(SpringApplication.java:402) ~[spring-boot-2.3.11.RELEASE.jar:2.3.11.RELEASE]
        at org.springframework.boot.SpringApplication.run(SpringApplication.java:312) ~[spring-boot-2.3.11.RELEASE.jar:2.3.11.RELEASE]
        at org.springframework.boot.SpringApplication.run(SpringApplication.java:1247) ~[spring-boot-2.3.11.RELEASE.jar:2.3.11.RELEASE]
        at org.springframework.boot.SpringApplication.run(SpringApplication.java:1236) ~[spring-boot-2.3.11.RELEASE.jar:2.3.11.RELEASE]
        at org.apache.geode.examples.MBeanRetrieve.MBeanRetrieveApplication.main(MBeanRetrieveApplication.java:35) [classes/:na]

---------Print csresult start----------
org.apache.geode.management.internal.cli.result.CommandResult@33bb3f86
Error while processing command <list clients> Reason : null


Environment

Product Version: 9.10

Resolution

This is a known issue (GEM-3298) which may be fixed in the future versions. Currently, we can use the below two methods to workaround this issue:
 
  • Use JMXConnector to connect with JMXManager and call the JMX Mbean action: "showAllClientStats" (#1* implementation example: DumpCacheClients.java).
  • Run the gfsh command "list clients" via java code such as Runtime.getRuntime().exec(gfsh commands) then parse the results from the command output. (#2* implementation sample code slice).

#1*:
DumpCacheClients.java
import java.io.IOException;
import java.util.Set;
import javax.management.MBeanServerConnection;
import javax.management.ObjectName;
import javax.management.openmbean.CompositeData;
import javax.management.remote.JMXConnector;
import javax.management.remote.JMXConnectorFactory;
import javax.management.remote.JMXServiceURL;

public class DumpCacheClients {

  private String jmxManagerHost;  
  private int jmxManagerPort;
  private JMXConnector jmxConnector;
  private MBeanServerConnection mbs;
  private ObjectName distributedSystem;
  
  private static final String CACHE_SERVER_MBEAN_NAME_PATTERN = "GemFire:service=CacheServer,*";
  
  private static final String DISTRIBUTED_SYSTEM_MBEAN_NAME = "GemFire:service=System,type=Distributed";

  public static void main(String[] args) throws Exception {
	String jmxManagerHost = "localhost";
	int jmxManagerPort = 1099;
			
	DumpCacheClients dumper = new DumpCacheClients(jmxManagerHost, jmxManagerPort);
		  
	// Connect to JMX manager
	dumper.connectToManager();
		
	// Dump the cache client statistics
	dumper.dumpCacheClientStatistics();
		
	// Disconnect from JMX manager
	dumper.disconnectFromManager();
		
  }
  
  private DumpCacheClients(String jmxManagerHost, int jmxManagerPort) {
	this.jmxManagerHost = jmxManagerHost;
	this.jmxManagerPort = jmxManagerPort;
  }
  
  private void connectToManager() throws Exception {
	// Create the JMXServiceURL
	StringBuilder builder = new StringBuilder();
	builder
	      .append("service:jmx:rmi://")
	      .append(this.jmxManagerHost)
	      .append("/jndi/rmi://")
	      .append(this.jmxManagerHost)
	      .append(":")
	      .append(this.jmxManagerPort)
	      .append("/jmxrmi");
    String urlString = builder.toString();
    JMXServiceURL url = new JMXServiceURL(urlString);
    System.out.println("Connecting to " + urlString);

    // Create the JMXConnector
    this.jmxConnector = JMXConnectorFactory.connect(url);
    System.out.println("Connected to " + this.jmxConnector);

    // Get the MBeanServerConnection
    this.mbs = this.jmxConnector.getMBeanServerConnection();
    
    // Get the DistributedSystem
    this.distributedSystem = new ObjectName(DISTRIBUTED_SYSTEM_MBEAN_NAME);
  }

  private void dumpCacheClientStatistics() throws Exception {
    ObjectName patternName = ObjectName.getInstance(CACHE_SERVER_MBEAN_NAME_PATTERN);
    Set<ObjectName> objectNames = this.mbs.queryNames(patternName, null);
	StringBuilder builder = new StringBuilder();
    builder.append("Dumping client statistics for ").append(objectNames.size()).append(" servers:\n");
    for (ObjectName objectName : objectNames) {
            builder.append("=======================================================\n");
            builder.append(objectName).append("\n");
            builder.append("=======================================================\n");
            CompositeData[] allClientStats = (CompositeData[]) invokeAction(objectName, "showAllClientStats");
            for (CompositeData clientStats : allClientStats) {
            builder.append("\nClient ").append(clientStats.get("clientId")).append("\n");
            }
    }
	System.out.println(builder.toString());
  }
  
  private void disconnectFromManager() throws IOException {
    if(this.jmxConnector != null) {
      this.jmxConnector.close();
    }
  }
  private Object invokeAction(ObjectName objectName, String operationName) throws Exception {
    return invokeAction(objectName, operationName, new Object[0], new String[0]);
  }

  private Object invokeAction(ObjectName objectName, String operationName, Object[] params, String[] signature) throws Exception {
    return this.mbs.invoke(objectName, operationName, params, signature);
  }
}


#2*:
Run gfsh list clients command via code:
       String lineStr;
        try {
            Process procVar = Runtime.getRuntime().exec("/Users/user1/Downloads/vsc_work/ListClients_Script.sh");
            BufferedReader brStr = new BufferedReader(new InputStreamReader(procVar.getInputStream()));
            while ((lineStr = brStr.readLine()) != null)
                System.out.println(lineStr);
            procVar.waitFor();
            procVar.destroy();
        } catch (Exception e) {}
 

ps:
ListClients_Script.sh
#!/bin/sh

export GEMFIRE=/Users/user1/Downloads/products/pivotal-gemfire-9.10.6
export JAVA_HOME=/Library/Java/JavaVirtualMachines/jdk1.8.0_281.jdk/Contents/Home
export PATH=$JAVA_HOME/bin:$GEMFIRE/bin:$PATH
export CLASSPATH=$GEMFIRE/lib/geode-dependencies.jar:$GEMFIRE/lib/gfsh-dependencies.jar

gfsh -e "connect --locator=localhost[10334]" -e "list clients"