You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@geode.apache.org by kl...@apache.org on 2017/08/01 21:03:11 UTC

[17/50] [abbrv] geode git commit: GEODE-3253: Refactoring ClientCommands and related tests

GEODE-3253: Refactoring ClientCommands and related tests

This closes #650


Project: http://git-wip-us.apache.org/repos/asf/geode/repo
Commit: http://git-wip-us.apache.org/repos/asf/geode/commit/7ae99960
Tree: http://git-wip-us.apache.org/repos/asf/geode/tree/7ae99960
Diff: http://git-wip-us.apache.org/repos/asf/geode/diff/7ae99960

Branch: refs/heads/feature/GEODE-3299
Commit: 7ae99960fd7b8ea4848d1bc381cc0b8ac4b8c964
Parents: e0aa1b0
Author: YehEmily <em...@gmail.com>
Authored: Thu Jul 20 16:54:22 2017 -0700
Committer: Kirk Lund <kl...@apache.org>
Committed: Wed Jul 26 15:14:31 2017 -0700

----------------------------------------------------------------------
 .../internal/cli/commands/ClientCommands.java   |  336 -----
 .../cli/commands/DescribeClientCommand.java     |  245 ++++
 .../cli/commands/ListClientCommand.java         |  128 ++
 .../controllers/ClientCommandsController.java   |    9 +-
 .../internal/security/TestCommand.java          |    2 +-
 .../internal/JUnit4DistributedTestCase.java     |   31 +-
 .../cli/commands/ClientCommandsDUnitTest.java   | 1178 ------------------
 .../cli/commands/ClientCommandsTestUtils.java   |  140 +++
 .../DescribeClientCommandDUnitTest.java         |  783 ++++++++++++
 .../commands/ListClientCommandDUnitTest.java    |  402 ++++++
 10 files changed, 1720 insertions(+), 1534 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/geode/blob/7ae99960/geode-core/src/main/java/org/apache/geode/management/internal/cli/commands/ClientCommands.java
----------------------------------------------------------------------
diff --git a/geode-core/src/main/java/org/apache/geode/management/internal/cli/commands/ClientCommands.java b/geode-core/src/main/java/org/apache/geode/management/internal/cli/commands/ClientCommands.java
deleted file mode 100644
index 83d1728..0000000
--- a/geode-core/src/main/java/org/apache/geode/management/internal/cli/commands/ClientCommands.java
+++ /dev/null
@@ -1,336 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one or more contributor license
- * agreements. See the NOTICE file distributed with this work for additional information regarding
- * copyright ownership. The ASF licenses this file to You under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance with the License. You may obtain a
- * copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software distributed under the License
- * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
- * or implied. See the License for the specific language governing permissions and limitations under
- * the License.
- */
-package org.apache.geode.management.internal.cli.commands;
-
-import java.util.ArrayList;
-import java.util.Arrays;
-import java.util.HashMap;
-import java.util.List;
-import java.util.Map;
-import java.util.Map.Entry;
-import java.util.Set;
-
-import javax.management.ObjectName;
-
-import org.springframework.shell.core.annotation.CliCommand;
-import org.springframework.shell.core.annotation.CliOption;
-
-import org.apache.geode.cache.execute.FunctionService;
-import org.apache.geode.distributed.DistributedMember;
-import org.apache.geode.internal.cache.InternalCache;
-import org.apache.geode.management.CacheServerMXBean;
-import org.apache.geode.management.ClientHealthStatus;
-import org.apache.geode.management.ManagementService;
-import org.apache.geode.management.cli.CliMetaData;
-import org.apache.geode.management.cli.Result;
-import org.apache.geode.management.internal.cli.CliUtil;
-import org.apache.geode.management.internal.cli.LogWrapper;
-import org.apache.geode.management.internal.cli.functions.ContinuousQueryFunction;
-import org.apache.geode.management.internal.cli.functions.ContinuousQueryFunction.ClientInfo;
-import org.apache.geode.management.internal.cli.i18n.CliStrings;
-import org.apache.geode.management.internal.cli.result.CompositeResultData;
-import org.apache.geode.management.internal.cli.result.CompositeResultData.SectionResultData;
-import org.apache.geode.management.internal.cli.result.ResultBuilder;
-import org.apache.geode.management.internal.cli.result.TabularResultData;
-import org.apache.geode.management.internal.security.ResourceOperation;
-import org.apache.geode.security.ResourcePermission.Operation;
-import org.apache.geode.security.ResourcePermission.Resource;
-
-/**
- * @since GemFire 8.0
- */
-public class ClientCommands implements GfshCommand {
-
-  @CliCommand(value = CliStrings.LIST_CLIENTS, help = CliStrings.LIST_CLIENT__HELP)
-  @CliMetaData(relatedTopic = {CliStrings.TOPIC_CLIENT})
-  @ResourceOperation(resource = Resource.CLUSTER, operation = Operation.READ)
-  public Result listClient() {
-    Result result;
-
-    try {
-      CompositeResultData compositeResultData = ResultBuilder.createCompositeResultData();
-      SectionResultData section = compositeResultData.addSection("section1");
-
-      TabularResultData resultTable = section.addTable("TableForClientList");
-      String headerText = "ClientList";
-      resultTable = resultTable.setHeader(headerText);
-
-      InternalCache cache = getCache();
-      ManagementService service = ManagementService.getExistingManagementService(cache);
-      ObjectName[] cacheServers = service.getDistributedSystemMXBean().listCacheServerObjectNames();
-
-      if (cacheServers.length == 0) {
-        return ResultBuilder.createGemFireErrorResult(
-            CliStrings.format(CliStrings.LIST_CLIENT_COULD_NOT_RETRIEVE_SERVER_LIST));
-      }
-
-      Map<String, List<String>> clientServerMap = new HashMap<>();
-
-      for (ObjectName objName : cacheServers) {
-        CacheServerMXBean serverMbean = service.getMBeanInstance(objName, CacheServerMXBean.class);
-        String[] listOfClient = serverMbean.getClientIds();
-
-        if (listOfClient == null || listOfClient.length == 0) {
-          continue;
-        }
-
-
-        for (String clientName : listOfClient) {
-          String serverDetails = "member=" + objName.getKeyProperty("member") + ",port="
-              + objName.getKeyProperty("port");
-          if (clientServerMap.containsKey(clientName)) {
-            List<String> listServers = clientServerMap.get(clientName);
-            listServers.add(serverDetails);
-          } else {
-            List<String> listServer = new ArrayList<>();
-            listServer.add(serverDetails);
-            clientServerMap.put(clientName, listServer);
-          }
-        }
-      }
-
-      if (clientServerMap.size() == 0) {
-        return ResultBuilder.createGemFireErrorResult(
-            CliStrings.format(CliStrings.LIST_COULD_NOT_RETRIEVE_CLIENT_LIST));
-      }
-
-      String memberSeparator = ";  ";
-
-      for (Entry<String, List<String>> pairs : clientServerMap.entrySet()) {
-        String client = pairs.getKey();
-        List<String> servers = pairs.getValue();
-        StringBuilder serverListForClient = new StringBuilder();
-        int serversSize = servers.size();
-        int i = 0;
-        for (String server : servers) {
-          serverListForClient.append(server);
-          if (i < serversSize - 1) {
-            serverListForClient.append(memberSeparator);
-          }
-          i++;
-        }
-        resultTable.accumulate(CliStrings.LIST_CLIENT_COLUMN_Clients, client);
-        resultTable.accumulate(CliStrings.LIST_CLIENT_COLUMN_SERVERS,
-            serverListForClient.toString());
-      }
-      result = ResultBuilder.buildResult(compositeResultData);
-
-    } catch (Exception e) {
-      LogWrapper.getInstance()
-          .warning("Error in list clients. stack trace" + CliUtil.stackTraceAsString(e));
-      result = ResultBuilder.createGemFireErrorResult(CliStrings
-          .format(CliStrings.LIST_CLIENT_COULD_NOT_RETRIEVE_CLIENT_LIST_0, e.getMessage()));
-    }
-
-    LogWrapper.getInstance().info("list client result " + result);
-
-    return result;
-  }
-
-  @CliCommand(value = CliStrings.DESCRIBE_CLIENT, help = CliStrings.DESCRIBE_CLIENT__HELP)
-  @CliMetaData(relatedTopic = {CliStrings.TOPIC_CLIENT})
-  @ResourceOperation(resource = Resource.CLUSTER, operation = Operation.READ)
-  public Result describeClient(@CliOption(key = CliStrings.DESCRIBE_CLIENT__ID, mandatory = true,
-      help = CliStrings.DESCRIBE_CLIENT__ID__HELP) String clientId) {
-    Result result;
-
-    if (clientId.startsWith("\"")) {
-      clientId = clientId.substring(1);
-    }
-
-    if (clientId.endsWith("\"")) {
-      clientId = clientId.substring(0, clientId.length() - 2);
-    }
-
-    if (clientId.endsWith("\";")) {
-      clientId = clientId.substring(0, clientId.length() - 2);
-    }
-
-    try {
-      CompositeResultData compositeResultData = ResultBuilder.createCompositeResultData();
-      SectionResultData sectionResult = compositeResultData.addSection("InfoSection");
-      InternalCache cache = getCache();
-
-      ManagementService service = ManagementService.getExistingManagementService(cache);
-      ObjectName[] cacheServers = service.getDistributedSystemMXBean().listCacheServerObjectNames();
-      if (cacheServers.length == 0) {
-        return ResultBuilder.createGemFireErrorResult(
-            CliStrings.format(CliStrings.DESCRIBE_CLIENT_COULD_NOT_RETRIEVE_SERVER_LIST));
-      }
-
-      ClientHealthStatus clientHealthStatus = null;
-
-      for (ObjectName objName : cacheServers) {
-        CacheServerMXBean serverMbean = service.getMBeanInstance(objName, CacheServerMXBean.class);
-        List<String> listOfClient =
-            new ArrayList<>(Arrays.asList((String[]) serverMbean.getClientIds()));
-        if (listOfClient.contains(clientId)) {
-          if (clientHealthStatus == null) {
-            try {
-              clientHealthStatus = serverMbean.showClientStats(clientId);
-              if (clientHealthStatus == null) {
-                return ResultBuilder.createGemFireErrorResult(CliStrings.format(
-                    CliStrings.DESCRIBE_CLIENT_COULD_NOT_RETRIEVE_STATS_FOR_CLIENT_0, clientId));
-              }
-            } catch (Exception eee) {
-              return ResultBuilder.createGemFireErrorResult(CliStrings.format(
-                  CliStrings.DESCRIBE_CLIENT_COULD_NOT_RETRIEVE_STATS_FOR_CLIENT_0_REASON_1,
-                  clientId, eee.getMessage()));
-            }
-          }
-        }
-      }
-
-      if (clientHealthStatus == null) {
-        return ResultBuilder.createGemFireErrorResult(
-            CliStrings.format(CliStrings.DESCRIBE_CLIENT__CLIENT__ID__NOT__FOUND__0, clientId));
-      }
-
-      Set<DistributedMember> dsMembers = CliUtil.getAllMembers(cache);
-      String isDurable = null;
-      List<String> primaryServers = new ArrayList<>();
-      List<String> secondaryServers = new ArrayList<>();
-
-      if (dsMembers.size() > 0) {
-        ContinuousQueryFunction continuousQueryFunction = new ContinuousQueryFunction();
-        FunctionService.registerFunction(continuousQueryFunction);
-        List<?> resultList = (List<?>) CliUtil
-            .executeFunction(continuousQueryFunction, clientId, dsMembers).getResult();
-        for (Object aResultList : resultList) {
-          try {
-            Object object = aResultList;
-            if (object instanceof Throwable) {
-              LogWrapper.getInstance().warning(
-                  "Exception in Describe Client " + ((Throwable) object).getMessage(),
-                  ((Throwable) object));
-              continue;
-            }
-
-            if (object != null) {
-              ClientInfo objectResult = (ClientInfo) object;
-              isDurable = objectResult.isDurable;
-
-              if (objectResult.primaryServer != null && objectResult.primaryServer.length() > 0) {
-                if (primaryServers.size() == 0) {
-                  primaryServers.add(objectResult.primaryServer);
-                } else {
-                  primaryServers.add(" ,");
-                  primaryServers.add(objectResult.primaryServer);
-                }
-              }
-
-              if (objectResult.secondaryServer != null
-                  && objectResult.secondaryServer.length() > 0) {
-                if (secondaryServers.size() == 0) {
-                  secondaryServers.add(objectResult.secondaryServer);
-                } else {
-                  secondaryServers.add(" ,");
-                  secondaryServers.add(objectResult.secondaryServer);
-                }
-              }
-            }
-          } catch (Exception e) {
-            LogWrapper.getInstance().info(CliStrings.DESCRIBE_CLIENT_ERROR_FETCHING_STATS_0 + " :: "
-                + CliUtil.stackTraceAsString(e));
-            return ResultBuilder.createGemFireErrorResult(CliStrings
-                .format(CliStrings.DESCRIBE_CLIENT_ERROR_FETCHING_STATS_0, e.getMessage()));
-          }
-        }
-
-        buildTableResult(sectionResult, clientHealthStatus, isDurable, primaryServers,
-            secondaryServers);
-        result = ResultBuilder.buildResult(compositeResultData);
-      } else {
-        return ResultBuilder.createGemFireErrorResult(CliStrings.DESCRIBE_CLIENT_NO_MEMBERS);
-      }
-    } catch (Exception e) {
-      LogWrapper.getInstance()
-          .info("Error in describe clients. stack trace" + CliUtil.stackTraceAsString(e));
-      result = ResultBuilder.createGemFireErrorResult(CliStrings
-          .format(CliStrings.DESCRIBE_CLIENT_COULD_NOT_RETRIEVE_CLIENT_0, e.getMessage()));
-    }
-    LogWrapper.getInstance().info("describe client result " + result);
-    return result;
-  }
-
-  private void buildTableResult(SectionResultData sectionResult,
-      ClientHealthStatus clientHealthStatus, String isDurable, List<String> primaryServers,
-      List<String> secondaryServers) {
-
-    StringBuilder primServers = new StringBuilder();
-    for (String primaryServer : primaryServers) {
-      primServers.append(primaryServer);
-    }
-
-    StringBuilder secondServers = new StringBuilder();
-    for (String secondServer : secondaryServers) {
-      secondServers.append(secondServer);
-    }
-    if (clientHealthStatus != null) {
-      sectionResult.addSeparator('-');
-      sectionResult.addData(CliStrings.DESCRIBE_CLIENT_COLUMN_PRIMARY_SERVERS, primServers);
-      sectionResult.addData(CliStrings.DESCRIBE_CLIENT_COLUMN_SECONDARY_SERVERS, secondServers);
-      sectionResult.addData(CliStrings.DESCRIBE_CLIENT_COLUMN_CPU, clientHealthStatus.getCpus());
-      sectionResult.addData(CliStrings.DESCRIBE_CLIENT_COLUMN_LISTENER_CALLS,
-          clientHealthStatus.getNumOfCacheListenerCalls());
-      sectionResult.addData(CliStrings.DESCRIBE_CLIENT_COLUMN_GETS,
-          clientHealthStatus.getNumOfGets());
-      sectionResult.addData(CliStrings.DESCRIBE_CLIENT_COLUMN_MISSES,
-          clientHealthStatus.getNumOfMisses());
-      sectionResult.addData(CliStrings.DESCRIBE_CLIENT_COLUMN_PUTS,
-          clientHealthStatus.getNumOfPuts());
-      sectionResult.addData(CliStrings.DESCRIBE_CLIENT_COLUMN_THREADS,
-          clientHealthStatus.getNumOfThreads());
-      sectionResult.addData(CliStrings.DESCRIBE_CLIENT_COLUMN_PROCESS_CPU_TIME,
-          clientHealthStatus.getProcessCpuTime());
-      sectionResult.addData(CliStrings.DESCRIBE_CLIENT_COLUMN_QUEUE_SIZE,
-          clientHealthStatus.getQueueSize());
-      sectionResult.addData(CliStrings.DESCRIBE_CLIENT_COLUMN_UP_TIME,
-          clientHealthStatus.getUpTime());
-      sectionResult.addData(CliStrings.DESCRIBE_CLIENT_COLUMN_DURABLE, isDurable);
-      sectionResult.addSeparator('-');
-
-      Map<String, String> poolStats = clientHealthStatus.getPoolStats();
-
-      if (poolStats.size() > 0) {
-        for (Entry<String, String> entry : poolStats.entrySet()) {
-          TabularResultData poolStatsResultTable =
-              sectionResult.addTable("Pool Stats For Pool Name = " + entry.getKey());
-          poolStatsResultTable.setHeader("Pool Stats For Pool Name = " + entry.getKey());
-          String poolStatsStr = entry.getValue();
-          String str[] = poolStatsStr.split(";");
-
-          LogWrapper.getInstance().info("describe client clientHealthStatus min conn="
-              + str[0].substring(str[0].indexOf("=") + 1));
-          LogWrapper.getInstance().info("describe client clientHealthStatus max conn ="
-              + str[1].substring(str[1].indexOf("=") + 1));
-          LogWrapper.getInstance().info("describe client clientHealthStatus redundancy ="
-              + str[2].substring(str[2].indexOf("=") + 1));
-          LogWrapper.getInstance().info("describe client clientHealthStatus CQs ="
-              + str[3].substring(str[3].indexOf("=") + 1));
-
-          poolStatsResultTable.accumulate(CliStrings.DESCRIBE_CLIENT_MIN_CONN,
-              str[0].substring(str[0].indexOf("=") + 1));
-          poolStatsResultTable.accumulate(CliStrings.DESCRIBE_CLIENT_MAX_CONN,
-              str[1].substring(str[1].indexOf("=") + 1));
-          poolStatsResultTable.accumulate(CliStrings.DESCRIBE_CLIENT_REDUNDANCY,
-              str[2].substring(str[2].indexOf("=") + 1));
-          poolStatsResultTable.accumulate(CliStrings.DESCRIBE_CLIENT_CQs,
-              str[3].substring(str[3].indexOf("=") + 1));
-        }
-      }
-    }
-  }
-}

http://git-wip-us.apache.org/repos/asf/geode/blob/7ae99960/geode-core/src/main/java/org/apache/geode/management/internal/cli/commands/DescribeClientCommand.java
----------------------------------------------------------------------
diff --git a/geode-core/src/main/java/org/apache/geode/management/internal/cli/commands/DescribeClientCommand.java b/geode-core/src/main/java/org/apache/geode/management/internal/cli/commands/DescribeClientCommand.java
new file mode 100644
index 0000000..9b37f12
--- /dev/null
+++ b/geode-core/src/main/java/org/apache/geode/management/internal/cli/commands/DescribeClientCommand.java
@@ -0,0 +1,245 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more contributor license
+ * agreements. See the NOTICE file distributed with this work for additional information regarding
+ * copyright ownership. The ASF licenses this file to You under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance with the License. You may obtain a
+ * copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software distributed under the License
+ * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
+ * or implied. See the License for the specific language governing permissions and limitations under
+ * the License.
+ */
+
+package org.apache.geode.management.internal.cli.commands;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+
+import javax.management.ObjectName;
+
+import org.springframework.shell.core.annotation.CliCommand;
+import org.springframework.shell.core.annotation.CliOption;
+
+import org.apache.geode.cache.execute.FunctionService;
+import org.apache.geode.distributed.DistributedMember;
+import org.apache.geode.internal.cache.InternalCache;
+import org.apache.geode.management.CacheServerMXBean;
+import org.apache.geode.management.ClientHealthStatus;
+import org.apache.geode.management.ManagementService;
+import org.apache.geode.management.cli.CliMetaData;
+import org.apache.geode.management.cli.Result;
+import org.apache.geode.management.internal.cli.CliUtil;
+import org.apache.geode.management.internal.cli.LogWrapper;
+import org.apache.geode.management.internal.cli.functions.ContinuousQueryFunction;
+import org.apache.geode.management.internal.cli.i18n.CliStrings;
+import org.apache.geode.management.internal.cli.result.CompositeResultData;
+import org.apache.geode.management.internal.cli.result.ResultBuilder;
+import org.apache.geode.management.internal.cli.result.TabularResultData;
+import org.apache.geode.management.internal.security.ResourceOperation;
+import org.apache.geode.security.ResourcePermission;
+
+public class DescribeClientCommand implements GfshCommand {
+  @CliCommand(value = CliStrings.DESCRIBE_CLIENT, help = CliStrings.DESCRIBE_CLIENT__HELP)
+  @CliMetaData(relatedTopic = {CliStrings.TOPIC_CLIENT})
+  @ResourceOperation(resource = ResourcePermission.Resource.CLUSTER,
+      operation = ResourcePermission.Operation.READ)
+  public Result describeClient(@CliOption(key = CliStrings.DESCRIBE_CLIENT__ID, mandatory = true,
+      help = CliStrings.DESCRIBE_CLIENT__ID__HELP) String clientId) {
+    Result result;
+
+    if (clientId.startsWith("\"")) {
+      clientId = clientId.substring(1);
+    }
+
+    if (clientId.endsWith("\"")) {
+      clientId = clientId.substring(0, clientId.length() - 2);
+    }
+
+    if (clientId.endsWith("\";")) {
+      clientId = clientId.substring(0, clientId.length() - 2);
+    }
+
+    try {
+      CompositeResultData compositeResultData = ResultBuilder.createCompositeResultData();
+      CompositeResultData.SectionResultData sectionResult =
+          compositeResultData.addSection("InfoSection");
+      InternalCache cache = getCache();
+
+      ManagementService service = ManagementService.getExistingManagementService(cache);
+      ObjectName[] cacheServers = service.getDistributedSystemMXBean().listCacheServerObjectNames();
+      if (cacheServers.length == 0) {
+        return ResultBuilder.createGemFireErrorResult(
+            CliStrings.format(CliStrings.DESCRIBE_CLIENT_COULD_NOT_RETRIEVE_SERVER_LIST));
+      }
+
+      ClientHealthStatus clientHealthStatus = null;
+
+      for (ObjectName objName : cacheServers) {
+        CacheServerMXBean serverMbean = service.getMBeanInstance(objName, CacheServerMXBean.class);
+        List<String> listOfClient =
+            new ArrayList<>(Arrays.asList((String[]) serverMbean.getClientIds()));
+        if (listOfClient.contains(clientId)) {
+          if (clientHealthStatus == null) {
+            try {
+              clientHealthStatus = serverMbean.showClientStats(clientId);
+              if (clientHealthStatus == null) {
+                return ResultBuilder.createGemFireErrorResult(CliStrings.format(
+                    CliStrings.DESCRIBE_CLIENT_COULD_NOT_RETRIEVE_STATS_FOR_CLIENT_0, clientId));
+              }
+            } catch (Exception eee) {
+              return ResultBuilder.createGemFireErrorResult(CliStrings.format(
+                  CliStrings.DESCRIBE_CLIENT_COULD_NOT_RETRIEVE_STATS_FOR_CLIENT_0_REASON_1,
+                  clientId, eee.getMessage()));
+            }
+          }
+        }
+      }
+
+      if (clientHealthStatus == null) {
+        return ResultBuilder.createGemFireErrorResult(
+            CliStrings.format(CliStrings.DESCRIBE_CLIENT__CLIENT__ID__NOT__FOUND__0, clientId));
+      }
+
+      Set<DistributedMember> dsMembers = CliUtil.getAllMembers(cache);
+      String isDurable = null;
+      List<String> primaryServers = new ArrayList<>();
+      List<String> secondaryServers = new ArrayList<>();
+
+      if (dsMembers.size() > 0) {
+        ContinuousQueryFunction continuousQueryFunction = new ContinuousQueryFunction();
+        FunctionService.registerFunction(continuousQueryFunction);
+        List<?> resultList = (List<?>) CliUtil
+            .executeFunction(continuousQueryFunction, clientId, dsMembers).getResult();
+        for (Object aResultList : resultList) {
+          try {
+            Object object = aResultList;
+            if (object instanceof Throwable) {
+              LogWrapper.getInstance().warning(
+                  "Exception in Describe Client " + ((Throwable) object).getMessage(),
+                  ((Throwable) object));
+              continue;
+            }
+
+            if (object != null) {
+              ContinuousQueryFunction.ClientInfo objectResult =
+                  (ContinuousQueryFunction.ClientInfo) object;
+              isDurable = objectResult.isDurable;
+
+              if (objectResult.primaryServer != null && objectResult.primaryServer.length() > 0) {
+                if (primaryServers.size() == 0) {
+                  primaryServers.add(objectResult.primaryServer);
+                } else {
+                  primaryServers.add(" ,");
+                  primaryServers.add(objectResult.primaryServer);
+                }
+              }
+
+              if (objectResult.secondaryServer != null
+                  && objectResult.secondaryServer.length() > 0) {
+                if (secondaryServers.size() == 0) {
+                  secondaryServers.add(objectResult.secondaryServer);
+                } else {
+                  secondaryServers.add(" ,");
+                  secondaryServers.add(objectResult.secondaryServer);
+                }
+              }
+            }
+          } catch (Exception e) {
+            LogWrapper.getInstance().info(CliStrings.DESCRIBE_CLIENT_ERROR_FETCHING_STATS_0 + " :: "
+                + CliUtil.stackTraceAsString(e));
+            return ResultBuilder.createGemFireErrorResult(CliStrings
+                .format(CliStrings.DESCRIBE_CLIENT_ERROR_FETCHING_STATS_0, e.getMessage()));
+          }
+        }
+
+        buildTableResult(sectionResult, clientHealthStatus, isDurable, primaryServers,
+            secondaryServers);
+        result = ResultBuilder.buildResult(compositeResultData);
+      } else {
+        return ResultBuilder.createGemFireErrorResult(CliStrings.DESCRIBE_CLIENT_NO_MEMBERS);
+      }
+    } catch (Exception e) {
+      LogWrapper.getInstance()
+          .info("Error in describe clients. stack trace" + CliUtil.stackTraceAsString(e));
+      result = ResultBuilder.createGemFireErrorResult(CliStrings
+          .format(CliStrings.DESCRIBE_CLIENT_COULD_NOT_RETRIEVE_CLIENT_0, e.getMessage()));
+    }
+    LogWrapper.getInstance().info("describe client result " + result);
+    return result;
+  }
+
+  private void buildTableResult(CompositeResultData.SectionResultData sectionResult,
+      ClientHealthStatus clientHealthStatus, String isDurable, List<String> primaryServers,
+      List<String> secondaryServers) {
+
+    StringBuilder primServers = new StringBuilder();
+    for (String primaryServer : primaryServers) {
+      primServers.append(primaryServer);
+    }
+
+    StringBuilder secondServers = new StringBuilder();
+    for (String secondServer : secondaryServers) {
+      secondServers.append(secondServer);
+    }
+    if (clientHealthStatus != null) {
+      sectionResult.addSeparator('-');
+      sectionResult.addData(CliStrings.DESCRIBE_CLIENT_COLUMN_PRIMARY_SERVERS, primServers);
+      sectionResult.addData(CliStrings.DESCRIBE_CLIENT_COLUMN_SECONDARY_SERVERS, secondServers);
+      sectionResult.addData(CliStrings.DESCRIBE_CLIENT_COLUMN_CPU, clientHealthStatus.getCpus());
+      sectionResult.addData(CliStrings.DESCRIBE_CLIENT_COLUMN_LISTENER_CALLS,
+          clientHealthStatus.getNumOfCacheListenerCalls());
+      sectionResult.addData(CliStrings.DESCRIBE_CLIENT_COLUMN_GETS,
+          clientHealthStatus.getNumOfGets());
+      sectionResult.addData(CliStrings.DESCRIBE_CLIENT_COLUMN_MISSES,
+          clientHealthStatus.getNumOfMisses());
+      sectionResult.addData(CliStrings.DESCRIBE_CLIENT_COLUMN_PUTS,
+          clientHealthStatus.getNumOfPuts());
+      sectionResult.addData(CliStrings.DESCRIBE_CLIENT_COLUMN_THREADS,
+          clientHealthStatus.getNumOfThreads());
+      sectionResult.addData(CliStrings.DESCRIBE_CLIENT_COLUMN_PROCESS_CPU_TIME,
+          clientHealthStatus.getProcessCpuTime());
+      sectionResult.addData(CliStrings.DESCRIBE_CLIENT_COLUMN_QUEUE_SIZE,
+          clientHealthStatus.getQueueSize());
+      sectionResult.addData(CliStrings.DESCRIBE_CLIENT_COLUMN_UP_TIME,
+          clientHealthStatus.getUpTime());
+      sectionResult.addData(CliStrings.DESCRIBE_CLIENT_COLUMN_DURABLE, isDurable);
+      sectionResult.addSeparator('-');
+
+      Map<String, String> poolStats = clientHealthStatus.getPoolStats();
+
+      if (poolStats.size() > 0) {
+        for (Map.Entry<String, String> entry : poolStats.entrySet()) {
+          TabularResultData poolStatsResultTable =
+              sectionResult.addTable("Pool Stats For Pool Name = " + entry.getKey());
+          poolStatsResultTable.setHeader("Pool Stats For Pool Name = " + entry.getKey());
+          String poolStatsStr = entry.getValue();
+          String str[] = poolStatsStr.split(";");
+
+          LogWrapper.getInstance().info("describe client clientHealthStatus min conn="
+              + str[0].substring(str[0].indexOf("=") + 1));
+          LogWrapper.getInstance().info("describe client clientHealthStatus max conn ="
+              + str[1].substring(str[1].indexOf("=") + 1));
+          LogWrapper.getInstance().info("describe client clientHealthStatus redundancy ="
+              + str[2].substring(str[2].indexOf("=") + 1));
+          LogWrapper.getInstance().info("describe client clientHealthStatus CQs ="
+              + str[3].substring(str[3].indexOf("=") + 1));
+
+          poolStatsResultTable.accumulate(CliStrings.DESCRIBE_CLIENT_MIN_CONN,
+              str[0].substring(str[0].indexOf("=") + 1));
+          poolStatsResultTable.accumulate(CliStrings.DESCRIBE_CLIENT_MAX_CONN,
+              str[1].substring(str[1].indexOf("=") + 1));
+          poolStatsResultTable.accumulate(CliStrings.DESCRIBE_CLIENT_REDUNDANCY,
+              str[2].substring(str[2].indexOf("=") + 1));
+          poolStatsResultTable.accumulate(CliStrings.DESCRIBE_CLIENT_CQs,
+              str[3].substring(str[3].indexOf("=") + 1));
+        }
+      }
+    }
+  }
+}

http://git-wip-us.apache.org/repos/asf/geode/blob/7ae99960/geode-core/src/main/java/org/apache/geode/management/internal/cli/commands/ListClientCommand.java
----------------------------------------------------------------------
diff --git a/geode-core/src/main/java/org/apache/geode/management/internal/cli/commands/ListClientCommand.java b/geode-core/src/main/java/org/apache/geode/management/internal/cli/commands/ListClientCommand.java
new file mode 100644
index 0000000..c2b6425
--- /dev/null
+++ b/geode-core/src/main/java/org/apache/geode/management/internal/cli/commands/ListClientCommand.java
@@ -0,0 +1,128 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more contributor license
+ * agreements. See the NOTICE file distributed with this work for additional information regarding
+ * copyright ownership. The ASF licenses this file to You under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance with the License. You may obtain a
+ * copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software distributed under the License
+ * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
+ * or implied. See the License for the specific language governing permissions and limitations under
+ * the License.
+ */
+
+package org.apache.geode.management.internal.cli.commands;
+
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+import javax.management.ObjectName;
+
+import org.springframework.shell.core.annotation.CliCommand;
+
+import org.apache.geode.internal.cache.InternalCache;
+import org.apache.geode.management.CacheServerMXBean;
+import org.apache.geode.management.ManagementService;
+import org.apache.geode.management.cli.CliMetaData;
+import org.apache.geode.management.cli.Result;
+import org.apache.geode.management.internal.cli.CliUtil;
+import org.apache.geode.management.internal.cli.LogWrapper;
+import org.apache.geode.management.internal.cli.i18n.CliStrings;
+import org.apache.geode.management.internal.cli.result.CompositeResultData;
+import org.apache.geode.management.internal.cli.result.ResultBuilder;
+import org.apache.geode.management.internal.cli.result.TabularResultData;
+import org.apache.geode.management.internal.security.ResourceOperation;
+import org.apache.geode.security.ResourcePermission;
+
+public class ListClientCommand implements GfshCommand {
+  @CliCommand(value = CliStrings.LIST_CLIENTS, help = CliStrings.LIST_CLIENT__HELP)
+  @CliMetaData(relatedTopic = {CliStrings.TOPIC_CLIENT})
+  @ResourceOperation(resource = ResourcePermission.Resource.CLUSTER,
+      operation = ResourcePermission.Operation.READ)
+  public Result listClient() {
+    Result result;
+
+    try {
+      CompositeResultData compositeResultData = ResultBuilder.createCompositeResultData();
+      CompositeResultData.SectionResultData section = compositeResultData.addSection("section1");
+
+      TabularResultData resultTable = section.addTable("TableForClientList");
+      String headerText = "ClientList";
+      resultTable = resultTable.setHeader(headerText);
+
+      InternalCache cache = getCache();
+      ManagementService service = ManagementService.getExistingManagementService(cache);
+      ObjectName[] cacheServers = service.getDistributedSystemMXBean().listCacheServerObjectNames();
+
+      if (cacheServers.length == 0) {
+        return ResultBuilder.createGemFireErrorResult(
+            CliStrings.format(CliStrings.LIST_CLIENT_COULD_NOT_RETRIEVE_SERVER_LIST));
+      }
+
+      Map<String, List<String>> clientServerMap = new HashMap<>();
+
+      for (ObjectName objName : cacheServers) {
+        CacheServerMXBean serverMbean = service.getMBeanInstance(objName, CacheServerMXBean.class);
+        String[] listOfClient = serverMbean.getClientIds();
+
+        if (listOfClient == null || listOfClient.length == 0) {
+          continue;
+        }
+
+
+        for (String clientName : listOfClient) {
+          String serverDetails = "member=" + objName.getKeyProperty("member") + ",port="
+              + objName.getKeyProperty("port");
+          if (clientServerMap.containsKey(clientName)) {
+            List<String> listServers = clientServerMap.get(clientName);
+            listServers.add(serverDetails);
+          } else {
+            List<String> listServer = new ArrayList<>();
+            listServer.add(serverDetails);
+            clientServerMap.put(clientName, listServer);
+          }
+        }
+      }
+
+      if (clientServerMap.size() == 0) {
+        return ResultBuilder.createGemFireErrorResult(
+            CliStrings.format(CliStrings.LIST_COULD_NOT_RETRIEVE_CLIENT_LIST));
+      }
+
+      String memberSeparator = ";  ";
+
+      for (Map.Entry<String, List<String>> pairs : clientServerMap.entrySet()) {
+        String client = pairs.getKey();
+        List<String> servers = pairs.getValue();
+        StringBuilder serverListForClient = new StringBuilder();
+        int serversSize = servers.size();
+        int i = 0;
+        for (String server : servers) {
+          serverListForClient.append(server);
+          if (i < serversSize - 1) {
+            serverListForClient.append(memberSeparator);
+          }
+          i++;
+        }
+        resultTable.accumulate(CliStrings.LIST_CLIENT_COLUMN_Clients, client);
+        resultTable.accumulate(CliStrings.LIST_CLIENT_COLUMN_SERVERS,
+            serverListForClient.toString());
+      }
+      result = ResultBuilder.buildResult(compositeResultData);
+
+    } catch (Exception e) {
+      LogWrapper.getInstance()
+          .warning("Error in list clients. stack trace" + CliUtil.stackTraceAsString(e));
+      result = ResultBuilder.createGemFireErrorResult(CliStrings
+          .format(CliStrings.LIST_CLIENT_COULD_NOT_RETRIEVE_CLIENT_LIST_0, e.getMessage()));
+    }
+
+    LogWrapper.getInstance().info("list client result " + result);
+
+    return result;
+  }
+}

http://git-wip-us.apache.org/repos/asf/geode/blob/7ae99960/geode-core/src/main/java/org/apache/geode/management/internal/web/controllers/ClientCommandsController.java
----------------------------------------------------------------------
diff --git a/geode-core/src/main/java/org/apache/geode/management/internal/web/controllers/ClientCommandsController.java b/geode-core/src/main/java/org/apache/geode/management/internal/web/controllers/ClientCommandsController.java
index d07ea9a..e8df505 100644
--- a/geode-core/src/main/java/org/apache/geode/management/internal/web/controllers/ClientCommandsController.java
+++ b/geode-core/src/main/java/org/apache/geode/management/internal/web/controllers/ClientCommandsController.java
@@ -14,20 +14,21 @@
  */
 package org.apache.geode.management.internal.web.controllers;
 
-import org.apache.geode.management.internal.cli.i18n.CliStrings;
-import org.apache.geode.management.internal.cli.util.CommandStringBuilder;
-
 import org.springframework.stereotype.Controller;
 import org.springframework.web.bind.annotation.PathVariable;
 import org.springframework.web.bind.annotation.RequestMapping;
 import org.springframework.web.bind.annotation.RequestMethod;
 import org.springframework.web.bind.annotation.ResponseBody;
 
+import org.apache.geode.management.internal.cli.i18n.CliStrings;
+import org.apache.geode.management.internal.cli.util.CommandStringBuilder;
+
 /**
  * The ShellCommandsController class implements GemFire REST API calls for Gfsh Shell Commands.
  * <p/>
  * 
- * @see org.apache.geode.management.internal.cli.commands.ClientCommands
+ * @see org.apache.geode.management.internal.cli.commands.ListClientCommand
+ * @see org.apache.geode.management.internal.cli.commands.DescribeClientCommand
  * @see org.apache.geode.management.internal.web.controllers.AbstractCommandsController
  * @see org.springframework.stereotype.Controller
  * @see org.springframework.web.bind.annotation.RequestMapping

http://git-wip-us.apache.org/repos/asf/geode/blob/7ae99960/geode-core/src/test/java/org/apache/geode/management/internal/security/TestCommand.java
----------------------------------------------------------------------
diff --git a/geode-core/src/test/java/org/apache/geode/management/internal/security/TestCommand.java b/geode-core/src/test/java/org/apache/geode/management/internal/security/TestCommand.java
index d2fdace..f380d88 100644
--- a/geode-core/src/test/java/org/apache/geode/management/internal/security/TestCommand.java
+++ b/geode-core/src/test/java/org/apache/geode/management/internal/security/TestCommand.java
@@ -119,7 +119,7 @@ public class TestCommand {
   }
 
   private static void init() {
-    // ClientCommands
+    // ListClientCommand, DescribeClientCommand
     createTestCommand("list clients", clusterRead);
     createTestCommand("describe client --clientID=172.16.196.144", clusterRead);
 

http://git-wip-us.apache.org/repos/asf/geode/blob/7ae99960/geode-core/src/test/java/org/apache/geode/test/dunit/internal/JUnit4DistributedTestCase.java
----------------------------------------------------------------------
diff --git a/geode-core/src/test/java/org/apache/geode/test/dunit/internal/JUnit4DistributedTestCase.java b/geode-core/src/test/java/org/apache/geode/test/dunit/internal/JUnit4DistributedTestCase.java
index 110d649..9f13dfb 100644
--- a/geode-core/src/test/java/org/apache/geode/test/dunit/internal/JUnit4DistributedTestCase.java
+++ b/geode-core/src/test/java/org/apache/geode/test/dunit/internal/JUnit4DistributedTestCase.java
@@ -20,6 +20,20 @@ import static org.apache.geode.distributed.ConfigurationProperties.MCAST_PORT;
 import static org.apache.geode.distributed.ConfigurationProperties.STATISTIC_ARCHIVE_FILE;
 import static org.junit.Assert.assertNotNull;
 
+import java.io.Serializable;
+import java.text.DecimalFormat;
+import java.util.Iterator;
+import java.util.LinkedHashSet;
+import java.util.Map;
+import java.util.Properties;
+import java.util.Set;
+
+import org.apache.logging.log4j.Logger;
+import org.junit.After;
+import org.junit.Before;
+import org.junit.BeforeClass;
+import org.junit.Rule;
+
 import org.apache.geode.admin.internal.AdminDistributedSystemImpl;
 import org.apache.geode.cache.Cache;
 import org.apache.geode.cache.Region;
@@ -57,19 +71,6 @@ import org.apache.geode.test.dunit.Invoke;
 import org.apache.geode.test.dunit.LogWriterUtils;
 import org.apache.geode.test.dunit.standalone.DUnitLauncher;
 import org.apache.geode.test.junit.rules.serializable.SerializableTestName;
-import org.apache.logging.log4j.Logger;
-import org.junit.After;
-import org.junit.Before;
-import org.junit.BeforeClass;
-import org.junit.Rule;
-
-import java.io.Serializable;
-import java.text.DecimalFormat;
-import java.util.Iterator;
-import java.util.LinkedHashSet;
-import java.util.Map;
-import java.util.Properties;
-import java.util.Set;
 
 /**
  * This class is the base class for all distributed tests using JUnit 4.
@@ -210,8 +211,8 @@ public abstract class JUnit4DistributedTestCase implements DistributedTestFixtur
         }
       } else {
         Properties activeProps = system.getProperties();
-        for (Iterator iter = props.entrySet().iterator(); iter.hasNext();) {
-          Map.Entry entry = (Map.Entry) iter.next();
+        for (Map.Entry<Object, Object> objectObjectEntry : props.entrySet()) {
+          Map.Entry entry = objectObjectEntry;
           String key = (String) entry.getKey();
           String value = (String) entry.getValue();
           if (!value.equals(activeProps.getProperty(key))) {