You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@geode.apache.org by ji...@apache.org on 2018/04/26 16:46:26 UTC

[geode] branch develop updated: GEODE-4858: refactor CreateIndexCommand and jdbc commands (#1853)

This is an automated email from the ASF dual-hosted git repository.

jinmeiliao pushed a commit to branch develop
in repository https://gitbox.apache.org/repos/asf/geode.git


The following commit(s) were added to refs/heads/develop by this push:
     new ca30ee0  GEODE-4858: refactor CreateIndexCommand and jdbc commands (#1853)
ca30ee0 is described below

commit ca30ee062cd82f973a24905cd8b2bdaebf5e055e
Author: jinmeiliao <ji...@pivotal.io>
AuthorDate: Thu Apr 26 09:46:21 2018 -0700

    GEODE-4858: refactor CreateIndexCommand and jdbc commands (#1853)
    
    * use ClusterConfigurationService
    * introduce SingleGfshCommand to ease update of cluster configuration
    * get rid of default methods in CluterConfigurationService
---
 .../jdbc/internal/cli/AlterConnectionCommand.java  |  42 ++--
 .../jdbc/internal/cli/AlterMappingCommand.java     |  47 ++---
 .../jdbc/internal/cli/CreateConnectionCommand.java |  34 ++--
 .../jdbc/internal/cli/CreateMappingCommand.java    |  35 ++--
 .../internal/cli/DescribeConnectionCommand.java    |  16 +-
 .../jdbc/internal/cli/DescribeMappingCommand.java  |  16 +-
 .../internal/cli/DestroyConnectionCommand.java     |  33 ++--
 .../jdbc/internal/cli/DestroyMappingCommand.java   |  32 ++-
 .../jdbc/internal/cli/ListConnectionCommand.java   |  18 +-
 .../jdbc/internal/cli/ListMappingCommand.java      |  18 +-
 .../internal/cli/AlterConnectionCommandTest.java   |  10 +-
 .../jdbc/internal/cli/AlterMappingCommandTest.java |  10 +-
 .../cli/DescribeConnectionCommandTest.java         |   9 +-
 .../internal/cli/DescribeMappingCommandTest.java   |   9 +-
 .../cli/JdbcClusterConfigDistributedTest.java      | 140 ++++---------
 .../internal/cli/ListConnectionCommandTest.java    |  17 +-
 .../jdbc/internal/cli/ListMappingCommandTest.java  |  17 +-
 .../geode/cache/configuration/CacheConfig.java     |  47 +++++
 .../geode/cache/configuration/CacheElement.java    |  44 -----
 .../geode/cache/configuration/RegionConfig.java    | 219 ++-------------------
 .../distributed/ClusterConfigurationService.java   |  88 +--------
 .../InternalClusterConfigurationService.java       |  17 +-
 .../internal/cache/ClusterConfigurationLoader.java |   6 +-
 .../geode/internal/cache/GemFireCacheImpl.java     |   6 +-
 .../geode/management/cli/SingleGfshCommand.java    |  45 +++++
 .../internal/cli/commands/CreateIndexCommand.java  |  61 ++++--
 .../cli/functions/CreateIndexFunction.java         |  74 ++-----
 .../internal/cli/remote/CommandExecutor.java       |  55 +++++-
 .../cli/remote/OnlineCommandProcessor.java         |   3 +-
 .../internal/cli/result/CommandResult.java         |   9 +
 .../internal/cli/shell/GfshExecutionStrategy.java  |   2 +-
 .../sanctioned-geode-core-serializables.txt        |   1 +
 .../geode/cache/configuration/CacheConfigTest.java |  54 +++++
 .../InternalClusterConfigurationServiceTest.java   |  87 ++------
 .../cli/commands/CreateIndexCommandDUnitTest.java  | 128 ++++++++++++
 .../cli/commands/CreateIndexCommandTest.java       |  26 ++-
 .../IndexCommandsShareConfigurationDUnitTest.java  |  94 ++-------
 .../internal/cli/remote/CommandExecutorTest.java   |   6 +-
 .../LuceneClusterConfigurationDUnitTest.java       |   4 +-
 39 files changed, 736 insertions(+), 843 deletions(-)

diff --git a/geode-connectors/src/main/java/org/apache/geode/connectors/jdbc/internal/cli/AlterConnectionCommand.java b/geode-connectors/src/main/java/org/apache/geode/connectors/jdbc/internal/cli/AlterConnectionCommand.java
index 73bd30d..3b5128a 100644
--- a/geode-connectors/src/main/java/org/apache/geode/connectors/jdbc/internal/cli/AlterConnectionCommand.java
+++ b/geode-connectors/src/main/java/org/apache/geode/connectors/jdbc/internal/cli/AlterConnectionCommand.java
@@ -14,19 +14,22 @@
  */
 package org.apache.geode.connectors.jdbc.internal.cli;
 
+import static org.apache.geode.distributed.ClusterConfigurationService.CLUSTER_CONFIG;
+
 import java.util.List;
 import java.util.Set;
 
 import org.springframework.shell.core.annotation.CliCommand;
 import org.springframework.shell.core.annotation.CliOption;
 
+import org.apache.geode.cache.configuration.CacheConfig;
 import org.apache.geode.cache.configuration.CacheElement;
 import org.apache.geode.connectors.jdbc.internal.configuration.ConnectorService;
 import org.apache.geode.distributed.ClusterConfigurationService;
 import org.apache.geode.distributed.DistributedMember;
 import org.apache.geode.management.cli.CliMetaData;
-import org.apache.geode.management.cli.GfshCommand;
 import org.apache.geode.management.cli.Result;
+import org.apache.geode.management.cli.SingleGfshCommand;
 import org.apache.geode.management.internal.cli.exceptions.EntityNotFoundException;
 import org.apache.geode.management.internal.cli.functions.CliFunctionResult;
 import org.apache.geode.management.internal.cli.i18n.CliStrings;
@@ -35,7 +38,7 @@ import org.apache.geode.management.internal.cli.result.ResultBuilder;
 import org.apache.geode.management.internal.security.ResourceOperation;
 import org.apache.geode.security.ResourcePermission;
 
-public class AlterConnectionCommand extends GfshCommand {
+public class AlterConnectionCommand extends SingleGfshCommand {
   static final String ALTER_JDBC_CONNECTION = "alter jdbc-connection";
   static final String ALTER_JDBC_CONNECTION__HELP =
       "Alter properties for an existing jdbc connection.";
@@ -79,8 +82,9 @@ public class AlterConnectionCommand extends GfshCommand {
     // if cc is running, you can only alter connection available in cc service.
     if (ccService != null) {
       // search for the connection that has this id to see if it exists
+      CacheConfig cacheConfig = ccService.getCacheConfig(CLUSTER_CONFIG);
       ConnectorService service =
-          ccService.getCustomCacheElement("cluster", "connector-service", ConnectorService.class);
+          cacheConfig.findCustomCacheElement("connector-service", ConnectorService.class);
       if (service == null) {
         throw new EntityNotFoundException("connection with name '" + name + "' does not exist.");
       }
@@ -94,26 +98,22 @@ public class AlterConnectionCommand extends GfshCommand {
     List<CliFunctionResult> results =
         executeAndGetFunctionResult(new AlterConnectionFunction(), newConnection, targetMembers);
 
-    // update the cc with the merged connection returned from the server
-    boolean persisted = false;
-    if (ccService != null && results.stream().filter(CliFunctionResult::isSuccessful).count() > 0) {
-      ConnectorService service =
-          ccService.getCustomCacheElement("cluster", "connector-service", ConnectorService.class);
-      if (service == null) {
-        service = new ConnectorService();
-      }
-      CliFunctionResult successResult =
-          results.stream().filter(CliFunctionResult::isSuccessful).findAny().get();
-      ConnectorService.Connection mergedConnection =
-          (ConnectorService.Connection) successResult.getResultObject();
-      CacheElement.removeElement(service.getConnection(), name);
-      service.getConnection().add(mergedConnection);
-      ccService.saveCustomCacheElement("cluster", service);
-      persisted = true;
-    }
+    CliFunctionResult successResult =
+        results.stream().filter(CliFunctionResult::isSuccessful).findAny().get();
+    ConnectorService.Connection mergedConnection =
+        (ConnectorService.Connection) successResult.getResultObject();
 
     CommandResult commandResult = ResultBuilder.buildResult(results);
-    commandResult.setCommandPersisted(persisted);
+    commandResult.setConfigObject(mergedConnection);
     return commandResult;
   }
+
+  @Override
+  public void updateClusterConfig(String group, CacheConfig config, Object element) {
+    ConnectorService.Connection connection = (ConnectorService.Connection) element;
+    ConnectorService service =
+        config.findCustomCacheElement("connector-service", ConnectorService.class);
+    CacheElement.removeElement(service.getConnection(), connection.getId());
+    service.getConnection().add(connection);
+  }
 }
diff --git a/geode-connectors/src/main/java/org/apache/geode/connectors/jdbc/internal/cli/AlterMappingCommand.java b/geode-connectors/src/main/java/org/apache/geode/connectors/jdbc/internal/cli/AlterMappingCommand.java
index ec56281..ccf8a15 100644
--- a/geode-connectors/src/main/java/org/apache/geode/connectors/jdbc/internal/cli/AlterMappingCommand.java
+++ b/geode-connectors/src/main/java/org/apache/geode/connectors/jdbc/internal/cli/AlterMappingCommand.java
@@ -14,19 +14,22 @@
  */
 package org.apache.geode.connectors.jdbc.internal.cli;
 
+import static org.apache.geode.distributed.ClusterConfigurationService.CLUSTER_CONFIG;
+
 import java.util.List;
 import java.util.Set;
 
 import org.springframework.shell.core.annotation.CliCommand;
 import org.springframework.shell.core.annotation.CliOption;
 
+import org.apache.geode.cache.configuration.CacheConfig;
 import org.apache.geode.cache.configuration.CacheElement;
 import org.apache.geode.connectors.jdbc.internal.configuration.ConnectorService;
 import org.apache.geode.distributed.ClusterConfigurationService;
 import org.apache.geode.distributed.DistributedMember;
 import org.apache.geode.management.cli.CliMetaData;
 import org.apache.geode.management.cli.Result;
-import org.apache.geode.management.internal.cli.commands.InternalGfshCommand;
+import org.apache.geode.management.cli.SingleGfshCommand;
 import org.apache.geode.management.internal.cli.exceptions.EntityNotFoundException;
 import org.apache.geode.management.internal.cli.functions.CliFunctionResult;
 import org.apache.geode.management.internal.cli.i18n.CliStrings;
@@ -35,7 +38,7 @@ import org.apache.geode.management.internal.cli.result.ResultBuilder;
 import org.apache.geode.management.internal.security.ResourceOperation;
 import org.apache.geode.security.ResourcePermission;
 
-public class AlterMappingCommand extends InternalGfshCommand {
+public class AlterMappingCommand extends SingleGfshCommand {
   static final String ALTER_MAPPING = "alter jdbc-mapping";
   static final String ALTER_MAPPING__HELP = "Alter properties for an existing jdbc mapping.";
 
@@ -85,8 +88,9 @@ public class AlterMappingCommand extends InternalGfshCommand {
     // if cc is running, you can only alter connection available in cc service.
     if (ccService != null) {
       // search for the connection that has this id to see if it exists
+      CacheConfig cacheConfig = ccService.getCacheConfig(CLUSTER_CONFIG);
       ConnectorService service =
-          ccService.getCustomCacheElement("cluster", "connector-service", ConnectorService.class);
+          cacheConfig.findCustomCacheElement("connector-service", ConnectorService.class);
       if (service == null) {
         throw new EntityNotFoundException("mapping with name '" + regionName + "' does not exist.");
       }
@@ -100,27 +104,24 @@ public class AlterMappingCommand extends InternalGfshCommand {
     // action
     List<CliFunctionResult> results =
         executeAndGetFunctionResult(new AlterMappingFunction(), newMapping, targetMembers);
-
-    boolean persisted = false;
-    // update the cc with the merged connection returned from the server
-    if (ccService != null && results.stream().filter(CliFunctionResult::isSuccessful).count() > 0) {
-      ConnectorService service =
-          ccService.getCustomCacheElement("cluster", "connector-service", ConnectorService.class);
-      if (service == null) {
-        service = new ConnectorService();
-      }
-      CliFunctionResult successResult =
-          results.stream().filter(CliFunctionResult::isSuccessful).findAny().get();
-      ConnectorService.RegionMapping mergedMapping =
-          (ConnectorService.RegionMapping) successResult.getResultObject();
-      CacheElement.removeElement(service.getRegionMapping(), connectionName);
-      service.getRegionMapping().add(mergedMapping);
-      ccService.saveCustomCacheElement("cluster", service);
-      persisted = true;
-    }
-
     CommandResult commandResult = ResultBuilder.buildResult(results);
-    commandResult.setCommandPersisted(persisted);
+
+    // find the merged regionMapping from the function result
+    CliFunctionResult successResult =
+        results.stream().filter(CliFunctionResult::isSuccessful).findAny().get();
+    ConnectorService.RegionMapping mergedMapping =
+        (ConnectorService.RegionMapping) successResult.getResultObject();
+    commandResult.setConfigObject(mergedMapping);
     return commandResult;
   }
+
+  @Override
+  public void updateClusterConfig(String group, CacheConfig config, Object element) {
+    ConnectorService.RegionMapping mapping = (ConnectorService.RegionMapping) element;
+    ConnectorService service =
+        config.findCustomCacheElement("connector-service", ConnectorService.class);
+    // service is not nul at this point
+    CacheElement.removeElement(service.getRegionMapping(), mapping.getId());
+    service.getRegionMapping().add(mapping);
+  }
 }
diff --git a/geode-connectors/src/main/java/org/apache/geode/connectors/jdbc/internal/cli/CreateConnectionCommand.java b/geode-connectors/src/main/java/org/apache/geode/connectors/jdbc/internal/cli/CreateConnectionCommand.java
index 67bee90..be2e4d7 100644
--- a/geode-connectors/src/main/java/org/apache/geode/connectors/jdbc/internal/cli/CreateConnectionCommand.java
+++ b/geode-connectors/src/main/java/org/apache/geode/connectors/jdbc/internal/cli/CreateConnectionCommand.java
@@ -22,14 +22,14 @@ import org.springframework.shell.core.annotation.CliAvailabilityIndicator;
 import org.springframework.shell.core.annotation.CliCommand;
 import org.springframework.shell.core.annotation.CliOption;
 
+import org.apache.geode.cache.configuration.CacheConfig;
 import org.apache.geode.connectors.jdbc.internal.configuration.ConnectorService;
-import org.apache.geode.distributed.ClusterConfigurationService;
 import org.apache.geode.distributed.DistributedMember;
 import org.apache.geode.management.cli.CliMetaData;
 import org.apache.geode.management.cli.Result;
+import org.apache.geode.management.cli.SingleGfshCommand;
 import org.apache.geode.management.internal.cli.AbstractCliAroundInterceptor;
 import org.apache.geode.management.internal.cli.GfshParseResult;
-import org.apache.geode.management.internal.cli.commands.InternalGfshCommand;
 import org.apache.geode.management.internal.cli.functions.CliFunctionResult;
 import org.apache.geode.management.internal.cli.i18n.CliStrings;
 import org.apache.geode.management.internal.cli.result.CommandResult;
@@ -37,7 +37,7 @@ import org.apache.geode.management.internal.cli.result.ResultBuilder;
 import org.apache.geode.management.internal.security.ResourceOperation;
 import org.apache.geode.security.ResourcePermission;
 
-public class CreateConnectionCommand extends InternalGfshCommand {
+public class CreateConnectionCommand extends SingleGfshCommand {
 
   static final String CREATE_CONNECTION = "create jdbc-connection";
   static final String CREATE_CONNECTION__HELP =
@@ -81,25 +81,23 @@ public class CreateConnectionCommand extends InternalGfshCommand {
     List<CliFunctionResult> results =
         executeAndGetFunctionResult(new CreateConnectionFunction(), connection, targetMembers);
 
-    boolean persisted = false;
-    ClusterConfigurationService ccService = getConfigurationService();
-
-    if (ccService != null && results.stream().filter(CliFunctionResult::isSuccessful).count() > 0) {
-      ConnectorService service =
-          ccService.getCustomCacheElement("cluster", "connector-service", ConnectorService.class);
-      if (service == null) {
-        service = new ConnectorService();
-      }
-      service.getConnection().add(connection);
-      ccService.saveCustomCacheElement("cluster", service);
-      persisted = true;
-    }
-
     CommandResult commandResult = ResultBuilder.buildResult(results);
-    commandResult.setCommandPersisted(persisted);
+    commandResult.setConfigObject(connection);
     return commandResult;
   }
 
+  @Override
+  public void updateClusterConfig(String group, CacheConfig config, Object element) {
+    ConnectorService.Connection connection = (ConnectorService.Connection) element;
+    ConnectorService service =
+        config.findCustomCacheElement("connector-service", ConnectorService.class);
+    if (service == null) {
+      service = new ConnectorService();
+      config.getCustomCacheElements().add(service);
+    }
+    service.getConnection().add(connection);
+  }
+
   public static class Interceptor extends AbstractCliAroundInterceptor {
     @Override
     public Result preExecution(GfshParseResult parseResult) {
diff --git a/geode-connectors/src/main/java/org/apache/geode/connectors/jdbc/internal/cli/CreateMappingCommand.java b/geode-connectors/src/main/java/org/apache/geode/connectors/jdbc/internal/cli/CreateMappingCommand.java
index ddf1985..1a06c2b 100644
--- a/geode-connectors/src/main/java/org/apache/geode/connectors/jdbc/internal/cli/CreateMappingCommand.java
+++ b/geode-connectors/src/main/java/org/apache/geode/connectors/jdbc/internal/cli/CreateMappingCommand.java
@@ -20,12 +20,12 @@ import java.util.Set;
 import org.springframework.shell.core.annotation.CliCommand;
 import org.springframework.shell.core.annotation.CliOption;
 
+import org.apache.geode.cache.configuration.CacheConfig;
 import org.apache.geode.connectors.jdbc.internal.configuration.ConnectorService;
-import org.apache.geode.distributed.ClusterConfigurationService;
 import org.apache.geode.distributed.DistributedMember;
 import org.apache.geode.management.cli.CliMetaData;
 import org.apache.geode.management.cli.Result;
-import org.apache.geode.management.internal.cli.commands.InternalGfshCommand;
+import org.apache.geode.management.cli.SingleGfshCommand;
 import org.apache.geode.management.internal.cli.functions.CliFunctionResult;
 import org.apache.geode.management.internal.cli.i18n.CliStrings;
 import org.apache.geode.management.internal.cli.result.CommandResult;
@@ -33,7 +33,7 @@ import org.apache.geode.management.internal.cli.result.ResultBuilder;
 import org.apache.geode.management.internal.security.ResourceOperation;
 import org.apache.geode.security.ResourcePermission;
 
-public class CreateMappingCommand extends InternalGfshCommand {
+public class CreateMappingCommand extends SingleGfshCommand {
   static final String CREATE_MAPPING = "create jdbc-mapping";
   static final String CREATE_MAPPING__HELP =
       "Create a mapping for a region for use with a JDBC database connection.";
@@ -55,8 +55,6 @@ public class CreateMappingCommand extends InternalGfshCommand {
   static final String CREATE_MAPPING__FIELD_MAPPING__HELP =
       "Key value pairs of PDX field names to database column names formatted like \"key:value(,key:value)*\".";
 
-  private static final String ERROR_PREFIX = "ERROR: ";
-
   @CliCommand(value = CREATE_MAPPING, help = CREATE_MAPPING__HELP)
   @CliMetaData(relatedTopic = CliStrings.DEFAULT_TOPIC_GEODE)
   @ResourceOperation(resource = ResourcePermission.Resource.CLUSTER,
@@ -86,22 +84,21 @@ public class CreateMappingCommand extends InternalGfshCommand {
     List<CliFunctionResult> results =
         executeAndGetFunctionResult(new CreateMappingFunction(), mapping, targetMembers);
 
-    boolean persisted = false;
-    ClusterConfigurationService ccService = getConfigurationService();
-
-    if (ccService != null && results.stream().filter(CliFunctionResult::isSuccessful).count() > 0) {
-      ConnectorService service =
-          ccService.getCustomCacheElement("cluster", "connector-service", ConnectorService.class);
-      if (service == null) {
-        service = new ConnectorService();
-      }
-      service.getRegionMapping().add(mapping);
-      ccService.saveCustomCacheElement("cluster", service);
-      persisted = true;
-    }
 
     CommandResult commandResult = ResultBuilder.buildResult(results);
-    commandResult.setCommandPersisted(persisted);
+    commandResult.setConfigObject(mapping);
     return commandResult;
   }
+
+  @Override
+  public void updateClusterConfig(String group, CacheConfig config, Object element) {
+    ConnectorService.RegionMapping mapping = (ConnectorService.RegionMapping) element;
+    ConnectorService service =
+        config.findCustomCacheElement("connector-service", ConnectorService.class);
+    if (service == null) {
+      service = new ConnectorService();
+      config.getCustomCacheElements().add(service);
+    }
+    service.getRegionMapping().add(mapping);
+  }
 }
diff --git a/geode-connectors/src/main/java/org/apache/geode/connectors/jdbc/internal/cli/DescribeConnectionCommand.java b/geode-connectors/src/main/java/org/apache/geode/connectors/jdbc/internal/cli/DescribeConnectionCommand.java
index 0347c05..267dcc0 100644
--- a/geode-connectors/src/main/java/org/apache/geode/connectors/jdbc/internal/cli/DescribeConnectionCommand.java
+++ b/geode-connectors/src/main/java/org/apache/geode/connectors/jdbc/internal/cli/DescribeConnectionCommand.java
@@ -27,14 +27,15 @@ import org.apache.logging.log4j.Logger;
 import org.springframework.shell.core.annotation.CliCommand;
 import org.springframework.shell.core.annotation.CliOption;
 
+import org.apache.geode.cache.configuration.CacheConfig;
 import org.apache.geode.cache.configuration.CacheElement;
 import org.apache.geode.connectors.jdbc.internal.configuration.ConnectorService;
 import org.apache.geode.distributed.ClusterConfigurationService;
 import org.apache.geode.distributed.DistributedMember;
 import org.apache.geode.internal.logging.LogService;
 import org.apache.geode.management.cli.CliMetaData;
+import org.apache.geode.management.cli.GfshCommand;
 import org.apache.geode.management.cli.Result;
-import org.apache.geode.management.internal.cli.commands.InternalGfshCommand;
 import org.apache.geode.management.internal.cli.exceptions.EntityNotFoundException;
 import org.apache.geode.management.internal.cli.i18n.CliStrings;
 import org.apache.geode.management.internal.cli.result.CompositeResultData;
@@ -43,7 +44,7 @@ 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 DescribeConnectionCommand extends InternalGfshCommand {
+public class DescribeConnectionCommand extends GfshCommand {
   private static Logger logger = LogService.getLogger();
   static final String DESCRIBE_CONNECTION = "describe jdbc-connection";
   static final String DESCRIBE_CONNECTION__HELP = "Describe the specified jdbc connection.";
@@ -65,10 +66,13 @@ public class DescribeConnectionCommand extends InternalGfshCommand {
     // check if CC is available and use it to describe the connection
     ClusterConfigurationService ccService = getConfigurationService();
     if (ccService != null) {
-      ConnectorService service =
-          ccService.getCustomCacheElement("cluster", "connector-service", ConnectorService.class);
-      if (service != null) {
-        connection = CacheElement.findElement(service.getConnection(), name);
+      CacheConfig cacheConfig = ccService.getCacheConfig("cluster");
+      if (cacheConfig != null) {
+        ConnectorService service =
+            cacheConfig.findCustomCacheElement("connector-service", ConnectorService.class);
+        if (service != null) {
+          connection = CacheElement.findElement(service.getConnection(), name);
+        }
       }
     } else {
       // otherwise get it from any member
diff --git a/geode-connectors/src/main/java/org/apache/geode/connectors/jdbc/internal/cli/DescribeMappingCommand.java b/geode-connectors/src/main/java/org/apache/geode/connectors/jdbc/internal/cli/DescribeMappingCommand.java
index aac317e..e73caa4 100644
--- a/geode-connectors/src/main/java/org/apache/geode/connectors/jdbc/internal/cli/DescribeMappingCommand.java
+++ b/geode-connectors/src/main/java/org/apache/geode/connectors/jdbc/internal/cli/DescribeMappingCommand.java
@@ -26,13 +26,14 @@ import java.util.Set;
 import org.springframework.shell.core.annotation.CliCommand;
 import org.springframework.shell.core.annotation.CliOption;
 
+import org.apache.geode.cache.configuration.CacheConfig;
 import org.apache.geode.cache.configuration.CacheElement;
 import org.apache.geode.connectors.jdbc.internal.configuration.ConnectorService;
 import org.apache.geode.distributed.ClusterConfigurationService;
 import org.apache.geode.distributed.DistributedMember;
 import org.apache.geode.management.cli.CliMetaData;
+import org.apache.geode.management.cli.GfshCommand;
 import org.apache.geode.management.cli.Result;
-import org.apache.geode.management.internal.cli.commands.InternalGfshCommand;
 import org.apache.geode.management.internal.cli.exceptions.EntityNotFoundException;
 import org.apache.geode.management.internal.cli.i18n.CliStrings;
 import org.apache.geode.management.internal.cli.result.CompositeResultData;
@@ -41,7 +42,7 @@ 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 DescribeMappingCommand extends InternalGfshCommand {
+public class DescribeMappingCommand extends GfshCommand {
   static final String DESCRIBE_MAPPING = "describe jdbc-mapping";
   static final String DESCRIBE_MAPPING__HELP = "Describe the specified jdbc mapping";
   static final String DESCRIBE_MAPPING__REGION_NAME = "region";
@@ -62,10 +63,13 @@ public class DescribeMappingCommand extends InternalGfshCommand {
     // check if CC is available and use it to describe the connection
     ClusterConfigurationService ccService = getConfigurationService();
     if (ccService != null) {
-      ConnectorService service =
-          ccService.getCustomCacheElement("cluster", "connector-service", ConnectorService.class);
-      if (service != null) {
-        mapping = CacheElement.findElement(service.getRegionMapping(), regionName);
+      CacheConfig cacheConfig = ccService.getCacheConfig("cluster");
+      if (cacheConfig != null) {
+        ConnectorService service =
+            cacheConfig.findCustomCacheElement("connector-service", ConnectorService.class);
+        if (service != null) {
+          mapping = CacheElement.findElement(service.getRegionMapping(), regionName);
+        }
       }
     } else {
       // otherwise get it from any member
diff --git a/geode-connectors/src/main/java/org/apache/geode/connectors/jdbc/internal/cli/DestroyConnectionCommand.java b/geode-connectors/src/main/java/org/apache/geode/connectors/jdbc/internal/cli/DestroyConnectionCommand.java
index 295c625..ff82fa2 100644
--- a/geode-connectors/src/main/java/org/apache/geode/connectors/jdbc/internal/cli/DestroyConnectionCommand.java
+++ b/geode-connectors/src/main/java/org/apache/geode/connectors/jdbc/internal/cli/DestroyConnectionCommand.java
@@ -20,13 +20,13 @@ import java.util.Set;
 import org.springframework.shell.core.annotation.CliCommand;
 import org.springframework.shell.core.annotation.CliOption;
 
+import org.apache.geode.cache.configuration.CacheConfig;
 import org.apache.geode.cache.configuration.CacheElement;
 import org.apache.geode.connectors.jdbc.internal.configuration.ConnectorService;
-import org.apache.geode.distributed.ClusterConfigurationService;
 import org.apache.geode.distributed.DistributedMember;
 import org.apache.geode.management.cli.CliMetaData;
 import org.apache.geode.management.cli.Result;
-import org.apache.geode.management.internal.cli.commands.InternalGfshCommand;
+import org.apache.geode.management.cli.SingleGfshCommand;
 import org.apache.geode.management.internal.cli.functions.CliFunctionResult;
 import org.apache.geode.management.internal.cli.i18n.CliStrings;
 import org.apache.geode.management.internal.cli.result.CommandResult;
@@ -34,7 +34,7 @@ import org.apache.geode.management.internal.cli.result.ResultBuilder;
 import org.apache.geode.management.internal.security.ResourceOperation;
 import org.apache.geode.security.ResourcePermission;
 
-public class DestroyConnectionCommand extends InternalGfshCommand {
+public class DestroyConnectionCommand extends SingleGfshCommand {
   static final String DESTROY_CONNECTION = "destroy jdbc-connection";
   static final String DESTROY_CONNECTION__HELP = "Destroy/Remove the specified jdbc connection.";
   static final String DESTROY_CONNECTION__NAME = "name";
@@ -54,24 +54,17 @@ public class DestroyConnectionCommand extends InternalGfshCommand {
     // action
     List<CliFunctionResult> results =
         executeAndGetFunctionResult(new DestroyConnectionFunction(), name, targetMembers);
-
-    boolean persisted = false;
-    ClusterConfigurationService ccService = getConfigurationService();
-
-    if (ccService != null && results.stream().filter(CliFunctionResult::isSuccessful).count() > 0) {
-      ConnectorService service =
-          ccService.getCustomCacheElement("cluster", "connector-service", ConnectorService.class);
-      if (service != null) {
-        ConnectorService.Connection conn = CacheElement.findElement(service.getConnection(), name);
-        service.getConnection().remove(conn);
-        ccService.saveCustomCacheElement("cluster", service);
-        persisted = true;
-      }
-    }
-
     CommandResult commandResult = ResultBuilder.buildResult(results);
-    commandResult.setCommandPersisted(persisted);
-
+    commandResult.setConfigObject(name);
     return commandResult;
   }
+
+  @Override
+  public void updateClusterConfig(String group, CacheConfig config, Object element) {
+    ConnectorService service =
+        config.findCustomCacheElement("connector-service", ConnectorService.class);
+    if (service != null) {
+      CacheElement.removeElement(service.getConnection(), (String) element);
+    }
+  }
 }
diff --git a/geode-connectors/src/main/java/org/apache/geode/connectors/jdbc/internal/cli/DestroyMappingCommand.java b/geode-connectors/src/main/java/org/apache/geode/connectors/jdbc/internal/cli/DestroyMappingCommand.java
index 8877b78..e2db96d 100644
--- a/geode-connectors/src/main/java/org/apache/geode/connectors/jdbc/internal/cli/DestroyMappingCommand.java
+++ b/geode-connectors/src/main/java/org/apache/geode/connectors/jdbc/internal/cli/DestroyMappingCommand.java
@@ -20,13 +20,13 @@ import java.util.Set;
 import org.springframework.shell.core.annotation.CliCommand;
 import org.springframework.shell.core.annotation.CliOption;
 
+import org.apache.geode.cache.configuration.CacheConfig;
 import org.apache.geode.cache.configuration.CacheElement;
 import org.apache.geode.connectors.jdbc.internal.configuration.ConnectorService;
-import org.apache.geode.distributed.ClusterConfigurationService;
 import org.apache.geode.distributed.DistributedMember;
 import org.apache.geode.management.cli.CliMetaData;
 import org.apache.geode.management.cli.Result;
-import org.apache.geode.management.internal.cli.commands.InternalGfshCommand;
+import org.apache.geode.management.cli.SingleGfshCommand;
 import org.apache.geode.management.internal.cli.functions.CliFunctionResult;
 import org.apache.geode.management.internal.cli.i18n.CliStrings;
 import org.apache.geode.management.internal.cli.result.CommandResult;
@@ -34,7 +34,7 @@ import org.apache.geode.management.internal.cli.result.ResultBuilder;
 import org.apache.geode.management.internal.security.ResourceOperation;
 import org.apache.geode.security.ResourcePermission;
 
-public class DestroyMappingCommand extends InternalGfshCommand {
+public class DestroyMappingCommand extends SingleGfshCommand {
   static final String DESTROY_MAPPING = "destroy jdbc-mapping";
   static final String DESTROY_MAPPING__HELP = "Destroy the specified mapping.";
   static final String DESTROY_MAPPING__REGION_NAME = "region";
@@ -56,23 +56,17 @@ public class DestroyMappingCommand extends InternalGfshCommand {
     List<CliFunctionResult> results =
         executeAndGetFunctionResult(new DestroyMappingFunction(), regionName, targetMembers);
 
-    // output
-    boolean persisted = false;
-    ClusterConfigurationService ccService = getConfigurationService();
-
-    if (ccService != null && results.stream().filter(CliFunctionResult::isSuccessful).count() > 0) {
-      ConnectorService service =
-          ccService.getCustomCacheElement("cluster", "connector-service", ConnectorService.class);
-      if (service != null) {
-        CacheElement.removeElement(service.getRegionMapping(), regionName);
-        ccService.saveCustomCacheElement("cluster", service);
-        persisted = true;
-      }
-    }
-
     CommandResult commandResult = ResultBuilder.buildResult(results);
-    commandResult.setCommandPersisted(persisted);
-
+    commandResult.setConfigObject(regionName);
     return commandResult;
   }
+
+  @Override
+  public void updateClusterConfig(String group, CacheConfig config, Object element) {
+    ConnectorService service =
+        config.findCustomCacheElement("connector-service", ConnectorService.class);
+    if (service != null) {
+      CacheElement.removeElement(service.getRegionMapping(), (String) element);
+    }
+  }
 }
diff --git a/geode-connectors/src/main/java/org/apache/geode/connectors/jdbc/internal/cli/ListConnectionCommand.java b/geode-connectors/src/main/java/org/apache/geode/connectors/jdbc/internal/cli/ListConnectionCommand.java
index 832e309..a9c64ad 100644
--- a/geode-connectors/src/main/java/org/apache/geode/connectors/jdbc/internal/cli/ListConnectionCommand.java
+++ b/geode-connectors/src/main/java/org/apache/geode/connectors/jdbc/internal/cli/ListConnectionCommand.java
@@ -14,18 +14,21 @@
  */
 package org.apache.geode.connectors.jdbc.internal.cli;
 
+import static org.apache.geode.distributed.ClusterConfigurationService.CLUSTER_CONFIG;
+
 import java.util.Collection;
 import java.util.List;
 import java.util.Set;
 
 import org.springframework.shell.core.annotation.CliCommand;
 
+import org.apache.geode.cache.configuration.CacheConfig;
 import org.apache.geode.connectors.jdbc.internal.configuration.ConnectorService;
 import org.apache.geode.distributed.ClusterConfigurationService;
 import org.apache.geode.distributed.DistributedMember;
 import org.apache.geode.management.cli.CliMetaData;
+import org.apache.geode.management.cli.GfshCommand;
 import org.apache.geode.management.cli.Result;
-import org.apache.geode.management.internal.cli.commands.InternalGfshCommand;
 import org.apache.geode.management.internal.cli.i18n.CliStrings;
 import org.apache.geode.management.internal.cli.result.ResultBuilder;
 import org.apache.geode.management.internal.cli.result.TabularResultData;
@@ -33,7 +36,7 @@ import org.apache.geode.management.internal.security.ResourceOperation;
 import org.apache.geode.security.ResourcePermission;
 
 
-public class ListConnectionCommand extends InternalGfshCommand {
+public class ListConnectionCommand extends GfshCommand {
   static final String LIST_JDBC_CONNECTION = "list jdbc-connections";
   static final String LIST_JDBC_CONNECTION__HELP = "Display jdbc connections for all members.";
 
@@ -51,10 +54,13 @@ public class ListConnectionCommand extends InternalGfshCommand {
     // check if CC is available and use it to describe the connection
     ClusterConfigurationService ccService = getConfigurationService();
     if (ccService != null) {
-      ConnectorService service =
-          ccService.getCustomCacheElement("cluster", "connector-service", ConnectorService.class);
-      if (service != null) {
-        connections = service.getConnection();
+      CacheConfig cacheConfig = ccService.getCacheConfig(CLUSTER_CONFIG);
+      if (cacheConfig != null) {
+        ConnectorService service =
+            cacheConfig.findCustomCacheElement("connector-service", ConnectorService.class);
+        if (service != null) {
+          connections = service.getConnection();
+        }
       }
     } else {
       // otherwise get it from any member
diff --git a/geode-connectors/src/main/java/org/apache/geode/connectors/jdbc/internal/cli/ListMappingCommand.java b/geode-connectors/src/main/java/org/apache/geode/connectors/jdbc/internal/cli/ListMappingCommand.java
index c30fcb6..70e0b8a 100644
--- a/geode-connectors/src/main/java/org/apache/geode/connectors/jdbc/internal/cli/ListMappingCommand.java
+++ b/geode-connectors/src/main/java/org/apache/geode/connectors/jdbc/internal/cli/ListMappingCommand.java
@@ -14,18 +14,21 @@
  */
 package org.apache.geode.connectors.jdbc.internal.cli;
 
+import static org.apache.geode.distributed.ClusterConfigurationService.CLUSTER_CONFIG;
+
 import java.util.Collection;
 import java.util.List;
 import java.util.Set;
 
 import org.springframework.shell.core.annotation.CliCommand;
 
+import org.apache.geode.cache.configuration.CacheConfig;
 import org.apache.geode.connectors.jdbc.internal.configuration.ConnectorService;
 import org.apache.geode.distributed.ClusterConfigurationService;
 import org.apache.geode.distributed.DistributedMember;
 import org.apache.geode.management.cli.CliMetaData;
+import org.apache.geode.management.cli.GfshCommand;
 import org.apache.geode.management.cli.Result;
-import org.apache.geode.management.internal.cli.commands.InternalGfshCommand;
 import org.apache.geode.management.internal.cli.i18n.CliStrings;
 import org.apache.geode.management.internal.cli.result.ResultBuilder;
 import org.apache.geode.management.internal.cli.result.TabularResultData;
@@ -33,7 +36,7 @@ import org.apache.geode.management.internal.security.ResourceOperation;
 import org.apache.geode.security.ResourcePermission;
 
 
-public class ListMappingCommand extends InternalGfshCommand {
+public class ListMappingCommand extends GfshCommand {
   static final String LIST_MAPPING = "list jdbc-mappings";
   static final String LIST_MAPPING__HELP = "Display jdbc mappings for all members.";
 
@@ -52,10 +55,13 @@ public class ListMappingCommand extends InternalGfshCommand {
     // check if CC is available and use it to describe the connection
     ClusterConfigurationService ccService = getConfigurationService();
     if (ccService != null) {
-      ConnectorService service =
-          ccService.getCustomCacheElement("cluster", "connector-service", ConnectorService.class);
-      if (service != null) {
-        mappings = service.getRegionMapping();
+      CacheConfig cacheConfig = ccService.getCacheConfig(CLUSTER_CONFIG);
+      if (cacheConfig != null) {
+        ConnectorService service =
+            cacheConfig.findCustomCacheElement("connector-service", ConnectorService.class);
+        if (service != null) {
+          mappings = service.getRegionMapping();
+        }
       }
     } else {
       // otherwise get it from any member
diff --git a/geode-connectors/src/test/java/org/apache/geode/connectors/jdbc/internal/cli/AlterConnectionCommandTest.java b/geode-connectors/src/test/java/org/apache/geode/connectors/jdbc/internal/cli/AlterConnectionCommandTest.java
index fa85ae8..80c96af 100644
--- a/geode-connectors/src/test/java/org/apache/geode/connectors/jdbc/internal/cli/AlterConnectionCommandTest.java
+++ b/geode-connectors/src/test/java/org/apache/geode/connectors/jdbc/internal/cli/AlterConnectionCommandTest.java
@@ -32,6 +32,7 @@ import org.junit.ClassRule;
 import org.junit.Test;
 import org.junit.experimental.categories.Category;
 
+import org.apache.geode.cache.configuration.CacheConfig;
 import org.apache.geode.connectors.jdbc.internal.configuration.ConnectorService;
 import org.apache.geode.distributed.ClusterConfigurationService;
 import org.apache.geode.distributed.internal.InternalClusterConfigurationService;
@@ -50,6 +51,7 @@ public class AlterConnectionCommandTest {
   private ConnectorService.Connection connection;
   private List<ConnectorService.Connection> connections;
   private ConnectorService connectorService;
+  private CacheConfig cacheConfig;
 
   @ClassRule
   public static GfshParserRule gfsh = new GfshParserRule();
@@ -65,6 +67,8 @@ public class AlterConnectionCommandTest {
     when(result.getMemberIdOrName()).thenReturn("memberName");
     when(result.getStatus()).thenReturn("message");
     ccService = mock(InternalClusterConfigurationService.class);
+    cacheConfig = mock(CacheConfig.class);
+    when(ccService.getCacheConfig("cluster")).thenReturn(cacheConfig);
     doReturn(ccService).when(command).getConfigurationService();
     connectorService = mock(ConnectorService.class);
     connections = new ArrayList<>();
@@ -113,7 +117,7 @@ public class AlterConnectionCommandTest {
 
   @Test
   public void whenCCServiceIsRunningAndNoConnectionFound() {
-    when(ccService.getCustomCacheElement(any(), any(), any())).thenReturn(connectorService);
+    when(cacheConfig.findCustomCacheElement(any(), any())).thenReturn(connectorService);
     gfsh.executeAndAssertThat(command, COMMAND).statusIsError()
         .containsOutput("connection with name 'name' does not exist.");
     verify(command, times(0)).executeAndGetFunctionResult(any(), any(), any());
@@ -122,7 +126,7 @@ public class AlterConnectionCommandTest {
   @Test
   public void noSuccessfulResult() {
     // connection found in CC
-    when(ccService.getCustomCacheElement(any(), any(), any())).thenReturn(connectorService);
+    when(cacheConfig.findCustomCacheElement(any(), any())).thenReturn(connectorService);
     when(connectorService.getConnection()).thenReturn(connections);
     connections.add(connection);
     // result is not successful
@@ -136,7 +140,7 @@ public class AlterConnectionCommandTest {
   @Test
   public void successfulResult() {
     // connection found in CC
-    when(ccService.getCustomCacheElement(any(), any(), any())).thenReturn(connectorService);
+    when(cacheConfig.findCustomCacheElement(any(), any())).thenReturn(connectorService);
     when(connectorService.getConnection()).thenReturn(connections);
     connections.add(connection);
 
diff --git a/geode-connectors/src/test/java/org/apache/geode/connectors/jdbc/internal/cli/AlterMappingCommandTest.java b/geode-connectors/src/test/java/org/apache/geode/connectors/jdbc/internal/cli/AlterMappingCommandTest.java
index 8d36497..e83d3d1 100644
--- a/geode-connectors/src/test/java/org/apache/geode/connectors/jdbc/internal/cli/AlterMappingCommandTest.java
+++ b/geode-connectors/src/test/java/org/apache/geode/connectors/jdbc/internal/cli/AlterMappingCommandTest.java
@@ -32,6 +32,7 @@ import org.junit.ClassRule;
 import org.junit.Test;
 import org.junit.experimental.categories.Category;
 
+import org.apache.geode.cache.configuration.CacheConfig;
 import org.apache.geode.connectors.jdbc.internal.configuration.ConnectorService;
 import org.apache.geode.distributed.ClusterConfigurationService;
 import org.apache.geode.distributed.internal.InternalClusterConfigurationService;
@@ -50,6 +51,7 @@ public class AlterMappingCommandTest {
   private ConnectorService.RegionMapping mapping;
   private List<ConnectorService.RegionMapping> mappings;
   private ConnectorService connectorService;
+  private CacheConfig cacheConfig;
 
   @ClassRule
   public static GfshParserRule gfsh = new GfshParserRule();
@@ -66,6 +68,8 @@ public class AlterMappingCommandTest {
     when(result.getStatus()).thenReturn("message");
     ccService = mock(InternalClusterConfigurationService.class);
     doReturn(ccService).when(command).getConfigurationService();
+    cacheConfig = mock(CacheConfig.class);
+    when(ccService.getCacheConfig("cluster")).thenReturn(cacheConfig);
     connectorService = mock(ConnectorService.class);
     mappings = new ArrayList<>();
     mapping = new ConnectorService.RegionMapping();
@@ -121,7 +125,7 @@ public class AlterMappingCommandTest {
   @Test
   public void whenCCServiceIsRunningAndNoMappingFound() {
     ConnectorService connectorService = mock(ConnectorService.class);
-    when(ccService.getCustomCacheElement(any(), any(), any())).thenReturn(connectorService);
+    when(cacheConfig.findCustomCacheElement(any(), any())).thenReturn(connectorService);
     gfsh.executeAndAssertThat(command, COMMAND).statusIsError()
         .containsOutput("mapping with name 'region' does not exist.");
     verify(command, times(0)).executeAndGetFunctionResult(any(), any(), any());
@@ -130,7 +134,7 @@ public class AlterMappingCommandTest {
   @Test
   public void noSuccessfulResult() {
     // mapping found in CC
-    when(ccService.getCustomCacheElement(any(), any(), any())).thenReturn(connectorService);
+    when(cacheConfig.findCustomCacheElement(any(), any())).thenReturn(connectorService);
     when(connectorService.getRegionMapping()).thenReturn(mappings);
     mappings.add(mapping);
     // result is not successful
@@ -144,7 +148,7 @@ public class AlterMappingCommandTest {
   @Test
   public void successfulResult() {
     // mapping found in CC
-    when(ccService.getCustomCacheElement(any(), any(), any())).thenReturn(connectorService);
+    when(cacheConfig.findCustomCacheElement(any(), any())).thenReturn(connectorService);
     when(connectorService.getRegionMapping()).thenReturn(mappings);
     mappings.add(mapping);
 
diff --git a/geode-connectors/src/test/java/org/apache/geode/connectors/jdbc/internal/cli/DescribeConnectionCommandTest.java b/geode-connectors/src/test/java/org/apache/geode/connectors/jdbc/internal/cli/DescribeConnectionCommandTest.java
index a014917..24d2bf5 100644
--- a/geode-connectors/src/test/java/org/apache/geode/connectors/jdbc/internal/cli/DescribeConnectionCommandTest.java
+++ b/geode-connectors/src/test/java/org/apache/geode/connectors/jdbc/internal/cli/DescribeConnectionCommandTest.java
@@ -29,6 +29,7 @@ import org.junit.ClassRule;
 import org.junit.Test;
 import org.junit.experimental.categories.Category;
 
+import org.apache.geode.cache.configuration.CacheConfig;
 import org.apache.geode.cache.execute.ResultCollector;
 import org.apache.geode.connectors.jdbc.internal.configuration.ConnectorService;
 import org.apache.geode.distributed.ClusterConfigurationService;
@@ -42,6 +43,7 @@ public class DescribeConnectionCommandTest {
   public static final String COMMAND = "describe jdbc-connection --name=name";
   private DescribeConnectionCommand command;
   private ClusterConfigurationService ccService;
+  private CacheConfig cacheConfig;
 
   @ClassRule
   public static GfshParserRule gfsh = new GfshParserRule();
@@ -50,6 +52,9 @@ public class DescribeConnectionCommandTest {
   public void setUp() {
     command = spy(DescribeConnectionCommand.class);
     ccService = mock(InternalClusterConfigurationService.class);
+    doReturn(ccService).when(command).getConfigurationService();
+    cacheConfig = mock(CacheConfig.class);
+    when(ccService.getCacheConfig("cluster")).thenReturn(cacheConfig);
   }
 
   @Test
@@ -70,7 +75,7 @@ public class DescribeConnectionCommandTest {
     doReturn(ccService).when(command).getConfigurationService();
 
     ConnectorService connectorService = mock(ConnectorService.class);
-    when(ccService.getCustomCacheElement(any(), any(), any())).thenReturn(connectorService);
+    when(cacheConfig.findCustomCacheElement(any(), any())).thenReturn(connectorService);
     gfsh.executeAndAssertThat(command, COMMAND).statusIsError()
         .containsOutput("connection named 'name' not found");
   }
@@ -86,7 +91,7 @@ public class DescribeConnectionCommandTest {
     connections.add(connection);
 
     ConnectorService connectorService = mock(ConnectorService.class);
-    when(ccService.getCustomCacheElement(any(), any(), any())).thenReturn(connectorService);
+    when(cacheConfig.findCustomCacheElement(any(), any())).thenReturn(connectorService);
     when(connectorService.getConnection()).thenReturn(connections);
 
     gfsh.executeAndAssertThat(command, COMMAND).statusIsSuccess().containsOutput("name", "name")
diff --git a/geode-connectors/src/test/java/org/apache/geode/connectors/jdbc/internal/cli/DescribeMappingCommandTest.java b/geode-connectors/src/test/java/org/apache/geode/connectors/jdbc/internal/cli/DescribeMappingCommandTest.java
index 18b68a8..578f2ab 100644
--- a/geode-connectors/src/test/java/org/apache/geode/connectors/jdbc/internal/cli/DescribeMappingCommandTest.java
+++ b/geode-connectors/src/test/java/org/apache/geode/connectors/jdbc/internal/cli/DescribeMappingCommandTest.java
@@ -29,6 +29,7 @@ import org.junit.ClassRule;
 import org.junit.Test;
 import org.junit.experimental.categories.Category;
 
+import org.apache.geode.cache.configuration.CacheConfig;
 import org.apache.geode.cache.execute.ResultCollector;
 import org.apache.geode.connectors.jdbc.internal.configuration.ConnectorService;
 import org.apache.geode.distributed.ClusterConfigurationService;
@@ -43,6 +44,7 @@ public class DescribeMappingCommandTest {
   public static final String COMMAND = "describe jdbc-mapping --region=region ";
   private DescribeMappingCommand command;
   private ClusterConfigurationService ccService;
+  private CacheConfig cacheConfig;
 
   @ClassRule
   public static GfshParserRule gfsh = new GfshParserRule();
@@ -51,6 +53,9 @@ public class DescribeMappingCommandTest {
   public void setUp() {
     command = spy(DescribeMappingCommand.class);
     ccService = mock(InternalClusterConfigurationService.class);
+    doReturn(ccService).when(command).getConfigurationService();
+    cacheConfig = mock(CacheConfig.class);
+    when(ccService.getCacheConfig("cluster")).thenReturn(cacheConfig);
   }
 
   @Test
@@ -71,7 +76,7 @@ public class DescribeMappingCommandTest {
     doReturn(ccService).when(command).getConfigurationService();
 
     ConnectorService connectorService = mock(ConnectorService.class);
-    when(ccService.getCustomCacheElement(any(), any(), any())).thenReturn(connectorService);
+    when(cacheConfig.findCustomCacheElement(any(), any())).thenReturn(connectorService);
     gfsh.executeAndAssertThat(command, COMMAND).statusIsError()
         .containsOutput("mapping for region 'region' not found");
   }
@@ -92,7 +97,7 @@ public class DescribeMappingCommandTest {
     List<ConnectorService.RegionMapping> mappings = new ArrayList<>();
     when(connectorService.getRegionMapping()).thenReturn(mappings);
     mappings.add(mapping);
-    when(ccService.getCustomCacheElement(any(), any(), any())).thenReturn(connectorService);
+    when(cacheConfig.findCustomCacheElement(any(), any())).thenReturn(connectorService);
 
     gfsh.executeAndAssertThat(command, COMMAND).statusIsSuccess().containsOutput("region", "region")
         .containsOutput("connection", "name1").containsOutput("table", "table1")
diff --git a/geode-connectors/src/test/java/org/apache/geode/connectors/jdbc/internal/cli/JdbcClusterConfigDistributedTest.java b/geode-connectors/src/test/java/org/apache/geode/connectors/jdbc/internal/cli/JdbcClusterConfigDistributedTest.java
index 64ca86a..4fc6474 100644
--- a/geode-connectors/src/test/java/org/apache/geode/connectors/jdbc/internal/cli/JdbcClusterConfigDistributedTest.java
+++ b/geode-connectors/src/test/java/org/apache/geode/connectors/jdbc/internal/cli/JdbcClusterConfigDistributedTest.java
@@ -14,135 +14,73 @@
  */
 package org.apache.geode.connectors.jdbc.internal.cli;
 
-import static java.util.concurrent.TimeUnit.MINUTES;
-import static org.apache.geode.distributed.ConfigurationProperties.LOCATORS;
-import static org.apache.geode.test.dunit.Disconnect.disconnectAllFromDS;
-import static org.apache.geode.test.dunit.VM.getHostName;
-import static org.apache.geode.test.dunit.VM.getVM;
 import static org.assertj.core.api.Assertions.assertThat;
-import static org.awaitility.Awaitility.await;
-import static org.junit.Assert.assertTrue;
 import static org.mockito.Mockito.mock;
 
-import java.io.Serializable;
-import java.util.Properties;
-
-import org.junit.After;
-import org.junit.Before;
+import org.junit.BeforeClass;
 import org.junit.ClassRule;
 import org.junit.Rule;
 import org.junit.Test;
 import org.junit.experimental.categories.Category;
 
-import org.apache.geode.cache.CacheFactory;
 import org.apache.geode.connectors.jdbc.internal.JdbcConnectorService;
 import org.apache.geode.connectors.jdbc.internal.TableMetaDataView;
 import org.apache.geode.connectors.jdbc.internal.configuration.ConnectorService;
-import org.apache.geode.distributed.Locator;
-import org.apache.geode.distributed.internal.InternalLocator;
-import org.apache.geode.internal.cache.InternalCache;
-import org.apache.geode.management.cli.Result;
-import org.apache.geode.test.dunit.VM;
-import org.apache.geode.test.dunit.rules.DistributedRestoreSystemProperties;
-import org.apache.geode.test.dunit.rules.DistributedTestRule;
+import org.apache.geode.test.dunit.rules.ClusterStartupRule;
+import org.apache.geode.test.dunit.rules.MemberVM;
 import org.apache.geode.test.junit.categories.DistributedTest;
-import org.apache.geode.test.junit.rules.serializable.SerializableTemporaryFolder;
-import org.apache.geode.test.junit.rules.serializable.SerializableTestName;
+import org.apache.geode.test.junit.rules.GfshCommandRule;
 
 @Category(DistributedTest.class)
 @SuppressWarnings("serial")
-public class JdbcClusterConfigDistributedTest implements Serializable {
-
-  private transient InternalCache cache;
-  private transient VM locator;
-
-  private String regionName;
-  private String connectionName;
-  private String connectionUrl;
-  private String tableName;
-  private String pdxClass;
-  private String locators;
-  private String[] fieldMappings;
-  private boolean keyInValue;
+public class JdbcClusterConfigDistributedTest {
 
+  private static MemberVM locator, server;
   @ClassRule
-  public static DistributedTestRule distributedTestRule = new DistributedTestRule();
-
-  @Rule
-  public DistributedRestoreSystemProperties restoreSystemProperties =
-      new DistributedRestoreSystemProperties();
+  public static ClusterStartupRule cluster = new ClusterStartupRule();
 
   @Rule
-  public SerializableTemporaryFolder temporaryFolder = new SerializableTemporaryFolder();
+  public GfshCommandRule gfsh = new GfshCommandRule();
 
-  @Rule
-  public SerializableTestName testName = new SerializableTestName();
-
-  @Before
-  public void setUp() {
-    regionName = "regionName";
-    connectionName = "connection";
-    connectionUrl = "url";
-    tableName = "testTable";
-    pdxClass = "myPdxClass";
-    keyInValue = true;
-    fieldMappings = new String[] {"field1:column1", "field2:column2"};
-
-    locator = getVM(0);
-    String locatorFolder = "vm-" + locator.getId() + "-" + testName.getMethodName();
+  @BeforeClass
+  public static void beforeClass() {
+    locator = cluster.startLocatorVM(0);
+    server = cluster.startServerVM(1, locator.getPort());
+  }
 
-    int port = locator.invoke(() -> {
-      System.setProperty("user.dir", temporaryFolder.newFolder(locatorFolder).getAbsolutePath());
-      Properties config = new Properties();
-      config.setProperty(LOCATORS, "");
-      InternalLocator locator = (InternalLocator) Locator.startLocatorAndDS(0, null, config);
-      await().atMost(2, MINUTES).until(() -> assertTrue(locator.isSharedConfigurationRunning()));
-      return Locator.getLocator().getPort();
+  @Test
+  public void recreateCacheFromClusterConfig() throws Exception {
+    gfsh.connectAndVerify(locator);
+    gfsh.executeAndAssertThat("create jdbc-connection --name=connection --url=url")
+        .statusIsSuccess();
+    gfsh.executeAndAssertThat(
+        "create jdbc-mapping --region=regionName --connection=connection --table=testTable --pdx-class-name=myPdxClass --value-contains-primary-key --field-mapping=field1:column1,field2:column2")
+        .statusIsSuccess();
+
+    server.invoke(() -> {
+      JdbcConnectorService service =
+          ClusterStartupRule.getCache().getService(JdbcConnectorService.class);
+      validateRegionMapping(service.getMappingForRegion("regionName"));
     });
-    locators = getHostName() + "[" + port + "]";
 
-    cache = (InternalCache) new CacheFactory().set(LOCATORS, locators).create();
+    server.stopVM(false);
 
-    locator.invoke(() -> {
-      CreateConnectionCommand command = new CreateConnectionCommand();
-      command.setCache(CacheFactory.getAnyInstance());
-      Result result = command.createConnection(connectionName, connectionUrl, null, null, null);
-      assertThat(result.getStatus()).isSameAs(Result.Status.OK);
-      CreateMappingCommand mappingCommand = new CreateMappingCommand();
-      mappingCommand.setCache(CacheFactory.getAnyInstance());
-      result = mappingCommand.createMapping(regionName, connectionName, tableName, pdxClass,
-          keyInValue, fieldMappings);
-
-      assertThat(result.getStatus()).isSameAs(Result.Status.OK);
+    server = cluster.startServerVM(1, locator.getPort());
+    server.invoke(() -> {
+      JdbcConnectorService service =
+          ClusterStartupRule.getCache().getService(JdbcConnectorService.class);
+      assertThat(service.getConnectionConfig("connection")).isNotNull();
+      validateRegionMapping(service.getMappingForRegion("regionName"));
     });
-
-    JdbcConnectorService service = cache.getService(JdbcConnectorService.class);
-    validateRegionMapping(service.getMappingForRegion(regionName));
-
-    cache.close();
-  }
-
-  @After
-  public void tearDown() {
-    disconnectAllFromDS();
-  }
-
-  @Test
-  public void recreatesCacheFromClusterConfig() {
-    cache = (InternalCache) new CacheFactory().set(LOCATORS, locators).create();
-
-    JdbcConnectorService service = cache.getService(JdbcConnectorService.class);
-    assertThat(service.getConnectionConfig(connectionName)).isNotNull();
-    validateRegionMapping(service.getMappingForRegion(regionName));
   }
 
-  private void validateRegionMapping(ConnectorService.RegionMapping regionMapping) {
+  private static void validateRegionMapping(ConnectorService.RegionMapping regionMapping) {
     assertThat(regionMapping).isNotNull();
-    assertThat(regionMapping.getRegionName()).isEqualTo(regionName);
-    assertThat(regionMapping.getConnectionConfigName()).isEqualTo(connectionName);
-    assertThat(regionMapping.getTableName()).isEqualTo(tableName);
-    assertThat(regionMapping.getPdxClassName()).isEqualTo(pdxClass);
-    assertThat(regionMapping.isPrimaryKeyInValue()).isEqualTo(keyInValue);
+    assertThat(regionMapping.getRegionName()).isEqualTo("regionName");
+    assertThat(regionMapping.getConnectionConfigName()).isEqualTo("connection");
+    assertThat(regionMapping.getTableName()).isEqualTo("testTable");
+    assertThat(regionMapping.getPdxClassName()).isEqualTo("myPdxClass");
+    assertThat(regionMapping.isPrimaryKeyInValue()).isEqualTo(true);
     assertThat(regionMapping.getColumnNameForField("field1", mock(TableMetaDataView.class)))
         .isEqualTo("column1");
     assertThat(regionMapping.getColumnNameForField("field2", mock(TableMetaDataView.class)))
diff --git a/geode-connectors/src/test/java/org/apache/geode/connectors/jdbc/internal/cli/ListConnectionCommandTest.java b/geode-connectors/src/test/java/org/apache/geode/connectors/jdbc/internal/cli/ListConnectionCommandTest.java
index 4018ec8..f5dc088 100644
--- a/geode-connectors/src/test/java/org/apache/geode/connectors/jdbc/internal/cli/ListConnectionCommandTest.java
+++ b/geode-connectors/src/test/java/org/apache/geode/connectors/jdbc/internal/cli/ListConnectionCommandTest.java
@@ -29,6 +29,7 @@ import org.junit.ClassRule;
 import org.junit.Test;
 import org.junit.experimental.categories.Category;
 
+import org.apache.geode.cache.configuration.CacheConfig;
 import org.apache.geode.cache.execute.ResultCollector;
 import org.apache.geode.connectors.jdbc.internal.configuration.ConnectorService;
 import org.apache.geode.distributed.ClusterConfigurationService;
@@ -43,6 +44,7 @@ public class ListConnectionCommandTest {
   public static final String COMMAND = "list jdbc-connections ";
   private ListConnectionCommand command;
   private ClusterConfigurationService ccService;
+  private CacheConfig cacheConfig;
 
   @ClassRule
   public static GfshParserRule gfsh = new GfshParserRule();
@@ -51,6 +53,17 @@ public class ListConnectionCommandTest {
   public void setUp() {
     command = spy(ListConnectionCommand.class);
     ccService = mock(InternalClusterConfigurationService.class);
+    doReturn(ccService).when(command).getConfigurationService();
+    cacheConfig = mock(CacheConfig.class);
+    when(ccService.getCacheConfig("cluster")).thenReturn(cacheConfig);
+  }
+
+  @Test
+  public void whenCCServiceIsNotAvailable() {
+    doReturn(null).when(command).getConfigurationService();
+    doReturn(Collections.emptySet()).when(command).findMembers(any(), any());
+    gfsh.executeAndAssertThat(command, COMMAND).statusIsSuccess()
+        .containsOutput("No connections found");
   }
 
   @Test
@@ -65,7 +78,7 @@ public class ListConnectionCommandTest {
     doReturn(ccService).when(command).getConfigurationService();
 
     ConnectorService connectorService = mock(ConnectorService.class);
-    when(ccService.getCustomCacheElement(any(), any(), any())).thenReturn(connectorService);
+    when(cacheConfig.findCustomCacheElement(any(), any())).thenReturn(connectorService);
     gfsh.executeAndAssertThat(command, COMMAND).statusIsSuccess()
         .containsOutput("No connections found");
   }
@@ -87,7 +100,7 @@ public class ListConnectionCommandTest {
     connectorService.getConnection().add(connection2);
     connectorService.getConnection().add(connection3);
 
-    when(ccService.getCustomCacheElement(any(), any(), any())).thenReturn(connectorService);
+    when(cacheConfig.findCustomCacheElement(any(), any())).thenReturn(connectorService);
 
     gfsh.executeAndAssertThat(command, COMMAND).statusIsSuccess().containsOutput("name1", "name2",
         "name3");
diff --git a/geode-connectors/src/test/java/org/apache/geode/connectors/jdbc/internal/cli/ListMappingCommandTest.java b/geode-connectors/src/test/java/org/apache/geode/connectors/jdbc/internal/cli/ListMappingCommandTest.java
index c31e2f3..8421d78 100644
--- a/geode-connectors/src/test/java/org/apache/geode/connectors/jdbc/internal/cli/ListMappingCommandTest.java
+++ b/geode-connectors/src/test/java/org/apache/geode/connectors/jdbc/internal/cli/ListMappingCommandTest.java
@@ -29,6 +29,7 @@ import org.junit.ClassRule;
 import org.junit.Test;
 import org.junit.experimental.categories.Category;
 
+import org.apache.geode.cache.configuration.CacheConfig;
 import org.apache.geode.cache.execute.ResultCollector;
 import org.apache.geode.connectors.jdbc.internal.configuration.ConnectorService;
 import org.apache.geode.distributed.ClusterConfigurationService;
@@ -43,6 +44,7 @@ public class ListMappingCommandTest {
   public static final String COMMAND = "list jdbc-mappings";
   private ListMappingCommand command;
   private ClusterConfigurationService ccService;
+  private CacheConfig cacheConfig;
 
   @ClassRule
   public static GfshParserRule gfsh = new GfshParserRule();
@@ -51,6 +53,17 @@ public class ListMappingCommandTest {
   public void setUp() {
     command = spy(ListMappingCommand.class);
     ccService = mock(InternalClusterConfigurationService.class);
+    doReturn(ccService).when(command).getConfigurationService();
+    cacheConfig = mock(CacheConfig.class);
+    when(ccService.getCacheConfig("cluster")).thenReturn(cacheConfig);
+  }
+
+  @Test
+  public void whenCCServiceIsNotAvailable() {
+    doReturn(null).when(command).getConfigurationService();
+    doReturn(Collections.emptySet()).when(command).findMembers(any(), any());
+    gfsh.executeAndAssertThat(command, COMMAND).statusIsSuccess()
+        .containsOutput("No mappings found");
   }
 
   @Test
@@ -65,7 +78,7 @@ public class ListMappingCommandTest {
     doReturn(ccService).when(command).getConfigurationService();
 
     ConnectorService connectorService = mock(ConnectorService.class);
-    when(ccService.getCustomCacheElement(any(), any(), any())).thenReturn(connectorService);
+    when(cacheConfig.findCustomCacheElement(any(), any())).thenReturn(connectorService);
     gfsh.executeAndAssertThat(command, COMMAND).statusIsSuccess()
         .containsOutput("No mappings found");
   }
@@ -88,7 +101,7 @@ public class ListMappingCommandTest {
     connectorService.getRegionMapping().add(mapping1);
     connectorService.getRegionMapping().add(mapping2);
 
-    when(ccService.getCustomCacheElement(any(), any(), any())).thenReturn(connectorService);
+    when(cacheConfig.findCustomCacheElement(any(), any())).thenReturn(connectorService);
 
     gfsh.executeAndAssertThat(command, COMMAND).statusIsSuccess().containsOutput("region1",
         "region2");
diff --git a/geode-core/src/main/java/org/apache/geode/cache/configuration/CacheConfig.java b/geode-core/src/main/java/org/apache/geode/cache/configuration/CacheConfig.java
index 49ac6e8..16db02d 100644
--- a/geode-core/src/main/java/org/apache/geode/cache/configuration/CacheConfig.java
+++ b/geode-core/src/main/java/org/apache/geode/cache/configuration/CacheConfig.java
@@ -18,6 +18,8 @@
 
 package org.apache.geode.cache.configuration;
 
+import static org.apache.geode.cache.configuration.CacheElement.findElement;
+
 import java.math.BigInteger;
 import java.util.ArrayList;
 import java.util.List;
@@ -35,6 +37,7 @@ import javax.xml.bind.annotation.adapters.XmlJavaTypeAdapter;
 import org.w3c.dom.Element;
 
 import org.apache.geode.annotations.Experimental;
+import org.apache.geode.cache.Region;
 
 
 /**
@@ -1022,6 +1025,50 @@ public class CacheConfig {
     this.version = value;
   }
 
+  public RegionConfig findRegionConfiguration(String regionPath) {
+    if (regionPath.startsWith(Region.SEPARATOR)) {
+      regionPath = regionPath.substring(1);
+    }
+    return findElement(getRegion(), regionPath);
+  }
+
+  public <T extends CacheElement> List<T> findCustomCacheElements(Class<T> classT) {
+    List<T> newList = new ArrayList<>();
+    // streaming won't work here, because it's trying to cast element into CacheElement
+    for (Object element : getCustomCacheElements()) {
+      if (classT.isInstance(element)) {
+        newList.add(classT.cast(element));
+      }
+    }
+    return newList;
+  }
+
+  public <T extends CacheElement> T findCustomCacheElement(String elementId, Class<T> classT) {
+    return findElement(findCustomCacheElements(classT), elementId);
+  }
+
+  public <T extends CacheElement> List<T> findCustomRegionElements(String regionPath,
+      Class<T> classT) {
+    List<T> newList = new ArrayList<>();
+    RegionConfig regionConfig = findRegionConfiguration(regionPath);
+    if (regionConfig == null) {
+      return newList;
+    }
+
+    // streaming won't work here, because it's trying to cast element into CacheElement
+    for (Object element : regionConfig.getCustomRegionElements()) {
+      if (classT.isInstance(element)) {
+        newList.add(classT.cast(element));
+      }
+    }
+    return newList;
+  }
+
+  public <T extends CacheElement> T findCustomRegionElement(String regionPath, String elementId,
+      Class<T> classT) {
+    return findElement(findCustomRegionElements(regionPath, classT), elementId);
+  }
+
   /**
    * <p>
    * Java class for anonymous complex type.
diff --git a/geode-core/src/main/java/org/apache/geode/cache/configuration/CacheElement.java b/geode-core/src/main/java/org/apache/geode/cache/configuration/CacheElement.java
index e0f1777..c52cdc6 100644
--- a/geode-core/src/main/java/org/apache/geode/cache/configuration/CacheElement.java
+++ b/geode-core/src/main/java/org/apache/geode/cache/configuration/CacheElement.java
@@ -18,7 +18,6 @@
 package org.apache.geode.cache.configuration;
 
 import java.io.Serializable;
-import java.util.ArrayList;
 import java.util.List;
 
 import org.apache.geode.annotations.Experimental;
@@ -34,47 +33,4 @@ public interface CacheElement extends Identifiable<String>, Serializable {
   static <T extends CacheElement> void removeElement(List<T> list, String id) {
     list.removeIf(t -> t.getId().equals(id));
   }
-
-  static RegionConfig findRegionConfiguration(CacheConfig cacheConfig, String regionPath) {
-    return findElement(cacheConfig.getRegion(), regionPath);
-  }
-
-  static <T extends CacheElement> List<T> findCustomCacheElements(CacheConfig cacheConfig,
-      Class<T> classT) {
-    List<T> newList = new ArrayList<>();
-    // streaming won't work here, because it's trying to cast element into CacheElement
-    for (Object element : cacheConfig.getCustomCacheElements()) {
-      if (classT.isInstance(element)) {
-        newList.add(classT.cast(element));
-      }
-    }
-    return newList;
-  }
-
-  static <T extends CacheElement> T findCustomCacheElement(CacheConfig cacheConfig,
-      String elementId, Class<T> classT) {
-    return findElement(findCustomCacheElements(cacheConfig, classT), elementId);
-  }
-
-  static <T extends CacheElement> List<T> findCustomRegionElements(CacheConfig cacheConfig,
-      String regionPath, Class<T> classT) {
-    List<T> newList = new ArrayList<>();
-    RegionConfig regionConfig = findRegionConfiguration(cacheConfig, regionPath);
-    if (regionConfig == null) {
-      return newList;
-    }
-
-    // streaming won't work here, because it's trying to cast element into CacheElement
-    for (Object element : regionConfig.getCustomRegionElements()) {
-      if (classT.isInstance(element)) {
-        newList.add(classT.cast(element));
-      }
-    }
-    return newList;
-  }
-
-  static <T extends CacheElement> T findCustomRegionElement(CacheConfig cacheConfig,
-      String regionPath, String elementId, Class<T> classT) {
-    return findElement(findCustomRegionElements(cacheConfig, regionPath, classT), elementId);
-  }
 }
diff --git a/geode-core/src/main/java/org/apache/geode/cache/configuration/RegionConfig.java b/geode-core/src/main/java/org/apache/geode/cache/configuration/RegionConfig.java
index 8af552b..629012a 100644
--- a/geode-core/src/main/java/org/apache/geode/cache/configuration/RegionConfig.java
+++ b/geode-core/src/main/java/org/apache/geode/cache/configuration/RegionConfig.java
@@ -167,6 +167,13 @@ public class RegionConfig implements CacheElement {
   @XmlAttribute(name = "refid")
   protected String refid;
 
+  public RegionConfig() {}
+
+  public RegionConfig(String name, String refid) {
+    this.name = name;
+    this.refid = refid;
+  }
+
   /**
    * Gets the value of the regionAttributes property.
    *
@@ -678,13 +685,7 @@ public class RegionConfig implements CacheElement {
    *
    */
   @XmlAccessorType(XmlAccessType.FIELD)
-  @XmlType(name = "", propOrder = {"functional", "primaryKey"})
-  public static class Index {
-
-    @XmlElement(namespace = "http://geode.apache.org/schema/cache")
-    protected RegionConfig.Index.Functional functional;
-    @XmlElement(name = "primary-key", namespace = "http://geode.apache.org/schema/cache")
-    protected RegionConfig.Index.PrimaryKey primaryKey;
+  public static class Index implements CacheElement {
     @XmlAttribute(name = "name", required = true)
     protected String name;
     @XmlAttribute(name = "expression")
@@ -696,51 +697,7 @@ public class RegionConfig implements CacheElement {
     @XmlAttribute(name = "key-index")
     protected Boolean keyIndex;
     @XmlAttribute(name = "type")
-    protected String type;
-
-    /**
-     * Gets the value of the functional property.
-     *
-     * possible object is
-     * {@link RegionConfig.Index.Functional }
-     *
-     */
-    public RegionConfig.Index.Functional getFunctional() {
-      return functional;
-    }
-
-    /**
-     * Sets the value of the functional property.
-     *
-     * allowed object is
-     * {@link RegionConfig.Index.Functional }
-     *
-     */
-    public void setFunctional(RegionConfig.Index.Functional value) {
-      this.functional = value;
-    }
-
-    /**
-     * Gets the value of the primaryKey property.
-     *
-     * possible object is
-     * {@link RegionConfig.Index.PrimaryKey }
-     *
-     */
-    public RegionConfig.Index.PrimaryKey getPrimaryKey() {
-      return primaryKey;
-    }
-
-    /**
-     * Sets the value of the primaryKey property.
-     *
-     * allowed object is
-     * {@link RegionConfig.Index.PrimaryKey }
-     *
-     */
-    public void setPrimaryKey(RegionConfig.Index.PrimaryKey value) {
-      this.primaryKey = value;
-    }
+    protected String type; // for non-key index type, range or hash
 
     /**
      * Gets the value of the name property.
@@ -875,161 +832,17 @@ public class RegionConfig implements CacheElement {
      *
      */
     public void setType(String value) {
-      this.type = value;
-    }
-
-
-    /**
-     * <p>
-     * Java class for anonymous complex type.
-     *
-     * <p>
-     * The following schema fragment specifies the expected content contained within this class.
-     *
-     * <pre>
-     * &lt;complexType>
-     *   &lt;complexContent>
-     *     &lt;restriction base="{http://www.w3.org/2001/XMLSchema}anyType">
-     *       &lt;attribute name="expression" use="required" type="{http://www.w3.org/2001/XMLSchema}string" />
-     *       &lt;attribute name="from-clause" use="required" type="{http://www.w3.org/2001/XMLSchema}string" />
-     *       &lt;attribute name="imports" type="{http://www.w3.org/2001/XMLSchema}string" />
-     *     &lt;/restriction>
-     *   &lt;/complexContent>
-     * &lt;/complexType>
-     * </pre>
-     *
-     *
-     */
-    @XmlAccessorType(XmlAccessType.FIELD)
-    @XmlType(name = "")
-    public static class Functional {
-
-      @XmlAttribute(name = "expression", required = true)
-      protected String expression;
-      @XmlAttribute(name = "from-clause", required = true)
-      protected String fromClause;
-      @XmlAttribute(name = "imports")
-      protected String imports;
-
-      /**
-       * Gets the value of the expression property.
-       *
-       * possible object is
-       * {@link String }
-       *
-       */
-      public String getExpression() {
-        return expression;
-      }
-
-      /**
-       * Sets the value of the expression property.
-       *
-       * allowed object is
-       * {@link String }
-       *
-       */
-      public void setExpression(String value) {
-        this.expression = value;
-      }
-
-      /**
-       * Gets the value of the fromClause property.
-       *
-       * possible object is
-       * {@link String }
-       *
-       */
-      public String getFromClause() {
-        return fromClause;
-      }
-
-      /**
-       * Sets the value of the fromClause property.
-       *
-       * allowed object is
-       * {@link String }
-       *
-       */
-      public void setFromClause(String value) {
-        this.fromClause = value;
-      }
-
-      /**
-       * Gets the value of the imports property.
-       *
-       * possible object is
-       * {@link String }
-       *
-       */
-      public String getImports() {
-        return imports;
-      }
-
-      /**
-       * Sets the value of the imports property.
-       *
-       * allowed object is
-       * {@link String }
-       *
-       */
-      public void setImports(String value) {
-        this.imports = value;
+      if ("range".equalsIgnoreCase(value) || "hash".equalsIgnoreCase(value)) {
+        this.type = value.toLowerCase();
+      } else {
+        throw new IllegalArgumentException("Invalid index type " + value);
       }
-
     }
 
-
-    /**
-     * <p>
-     * Java class for anonymous complex type.
-     *
-     * <p>
-     * The following schema fragment specifies the expected content contained within this class.
-     *
-     * <pre>
-     * &lt;complexType>
-     *   &lt;complexContent>
-     *     &lt;restriction base="{http://www.w3.org/2001/XMLSchema}anyType">
-     *       &lt;attribute name="field" use="required" type="{http://www.w3.org/2001/XMLSchema}string" />
-     *     &lt;/restriction>
-     *   &lt;/complexContent>
-     * &lt;/complexType>
-     * </pre>
-     *
-     *
-     */
-    @XmlAccessorType(XmlAccessType.FIELD)
-    @XmlType(name = "")
-    public static class PrimaryKey {
-
-      @XmlAttribute(name = "field", required = true)
-      protected String field;
-
-      /**
-       * Gets the value of the field property.
-       *
-       * possible object is
-       * {@link String }
-       *
-       */
-      public String getField() {
-        return field;
-      }
-
-      /**
-       * Sets the value of the field property.
-       *
-       * allowed object is
-       * {@link String }
-       *
-       */
-      public void setField(String value) {
-        this.field = value;
-      }
-
+    @Override
+    public String getId() {
+      return getName();
     }
-
   }
 
 }
diff --git a/geode-core/src/main/java/org/apache/geode/distributed/ClusterConfigurationService.java b/geode-core/src/main/java/org/apache/geode/distributed/ClusterConfigurationService.java
index 8cf9b84..61aeb7d 100644
--- a/geode-core/src/main/java/org/apache/geode/distributed/ClusterConfigurationService.java
+++ b/geode-core/src/main/java/org/apache/geode/distributed/ClusterConfigurationService.java
@@ -17,20 +17,15 @@
 
 package org.apache.geode.distributed;
 
-import static org.apache.geode.cache.configuration.CacheElement.findCustomCacheElement;
-import static org.apache.geode.cache.configuration.CacheElement.findCustomRegionElement;
-import static org.apache.geode.cache.configuration.CacheElement.findRegionConfiguration;
-
 import java.util.function.UnaryOperator;
 
 import org.apache.geode.annotations.Experimental;
 import org.apache.geode.cache.configuration.CacheConfig;
-import org.apache.geode.cache.configuration.CacheElement;
-import org.apache.geode.cache.configuration.RegionConfig;
-import org.apache.geode.management.internal.cli.exceptions.EntityNotFoundException;
 
 @Experimental
 public interface ClusterConfigurationService {
+  String CLUSTER_CONFIG = "cluster";
+
   /**
    * retrieves the configuration object of a member group
    *
@@ -46,83 +41,4 @@ public interface ClusterConfigurationService {
    * @param mutator the change you want to apply to the configuration
    */
   void updateCacheConfig(String group, UnaryOperator<CacheConfig> mutator);
-
-
-  default <T extends CacheElement> T getCustomCacheElement(String group, String id,
-      Class<T> classT) {
-    CacheConfig cacheConfig = getCacheConfig(group);
-    if (cacheConfig == null) {
-      return null;
-    }
-    return findCustomCacheElement(cacheConfig, id, classT);
-  }
-
-  default void saveCustomCacheElement(String group, CacheElement element) {
-    updateCacheConfig(group, cacheConfig -> {
-      CacheElement foundElement =
-          findCustomCacheElement(cacheConfig, element.getId(), element.getClass());
-      if (foundElement != null) {
-        cacheConfig.getCustomCacheElements().remove(foundElement);
-      }
-      cacheConfig.getCustomCacheElements().add(element);
-      return cacheConfig;
-    });
-  }
-
-  default void deleteCustomCacheElement(String group, String id,
-      Class<? extends CacheElement> classT) {
-    updateCacheConfig(group, config -> {
-      CacheElement cacheElement = findCustomCacheElement(config, id, classT);
-      if (cacheElement == null) {
-        return null;
-      }
-      config.getCustomCacheElements().remove(cacheElement);
-      return config;
-    });
-  }
-
-  default <T extends CacheElement> T getCustomRegionElement(String group, String regionPath,
-      String id, Class<T> classT) {
-    CacheConfig cacheConfig = getCacheConfig(group);
-    return findCustomRegionElement(cacheConfig, regionPath, id, classT);
-  }
-
-  default void saveCustomRegionElement(String group, String regionPath, CacheElement element) {
-    updateCacheConfig(group, cacheConfig -> {
-      RegionConfig regionConfig = findRegionConfiguration(cacheConfig, regionPath);
-      if (regionConfig == null) {
-        throw new EntityNotFoundException(
-            String.format("region %s does not exist in group %s", regionPath, group));
-      }
-
-      CacheElement oldElement =
-          findCustomRegionElement(cacheConfig, regionPath, element.getId(), element.getClass());
-
-      if (oldElement != null) {
-        regionConfig.getCustomRegionElements().remove(oldElement);
-      }
-      regionConfig.getCustomRegionElements().add(element);
-      return cacheConfig;
-    });
-  }
-
-  default void deleteCustomRegionElement(String group, String regionPath, String id,
-      Class<? extends CacheElement> classT) {
-    updateCacheConfig(group, cacheConfig -> {
-      RegionConfig regionConfig = findRegionConfiguration(cacheConfig, regionPath);
-      if (regionConfig == null) {
-        throw new EntityNotFoundException(
-            String.format("region %s does not exist in group %s", regionPath, group));
-      }
-      CacheElement element = findCustomRegionElement(cacheConfig, regionPath, id, classT);
-      if (element == null) {
-        return null;
-      }
-      regionConfig.getCustomRegionElements().remove(element);
-      return cacheConfig;
-    });
-  }
-
-
-
 }
diff --git a/geode-core/src/main/java/org/apache/geode/distributed/internal/InternalClusterConfigurationService.java b/geode-core/src/main/java/org/apache/geode/distributed/internal/InternalClusterConfigurationService.java
index 7af4e0f..02b5a68 100644
--- a/geode-core/src/main/java/org/apache/geode/distributed/internal/InternalClusterConfigurationService.java
+++ b/geode-core/src/main/java/org/apache/geode/distributed/internal/InternalClusterConfigurationService.java
@@ -114,8 +114,6 @@ public class InternalClusterConfigurationService implements ClusterConfiguration
 
   public static final String CLUSTER_CONFIG_DISK_DIR_PREFIX = "ConfigDiskDir_";
 
-  public static final String CLUSTER_CONFIG = "cluster";
-
   /**
    * Name of the lock service used for shared configuration
    */
@@ -237,7 +235,7 @@ public class InternalClusterConfigurationService implements ClusterConfiguration
     try {
       Region<String, Configuration> configRegion = getConfigurationRegion();
       if (groups == null || groups.length == 0) {
-        groups = new String[] {InternalClusterConfigurationService.CLUSTER_CONFIG};
+        groups = new String[] {ClusterConfigurationService.CLUSTER_CONFIG};
       }
       for (String group : groups) {
         Configuration configuration = configRegion.get(group);
@@ -303,7 +301,7 @@ public class InternalClusterConfigurationService implements ClusterConfiguration
     lockSharedConfiguration();
     try {
       if (groups == null) {
-        groups = new String[] {InternalClusterConfigurationService.CLUSTER_CONFIG};
+        groups = new String[] {ClusterConfigurationService.CLUSTER_CONFIG};
       }
       Region<String, Configuration> configRegion = getConfigurationRegion();
       for (String group : groups) {
@@ -349,7 +347,7 @@ public class InternalClusterConfigurationService implements ClusterConfiguration
     lockSharedConfiguration();
     try {
       if (groups == null) {
-        groups = new String[] {InternalClusterConfigurationService.CLUSTER_CONFIG};
+        groups = new String[] {ClusterConfigurationService.CLUSTER_CONFIG};
       }
       Region<String, Configuration> configRegion = getConfigurationRegion();
       for (String group : groups) {
@@ -538,11 +536,10 @@ public class InternalClusterConfigurationService implements ClusterConfiguration
     Properties securityProps = this.cache.getDistributedSystem().getSecurityProperties();
 
     Configuration clusterPropertiesConfig =
-        configRegion.get(InternalClusterConfigurationService.CLUSTER_CONFIG);
+        configRegion.get(ClusterConfigurationService.CLUSTER_CONFIG);
     if (clusterPropertiesConfig == null) {
-      clusterPropertiesConfig =
-          new Configuration(InternalClusterConfigurationService.CLUSTER_CONFIG);
-      configRegion.put(InternalClusterConfigurationService.CLUSTER_CONFIG, clusterPropertiesConfig);
+      clusterPropertiesConfig = new Configuration(ClusterConfigurationService.CLUSTER_CONFIG);
+      configRegion.put(ClusterConfigurationService.CLUSTER_CONFIG, clusterPropertiesConfig);
     }
     // put security-manager and security-post-processor in the cluster config
     Properties clusterProperties = clusterPropertiesConfig.getGemfireProperties();
@@ -567,7 +564,7 @@ public class InternalClusterConfigurationService implements ClusterConfiguration
     try {
       if (isLocked) {
         configResponse = new ConfigurationResponse();
-        groups.add(InternalClusterConfigurationService.CLUSTER_CONFIG);
+        groups.add(ClusterConfigurationService.CLUSTER_CONFIG);
         logger.info("Building up configuration response with following configurations: {}", groups);
 
         for (String group : groups) {
diff --git a/geode-core/src/main/java/org/apache/geode/internal/cache/ClusterConfigurationLoader.java b/geode-core/src/main/java/org/apache/geode/internal/cache/ClusterConfigurationLoader.java
index 2288f21..8f63e82 100644
--- a/geode-core/src/main/java/org/apache/geode/internal/cache/ClusterConfigurationLoader.java
+++ b/geode-core/src/main/java/org/apache/geode/internal/cache/ClusterConfigurationLoader.java
@@ -51,10 +51,10 @@ import org.apache.geode.cache.execute.FunctionException;
 import org.apache.geode.cache.execute.FunctionInvocationTargetException;
 import org.apache.geode.cache.execute.FunctionService;
 import org.apache.geode.cache.execute.ResultCollector;
+import org.apache.geode.distributed.ClusterConfigurationService;
 import org.apache.geode.distributed.DistributedMember;
 import org.apache.geode.distributed.LockServiceDestroyedException;
 import org.apache.geode.distributed.internal.DistributionConfig;
-import org.apache.geode.distributed.internal.InternalClusterConfigurationService;
 import org.apache.geode.distributed.internal.membership.InternalDistributedMember;
 import org.apache.geode.internal.ClassPathLoader;
 import org.apache.geode.internal.ConfigSource;
@@ -169,7 +169,7 @@ public class ClusterConfigurationLoader {
 
     // apply the cluster config first
     Configuration clusterConfiguration =
-        requestedConfiguration.get(InternalClusterConfigurationService.CLUSTER_CONFIG);
+        requestedConfiguration.get(ClusterConfigurationService.CLUSTER_CONFIG);
     if (clusterConfiguration != null) {
       String cacheXmlContent = clusterConfiguration.getCacheXmlContent();
       if (StringUtils.isNotBlank(cacheXmlContent)) {
@@ -221,7 +221,7 @@ public class ClusterConfigurationLoader {
 
     // apply the cluster config first
     Configuration clusterConfiguration =
-        requestedConfiguration.get(InternalClusterConfigurationService.CLUSTER_CONFIG);
+        requestedConfiguration.get(ClusterConfigurationService.CLUSTER_CONFIG);
     if (clusterConfiguration != null) {
       runtimeProps.putAll(clusterConfiguration.getGemfireProperties());
     }
diff --git a/geode-core/src/main/java/org/apache/geode/internal/cache/GemFireCacheImpl.java b/geode-core/src/main/java/org/apache/geode/internal/cache/GemFireCacheImpl.java
index 7404a44..8cd5eea 100755
--- a/geode-core/src/main/java/org/apache/geode/internal/cache/GemFireCacheImpl.java
+++ b/geode-core/src/main/java/org/apache/geode/internal/cache/GemFireCacheImpl.java
@@ -147,6 +147,7 @@ import org.apache.geode.cache.wan.GatewayReceiver;
 import org.apache.geode.cache.wan.GatewayReceiverFactory;
 import org.apache.geode.cache.wan.GatewaySender;
 import org.apache.geode.cache.wan.GatewaySenderFactory;
+import org.apache.geode.distributed.ClusterConfigurationService;
 import org.apache.geode.distributed.ConfigurationProperties;
 import org.apache.geode.distributed.DistributedLockService;
 import org.apache.geode.distributed.DistributedMember;
@@ -160,7 +161,6 @@ import org.apache.geode.distributed.internal.DistributionAdvisor;
 import org.apache.geode.distributed.internal.DistributionAdvisor.Profile;
 import org.apache.geode.distributed.internal.DistributionConfig;
 import org.apache.geode.distributed.internal.DistributionManager;
-import org.apache.geode.distributed.internal.InternalClusterConfigurationService;
 import org.apache.geode.distributed.internal.InternalDistributedSystem;
 import org.apache.geode.distributed.internal.InternalLocator;
 import org.apache.geode.distributed.internal.PooledExecutorWithDMStats;
@@ -1075,8 +1075,8 @@ public class GemFireCacheImpl implements InternalCache, InternalClientCache, Has
           .create(LocalizedStrings.GemFireCache_RECEIVED_SHARED_CONFIGURATION_FROM_LOCATORS));
       logger.info(response.describeConfig());
 
-      Configuration clusterConfig = response.getRequestedConfiguration()
-          .get(InternalClusterConfigurationService.CLUSTER_CONFIG);
+      Configuration clusterConfig =
+          response.getRequestedConfiguration().get(ClusterConfigurationService.CLUSTER_CONFIG);
       Properties clusterSecProperties =
           clusterConfig == null ? new Properties() : clusterConfig.getGemfireProperties();
 
diff --git a/geode-core/src/main/java/org/apache/geode/management/cli/SingleGfshCommand.java b/geode-core/src/main/java/org/apache/geode/management/cli/SingleGfshCommand.java
new file mode 100644
index 0000000..ef5c1bc
--- /dev/null
+++ b/geode-core/src/main/java/org/apache/geode/management/cli/SingleGfshCommand.java
@@ -0,0 +1,45 @@
+/*
+ * 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.cli;
+
+import org.apache.geode.annotations.Experimental;
+import org.apache.geode.cache.configuration.CacheConfig;
+
+/**
+ * Command class that extends this class can only have one single command method,
+ * i.e only one method that is annotated with @CliCommand.
+ */
+@Experimental
+public abstract class SingleGfshCommand extends GfshCommand {
+
+  /**
+   * implement this method for updating the cluster configuration of the group
+   *
+   * the implementation should update the passed in config object with appropriate changes
+   * if for any reason config can't be updated. throw a RuntimeException stating the reason.
+   *
+   * @param group the group name of the cluster config, never null
+   * @param config the configuration object, never null
+   * @param configObject the return value of CommandResult.getConfigObject. CommandResult is the
+   *        return
+   *        value of your command method.
+   *
+   *        it should throw some RuntimeException if update failed.
+   */
+  public abstract void updateClusterConfig(String group, CacheConfig config, Object configObject);
+}
diff --git a/geode-core/src/main/java/org/apache/geode/management/internal/cli/commands/CreateIndexCommand.java b/geode-core/src/main/java/org/apache/geode/management/internal/cli/commands/CreateIndexCommand.java
index d9b27c1..60df346 100644
--- a/geode-core/src/main/java/org/apache/geode/management/internal/cli/commands/CreateIndexCommand.java
+++ b/geode-core/src/main/java/org/apache/geode/management/internal/cli/commands/CreateIndexCommand.java
@@ -21,27 +21,28 @@ import java.util.Set;
 import org.springframework.shell.core.annotation.CliCommand;
 import org.springframework.shell.core.annotation.CliOption;
 
+import org.apache.geode.cache.configuration.CacheConfig;
+import org.apache.geode.cache.configuration.RegionConfig;
 import org.apache.geode.cache.query.IndexType;
 import org.apache.geode.distributed.DistributedMember;
-import org.apache.geode.distributed.internal.InternalClusterConfigurationService;
 import org.apache.geode.management.cli.CliMetaData;
 import org.apache.geode.management.cli.ConverterHint;
 import org.apache.geode.management.cli.Result;
-import org.apache.geode.management.internal.cli.domain.IndexInfo;
+import org.apache.geode.management.cli.SingleGfshCommand;
+import org.apache.geode.management.internal.cli.exceptions.EntityNotFoundException;
 import org.apache.geode.management.internal.cli.functions.CliFunctionResult;
 import org.apache.geode.management.internal.cli.functions.CreateIndexFunction;
 import org.apache.geode.management.internal.cli.i18n.CliStrings;
+import org.apache.geode.management.internal.cli.result.CommandResult;
 import org.apache.geode.management.internal.cli.result.ResultBuilder;
-import org.apache.geode.management.internal.configuration.domain.XmlEntity;
 import org.apache.geode.management.internal.security.ResourceOperation;
 import org.apache.geode.security.ResourcePermission;
 
-public class CreateIndexCommand extends InternalGfshCommand {
+public class CreateIndexCommand extends SingleGfshCommand {
   private static final CreateIndexFunction createIndexFunction = new CreateIndexFunction();
 
   @CliCommand(value = CliStrings.CREATE_INDEX, help = CliStrings.CREATE_INDEX__HELP)
   @CliMetaData(relatedTopic = {CliStrings.TOPIC_GEODE_REGION, CliStrings.TOPIC_GEODE_DATA})
-  // TODO : Add optionContext for indexName
   @ResourceOperation(resource = ResourcePermission.Resource.CLUSTER,
       operation = ResourcePermission.Operation.MANAGE, target = ResourcePermission.Target.QUERY)
   public Result createIndex(@CliOption(key = CliStrings.CREATE_INDEX__NAME, mandatory = true,
@@ -64,26 +65,54 @@ public class CreateIndexCommand extends InternalGfshCommand {
 
       @CliOption(key = {CliStrings.GROUP, CliStrings.GROUPS},
           optionContext = ConverterHint.MEMBERGROUP,
-          help = CliStrings.CREATE_INDEX__GROUP__HELP) final String[] group) {
+          help = CliStrings.CREATE_INDEX__GROUP__HELP) final String[] groups) {
 
-    Result result;
-    final Set<DistributedMember> targetMembers = findMembers(group, memberNameOrID);
+    CommandResult result;
+    final Set<DistributedMember> targetMembers = findMembers(groups, memberNameOrID);
 
     if (targetMembers.isEmpty()) {
       return ResultBuilder.createUserErrorResult(CliStrings.NO_MEMBERS_FOUND_MESSAGE);
     }
 
-    IndexInfo indexInfo = new IndexInfo(indexName, indexedExpression, regionPath, indexType);
+    RegionConfig.Index index = new RegionConfig.Index();
+    index.setName(indexName);
+    index.setExpression(indexedExpression);
+    index.setFromClause(regionPath);
+    if (indexType == IndexType.PRIMARY_KEY) {
+      index.setKeyIndex(true);
+    } else {
+      index.setKeyIndex(false);
+      index.setType(indexType.getName());
+    }
+
     List<CliFunctionResult> functionResults =
-        executeAndGetFunctionResult(createIndexFunction, indexInfo, targetMembers);
+        executeAndGetFunctionResult(createIndexFunction, index, targetMembers);
     result = ResultBuilder.buildResult(functionResults);
-    XmlEntity xmlEntity = findXmlEntity(functionResults);
+    result.setConfigObject(index);
+    return result;
+  }
 
-    if (xmlEntity != null) {
-      persistClusterConfiguration(result,
-          () -> ((InternalClusterConfigurationService) getConfigurationService())
-              .addXmlEntity(xmlEntity, group));
+  String getValidRegionName(String regionPath, CacheConfig cacheConfig) {
+    // Check to see if the region path contains an alias e.g "/region1 r1"
+    // Then the first string will be the regionPath
+    String[] regionPathTokens = regionPath.trim().split(" ");
+    regionPath = regionPathTokens[0];
+    // check to see if the region path is in the form of "--region=region.entrySet() z"
+    while (regionPath.contains(".") && cacheConfig.findRegionConfiguration(regionPath) == null) {
+      regionPath = regionPath.substring(0, regionPath.lastIndexOf("."));
     }
-    return result;
+    return regionPath;
+  }
+
+  @Override
+  public void updateClusterConfig(String group, CacheConfig config, Object element) {
+    RegionConfig.Index index = (RegionConfig.Index) element;
+    String regionPath = getValidRegionName(index.getFromClause(), config);
+
+    RegionConfig regionConfig = config.findRegionConfiguration(regionPath);
+    if (regionConfig == null) {
+      throw new EntityNotFoundException("Region " + index.getFromClause() + " not found.");
+    }
+    regionConfig.getIndex().add(index);
   }
 }
diff --git a/geode-core/src/main/java/org/apache/geode/management/internal/cli/functions/CreateIndexFunction.java b/geode-core/src/main/java/org/apache/geode/management/internal/cli/functions/CreateIndexFunction.java
index 559fa28..c3824d5 100644
--- a/geode-core/src/main/java/org/apache/geode/management/internal/cli/functions/CreateIndexFunction.java
+++ b/geode-core/src/main/java/org/apache/geode/management/internal/cli/functions/CreateIndexFunction.java
@@ -15,6 +15,7 @@
 package org.apache.geode.management.internal.cli.functions;
 
 import org.apache.geode.cache.Cache;
+import org.apache.geode.cache.configuration.RegionConfig;
 import org.apache.geode.cache.execute.FunctionContext;
 import org.apache.geode.cache.query.IndexExistsException;
 import org.apache.geode.cache.query.IndexInvalidException;
@@ -22,10 +23,7 @@ import org.apache.geode.cache.query.IndexNameConflictException;
 import org.apache.geode.cache.query.QueryService;
 import org.apache.geode.cache.query.RegionNotFoundException;
 import org.apache.geode.internal.cache.execute.InternalFunction;
-import org.apache.geode.internal.cache.xmlcache.CacheXml;
-import org.apache.geode.management.internal.cli.domain.IndexInfo;
 import org.apache.geode.management.internal.cli.i18n.CliStrings;
-import org.apache.geode.management.internal.configuration.domain.XmlEntity;
 
 /***
  * Function to create index in a member, based on different arguments passed to it
@@ -38,81 +36,45 @@ public class CreateIndexFunction implements InternalFunction {
 
   @Override
   public void execute(FunctionContext context) {
-    final IndexInfo indexInfo = (IndexInfo) context.getArguments();
+    final RegionConfig.Index indexInfo = (RegionConfig.Index) context.getArguments();
     String memberId = null;
     try {
       Cache cache = context.getCache();
       memberId = cache.getDistributedSystem().getDistributedMember().getId();
       QueryService queryService = cache.getQueryService();
-      String indexName = indexInfo.getIndexName();
-      String indexedExpression = indexInfo.getIndexedExpression();
-      String fromClause = indexInfo.getRegionPath();
-      // Check to see if the region path contains an alias e.g "/region1 r1"
-      // Then the first string will be the regionPath
-      String[] regionPathTokens = fromClause.trim().split(" ");
-      String regionPath = regionPathTokens[0];
-
-      switch (indexInfo.getIndexType()) {
-        case FUNCTIONAL:
-          queryService.createIndex(indexName, indexedExpression, fromClause);
-          break;
-        case PRIMARY_KEY:
-          queryService.createKeyIndex(indexName, indexedExpression, fromClause);
-          break;
-        case HASH:
-          queryService.createHashIndex(indexName, indexedExpression, fromClause);
-          break;
-        default:
-          queryService.createIndex(indexName, indexedExpression, fromClause);
+      String indexName = indexInfo.getName();
+      String indexedExpression = indexInfo.getExpression();
+      String fromClause = indexInfo.getFromClause();
+      if (indexInfo.isKeyIndex()) {
+        queryService.createKeyIndex(indexName, indexedExpression, fromClause);
+      } else if ("hash".equals(indexInfo.getType())) {
+        queryService.createHashIndex(indexName, indexedExpression, fromClause);
+      } else {
+        queryService.createIndex(indexName, indexedExpression, fromClause);
       }
 
-      regionPath = getValidRegionName(cache, regionPath);
-      setResultInSender(context, indexInfo, memberId, cache, regionPath);
+      context.getResultSender()
+          .lastResult(new CliFunctionResult(memberId, null, "Index successfully created"));
+
     } catch (IndexExistsException e) {
       String message =
-          CliStrings.format(CliStrings.CREATE_INDEX__INDEX__EXISTS, indexInfo.getIndexName());
+          CliStrings.format(CliStrings.CREATE_INDEX__INDEX__EXISTS, indexInfo.getName());
       context.getResultSender().lastResult(new CliFunctionResult(memberId, false, message));
     } catch (IndexNameConflictException e) {
       String message =
-          CliStrings.format(CliStrings.CREATE_INDEX__NAME__CONFLICT, indexInfo.getIndexName());
+          CliStrings.format(CliStrings.CREATE_INDEX__NAME__CONFLICT, indexInfo.getName());
       context.getResultSender().lastResult(new CliFunctionResult(memberId, false, message));
     } catch (RegionNotFoundException e) {
       String message = CliStrings.format(CliStrings.CREATE_INDEX__INVALID__REGIONPATH,
-          indexInfo.getRegionPath());
+          indexInfo.getFromClause());
       context.getResultSender().lastResult(new CliFunctionResult(memberId, false, message));
     } catch (IndexInvalidException e) {
       context.getResultSender().lastResult(new CliFunctionResult(memberId, e, e.getMessage()));
     } catch (Exception e) {
       String exceptionMessage = CliStrings.format(CliStrings.EXCEPTION_CLASS_AND_MESSAGE,
           e.getClass().getName(), e.getMessage());
-      context.getResultSender().lastResult(new CliFunctionResult(memberId, e, e.getMessage()));
-    }
-  }
-
-  private void setResultInSender(FunctionContext context, IndexInfo indexInfo, String memberId,
-      Cache cache, String regionPath) {
-    if (regionPath == null) {
-      String message = CliStrings.format(CliStrings.CREATE_INDEX__INVALID__REGIONPATH,
-          indexInfo.getRegionPath());
-      context.getResultSender().lastResult(new CliFunctionResult(memberId, false, message));
-    } else {
-      XmlEntity xmlEntity =
-          new XmlEntity(CacheXml.REGION, "name", cache.getRegion(regionPath).getName());
-      context.getResultSender()
-          .lastResult(new CliFunctionResult(memberId, xmlEntity, "Index successfully created"));
-    }
-  }
-
-  private String getValidRegionName(Cache cache, String regionPath) {
-    while (regionPath != null && cache.getRegion(regionPath) == null) {
-      int dotPosition;
-      if (regionPath.contains(".") && ((dotPosition = regionPath.lastIndexOf('.')) != -1)) {
-        regionPath = regionPath.substring(0, dotPosition);
-      } else {
-        regionPath = null;
-      }
+      context.getResultSender().lastResult(new CliFunctionResult(memberId, e, exceptionMessage));
     }
-    return regionPath;
   }
 
   @Override
diff --git a/geode-core/src/main/java/org/apache/geode/management/internal/cli/remote/CommandExecutor.java b/geode-core/src/main/java/org/apache/geode/management/internal/cli/remote/CommandExecutor.java
index 5a165ea..dc402ed 100755
--- a/geode-core/src/main/java/org/apache/geode/management/internal/cli/remote/CommandExecutor.java
+++ b/geode-core/src/main/java/org/apache/geode/management/internal/cli/remote/CommandExecutor.java
@@ -15,13 +15,17 @@
 package org.apache.geode.management.internal.cli.remote;
 
 import org.apache.logging.log4j.Logger;
-import org.springframework.shell.event.ParseResult;
 import org.springframework.util.ReflectionUtils;
 
 import org.apache.geode.SystemFailure;
+import org.apache.geode.distributed.ClusterConfigurationService;
 import org.apache.geode.internal.logging.LogService;
+import org.apache.geode.management.cli.Result;
+import org.apache.geode.management.cli.SingleGfshCommand;
+import org.apache.geode.management.internal.cli.GfshParseResult;
 import org.apache.geode.management.internal.cli.exceptions.EntityNotFoundException;
 import org.apache.geode.management.internal.cli.exceptions.UserErrorException;
+import org.apache.geode.management.internal.cli.result.CommandResult;
 import org.apache.geode.management.internal.cli.result.ResultBuilder;
 import org.apache.geode.security.NotAuthorizedException;
 
@@ -35,12 +39,12 @@ public class CommandExecutor {
   private Logger logger = LogService.getLogger();
 
   // used by the product
-  public Object execute(ParseResult parseResult) {
+  public Object execute(GfshParseResult parseResult) {
     return execute(null, parseResult);
   }
 
   // used by the GfshParserRule to pass in a mock command
-  public Object execute(Object command, ParseResult parseResult) {
+  public Object execute(Object command, GfshParseResult parseResult) {
     try {
       Object result = invokeCommand(command, parseResult);
 
@@ -89,12 +93,51 @@ public class CommandExecutor {
     }
   }
 
-  protected Object invokeCommand(Object command, ParseResult parseResult) {
+  protected Object invokeCommand(Object command, GfshParseResult parseResult) {
     // if no command instance is passed in, use the one in the parseResult
     if (command == null) {
       command = parseResult.getInstance();
     }
-    return ReflectionUtils.invokeMethod(parseResult.getMethod(), command,
-        parseResult.getArguments());
+
+    Object result =
+        ReflectionUtils.invokeMethod(parseResult.getMethod(), command, parseResult.getArguments());
+
+    if (!(command instanceof SingleGfshCommand)) {
+      return result;
+    }
+
+    SingleGfshCommand gfshCommand = (SingleGfshCommand) command;
+    CommandResult commandResult = (CommandResult) result;
+    if (commandResult.getStatus() == Result.Status.ERROR) {
+      return result;
+    }
+
+    // if command result is ok, we will need to see if we need to update cluster configuration
+    ClusterConfigurationService ccService = gfshCommand.getConfigurationService();
+    if (parseResult.getParamValue("member") != null || ccService == null) {
+      commandResult.setCommandPersisted(false);
+      return commandResult;
+    }
+
+    String groupInput = parseResult.getParamValueAsString("group");
+    if (groupInput == null) {
+      groupInput = "cluster";
+    }
+    String[] groups = groupInput.split(",");
+    for (String group : groups) {
+      ccService.updateCacheConfig(group, cc -> {
+        try {
+          gfshCommand.updateClusterConfig(group, cc, commandResult.getConfigObject());
+        } catch (Exception e) {
+          logger.error("failed to update cluster config for " + group, e);
+          // for now, if one cc update failed, we will set this flag. Will change this when we can
+          // add lines to the result returned by the command
+          commandResult.setCommandPersisted(false);
+          return null;
+        }
+        return cc;
+      });
+    }
+    return commandResult;
   }
 }
diff --git a/geode-core/src/main/java/org/apache/geode/management/internal/cli/remote/OnlineCommandProcessor.java b/geode-core/src/main/java/org/apache/geode/management/internal/cli/remote/OnlineCommandProcessor.java
index 65ea57f..93fd103 100644
--- a/geode-core/src/main/java/org/apache/geode/management/internal/cli/remote/OnlineCommandProcessor.java
+++ b/geode-core/src/main/java/org/apache/geode/management/internal/cli/remote/OnlineCommandProcessor.java
@@ -31,6 +31,7 @@ import org.apache.geode.management.cli.CliMetaData;
 import org.apache.geode.management.cli.CommandProcessingException;
 import org.apache.geode.management.cli.Result;
 import org.apache.geode.management.internal.cli.CommandManager;
+import org.apache.geode.management.internal.cli.GfshParseResult;
 import org.apache.geode.management.internal.cli.GfshParser;
 import org.apache.geode.management.internal.cli.result.ResultBuilder;
 import org.apache.geode.management.internal.cli.util.CommentSkipHelper;
@@ -124,6 +125,6 @@ public class OnlineCommandProcessor {
           .createUserErrorResult(command + " can not be executed only from server side");
     }
 
-    return (Result) commandExecutor.execute(parseResult);
+    return (Result) commandExecutor.execute((GfshParseResult) parseResult);
   }
 }
diff --git a/geode-core/src/main/java/org/apache/geode/management/internal/cli/result/CommandResult.java b/geode-core/src/main/java/org/apache/geode/management/internal/cli/result/CommandResult.java
index cfd4f64..f68eac9 100644
--- a/geode-core/src/main/java/org/apache/geode/management/internal/cli/result/CommandResult.java
+++ b/geode-core/src/main/java/org/apache/geode/management/internal/cli/result/CommandResult.java
@@ -56,6 +56,7 @@ public class CommandResult implements Result {
   private ResultData resultData;
   private List<String> resultLines;
   private boolean failedToPersist = false;
+  private Object configObject;
 
   private transient int numTimesSaved;
 
@@ -99,6 +100,14 @@ public class CommandResult implements Result {
     return gfJsonObject;
   }
 
+  public Object getConfigObject() {
+    return configObject;
+  }
+
+  public void setConfigObject(Object configObject) {
+    this.configObject = configObject;
+  }
+
   @Override
   public void resetToFirstLine() {
     index = 0;
diff --git a/geode-core/src/main/java/org/apache/geode/management/internal/cli/shell/GfshExecutionStrategy.java b/geode-core/src/main/java/org/apache/geode/management/internal/cli/shell/GfshExecutionStrategy.java
index be641d8..13ee449 100755
--- a/geode-core/src/main/java/org/apache/geode/management/internal/cli/shell/GfshExecutionStrategy.java
+++ b/geode-core/src/main/java/org/apache/geode/management/internal/cli/shell/GfshExecutionStrategy.java
@@ -78,7 +78,7 @@ public class GfshExecutionStrategy implements ExecutionStrategy {
       synchronized (mutex) {
         Assert.isTrue(isReadyForCommands(), "Not yet ready for commands");
 
-        return new CommandExecutor().execute(parseResult);
+        return new CommandExecutor().execute((GfshParseResult) parseResult);
       }
     }
 
diff --git a/geode-core/src/main/resources/org/apache/geode/internal/sanctioned-geode-core-serializables.txt b/geode-core/src/main/resources/org/apache/geode/internal/sanctioned-geode-core-serializables.txt
index ceffa41..75d2d1d 100644
--- a/geode-core/src/main/resources/org/apache/geode/internal/sanctioned-geode-core-serializables.txt
+++ b/geode-core/src/main/resources/org/apache/geode/internal/sanctioned-geode-core-serializables.txt
@@ -129,6 +129,7 @@ org/apache/geode/cache/configuration/RegionAttributesIndexUpdateType,false,value
 org/apache/geode/cache/configuration/RegionAttributesMirrorType,false,value:java/lang/String
 org/apache/geode/cache/configuration/RegionAttributesScope,false,value:java/lang/String
 org/apache/geode/cache/configuration/RegionConfig,false,entry:java/util/List,index:java/util/List,name:java/lang/String,refid:java/lang/String,region:java/util/List,regionAttributes:java/util/List,regionElements:java/util/List
+org/apache/geode/cache/configuration/RegionConfig$Index,false,expression:java/lang/String,fromClause:java/lang/String,imports:java/lang/String,keyIndex:java/lang/Boolean,name:java/lang/String,type:java/lang/String
 org/apache/geode/cache/execute/EmptyRegionFunctionException,true,1
 org/apache/geode/cache/execute/FunctionAdapter,true,-4891043890440825485
 org/apache/geode/cache/execute/FunctionException,true,4893171227542647452
diff --git a/geode-core/src/test/java/org/apache/geode/cache/configuration/CacheConfigTest.java b/geode-core/src/test/java/org/apache/geode/cache/configuration/CacheConfigTest.java
new file mode 100644
index 0000000..16d96f0
--- /dev/null
+++ b/geode-core/src/test/java/org/apache/geode/cache/configuration/CacheConfigTest.java
@@ -0,0 +1,54 @@
+/*
+ * 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.cache.configuration;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.experimental.categories.Category;
+
+import org.apache.geode.internal.config.JAXBService;
+import org.apache.geode.test.junit.categories.UnitTest;
+
+
+@Category(UnitTest.class)
+public class CacheConfigTest {
+
+  private CacheConfig cacheConfig;
+  private JAXBService service;
+
+  @Before
+  public void setUp() throws Exception {
+    cacheConfig = new CacheConfig("1.0");
+    service = new JAXBService(CacheConfig.class);
+  }
+
+  @Test
+  public void invalidIndexType() {
+    RegionConfig regionConfig = new RegionConfig();
+    cacheConfig.getRegion().add(regionConfig);
+    regionConfig.setName("regionA");
+    regionConfig.setRefid("REPLICATE");
+    RegionConfig.Index index = new RegionConfig.Index();
+    index.setName("indexName");
+    index.setKeyIndex(true);
+    index.setExpression("expression");
+    regionConfig.getIndex().add(index);
+
+    System.out.println(service.marshall(cacheConfig));
+  }
+}
diff --git a/geode-core/src/test/java/org/apache/geode/distributed/internal/InternalClusterConfigurationServiceTest.java b/geode-core/src/test/java/org/apache/geode/distributed/internal/InternalClusterConfigurationServiceTest.java
index 8403a97..aeeefbc 100644
--- a/geode-core/src/test/java/org/apache/geode/distributed/internal/InternalClusterConfigurationServiceTest.java
+++ b/geode-core/src/test/java/org/apache/geode/distributed/internal/InternalClusterConfigurationServiceTest.java
@@ -17,9 +17,7 @@
 
 package org.apache.geode.distributed.internal;
 
-import static org.apache.geode.internal.config.JAXBServiceTest.setBasicValues;
 import static org.assertj.core.api.Assertions.assertThat;
-import static org.assertj.core.api.Assertions.assertThatThrownBy;
 import static org.mockito.ArgumentMatchers.any;
 import static org.mockito.ArgumentMatchers.eq;
 import static org.mockito.Mockito.doCallRealMethod;
@@ -40,7 +38,6 @@ import org.apache.geode.cache.configuration.RegionConfig;
 import org.apache.geode.internal.config.JAXBServiceTest;
 import org.apache.geode.internal.config.JAXBServiceTest.ElementOne;
 import org.apache.geode.internal.config.JAXBServiceTest.ElementTwo;
-import org.apache.geode.management.internal.cli.exceptions.EntityNotFoundException;
 import org.apache.geode.management.internal.configuration.domain.Configuration;
 import org.apache.geode.test.junit.categories.UnitTest;
 
@@ -104,12 +101,18 @@ public class InternalClusterConfigurationServiceTest {
   @Test
   public void addCustomCacheElement() {
     ElementOne customOne = new ElementOne("testOne");
-    service.saveCustomCacheElement("cluster", customOne);
+    service.updateCacheConfig("cluster", config -> {
+      config.getCustomCacheElements().add(customOne);
+      return config;
+    });
     System.out.println(configuration.getCacheXmlContent());
     assertThat(configuration.getCacheXmlContent()).contains("custom-one>");
 
     JAXBServiceTest.ElementTwo customTwo = new ElementTwo("testTwo");
-    service.saveCustomCacheElement("cluster", customTwo);
+    service.updateCacheConfig("cluster", config -> {
+      config.getCustomCacheElements().add(customTwo);
+      return config;
+    });
     System.out.println(configuration.getCacheXmlContent());
     assertThat(configuration.getCacheXmlContent()).contains("custom-one>");
     assertThat(configuration.getCacheXmlContent()).contains("custom-two>");
@@ -118,8 +121,11 @@ public class InternalClusterConfigurationServiceTest {
   @Test
   // in case a locator in the cluster doesn't have the plugin installed
   public void xmlWithCustomElementsCanBeUnMarshalledByAnotherService() {
-    service.saveCustomCacheElement("cluster", new ElementOne("one"));
-    service.saveCustomCacheElement("cluster", new ElementTwo("two"));
+    service.updateCacheConfig("cluster", config -> {
+      config.getCustomCacheElements().add(new ElementOne("one"));
+      config.getCustomCacheElements().add(new ElementTwo("two"));
+      return config;
+    });
 
     String prettyXml = configuration.getCacheXmlContent();
     System.out.println(prettyXml);
@@ -127,8 +133,8 @@ public class InternalClusterConfigurationServiceTest {
     // the xml is sent to another locator with no such plugin installed, it can be parsed
     // but the element couldn't be recognized by the locator without the plugin
     service2.updateCacheConfig("cluster", cc -> cc);
-    ElementOne elementOne = service2.getCustomCacheElement("cluster", "one", ElementOne.class);
-    assertThat(elementOne).isNull();
+    CacheConfig config = service2.getCacheConfig("cluster");
+    assertThat(config.findCustomCacheElement("one", ElementOne.class)).isNull();
 
     String uglyXml = configuration.getCacheXmlContent();
     System.out.println(uglyXml);
@@ -144,69 +150,6 @@ public class InternalClusterConfigurationServiceTest {
     assertThat(configuration.getCacheXmlContent()).isEqualTo(prettyXml);
   }
 
-
-  @Test
-  public void updateCustomCacheElement() {
-    ElementOne customOne = new ElementOne("testOne");
-    service.saveCustomCacheElement("cluster", customOne);
-    System.out.println(configuration.getCacheXmlContent());
-    assertThat(configuration.getCacheXmlContent()).contains("custom-one>");
-    assertThat(configuration.getCacheXmlContent()).containsPattern("<ns\\d:id>testOne</ns\\d:id>");
-    assertThat(configuration.getCacheXmlContent()).doesNotContain("<value>");
-
-    customOne = service.getCustomCacheElement("cluster", "testOne", ElementOne.class);
-    customOne.setValue("valueOne");
-    service.saveCustomCacheElement("cluster", customOne);
-    System.out.println(configuration.getCacheXmlContent());
-    assertThat(configuration.getCacheXmlContent()).contains("custom-one>");
-    assertThat(configuration.getCacheXmlContent()).containsPattern("<ns\\d:id>testOne</ns\\d:id>");
-    assertThat(configuration.getCacheXmlContent())
-        .containsPattern("<ns\\d:value>valueOne</ns\\d:value>");
-  }
-
-  @Test
-  public void deleteCustomCacheElement() {
-    ElementOne customOne = new ElementOne("testOne");
-    service.saveCustomCacheElement("cluster", customOne);
-    System.out.println(configuration.getCacheXmlContent());
-    assertThat(configuration.getCacheXmlContent()).contains("custom-one>");
-
-    service.deleteCustomCacheElement("cluster", "testOne", ElementOne.class);
-    System.out.println(configuration.getCacheXmlContent());
-    assertThat(configuration.getCacheXmlContent()).doesNotContain("custom-one>");
-  }
-
-  @Test
-  public void updateCustomRegionElement() {
-    // start with a cache.xml that has region info
-    service.updateCacheConfig("cluster", cacheConfig -> {
-      setBasicValues(cacheConfig);
-      return cacheConfig;
-    });
-
-    ElementOne one = new ElementOne("elementOne");
-    one.setValue("valueOne");
-
-    assertThatThrownBy(() -> service.saveCustomRegionElement("cluster", "noSuchRegion", one))
-        .isInstanceOf(EntityNotFoundException.class)
-        .hasMessageContaining("region noSuchRegion does not exist in group cluster");
-
-    service.saveCustomRegionElement("cluster", "testRegion", one);
-    System.out.println(configuration.getCacheXmlContent());
-    assertThat(configuration.getCacheXmlContent()).contains("region name=\"testRegion\"");
-    assertThat(configuration.getCacheXmlContent())
-        .containsPattern("</ns\\d:custom-one>\n" + "    </region>");
-
-    ElementOne retrieved =
-        service.getCustomRegionElement("cluster", "testRegion", "elementOne", ElementOne.class);
-    assertThat(retrieved.getId()).isEqualTo("elementOne");
-    assertThat(retrieved.getValue()).isEqualTo("valueOne");
-
-    service.deleteCustomRegionElement("cluster", "testRegion", "elementOne", ElementOne.class);
-    System.out.println(configuration.getCacheXmlContent());
-    assertThat(configuration.getCacheXmlContent()).doesNotContain("custom-one>");
-  }
-
   @Test
   public void getNonExistingGroupConfigShouldReturnNull() {
     assertThat(service.getCacheConfig("non-existing-group")).isNull();
diff --git a/geode-core/src/test/java/org/apache/geode/management/internal/cli/commands/CreateIndexCommandDUnitTest.java b/geode-core/src/test/java/org/apache/geode/management/internal/cli/commands/CreateIndexCommandDUnitTest.java
new file mode 100644
index 0000000..a83e6fa
--- /dev/null
+++ b/geode-core/src/test/java/org/apache/geode/management/internal/cli/commands/CreateIndexCommandDUnitTest.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 static org.assertj.core.api.Assertions.assertThat;
+
+import org.junit.BeforeClass;
+import org.junit.ClassRule;
+import org.junit.Test;
+import org.junit.experimental.categories.Category;
+
+import org.apache.geode.cache.Cache;
+import org.apache.geode.cache.RegionShortcut;
+import org.apache.geode.cache.configuration.CacheConfig;
+import org.apache.geode.distributed.internal.InternalClusterConfigurationService;
+import org.apache.geode.test.dunit.IgnoredException;
+import org.apache.geode.test.dunit.rules.ClusterStartupRule;
+import org.apache.geode.test.dunit.rules.MemberVM;
+import org.apache.geode.test.junit.categories.DistributedTest;
+import org.apache.geode.test.junit.rules.GfshCommandRule;
+
+
+@Category(DistributedTest.class)
+public class CreateIndexCommandDUnitTest {
+
+  @ClassRule
+  public static ClusterStartupRule cluster = new ClusterStartupRule();
+
+  @ClassRule
+  public static GfshCommandRule gfsh = new GfshCommandRule();
+
+  private static MemberVM locator, server1;
+
+  @BeforeClass
+  public static void beforeClass() throws Exception {
+    locator = cluster.startLocatorVM(0);
+    server1 = cluster.startServerVM(1, locator.getPort());
+    gfsh.connectAndVerify(locator);
+
+    // when locator started, the cacheConfig is null
+    locator.invoke(() -> {
+      CacheConfig cacheConfig =
+          ClusterStartupRule.getLocator().getSharedConfiguration().getCacheConfig("cluster");
+      assertThat(cacheConfig).isNull();
+    });
+  }
+
+  @Test
+  public void regionNotExist() {
+    gfsh.executeAndAssertThat("create index --name=myIndex --expression=id --region=/noExist")
+        .statusIsError().containsOutput("ERROR: Region not found : \"/noExist\"");
+
+    locator.invoke(() -> {
+      InternalClusterConfigurationService configurationService =
+          ClusterStartupRule.getLocator().getSharedConfiguration();
+      CacheConfig cacheConfig = configurationService.getCacheConfig("cluster");
+      assertThat(cacheConfig.findRegionConfiguration("noExist")).isNull();
+    });
+  }
+
+  @Test
+  public void regionExistOnServerButNotInClusterConfig() {
+    IgnoredException.addIgnoredException(
+        "org.apache.geode.management.internal.cli.exceptions.EntityNotFoundException");
+    server1.invoke(() -> {
+      Cache cache = ClusterStartupRule.getCache();
+      cache.createRegionFactory(RegionShortcut.REPLICATE).create("regionA");
+    });
+
+    // no region exists in cluster config
+    locator.invoke(() -> {
+      InternalClusterConfigurationService configurationService =
+          ClusterStartupRule.getLocator().getSharedConfiguration();
+      CacheConfig cacheConfig = configurationService.getCacheConfig("cluster");
+      assertThat(cacheConfig.findRegionConfiguration("regionA")).isNull();
+    });
+
+    gfsh.executeAndAssertThat("create index --name=myIndex --expression=id --region=regionA")
+        .statusIsSuccess().containsOutput("Index successfully created");
+
+    // after index is created, the cluster config is not udpated with regionA or index
+    locator.invoke(() -> {
+      InternalClusterConfigurationService configurationService =
+          ClusterStartupRule.getLocator().getSharedConfiguration();
+      assertThat(configurationService.getCacheConfig("cluster").findRegionConfiguration("regionA"))
+          .isNull();
+    });
+  }
+
+  @Test
+  public void regionExistInClusterConfig() {
+    gfsh.executeAndAssertThat("create region --name=regionB --type=REPLICATE").statusIsSuccess();
+    locator.waitTillRegionsAreReadyOnServers("/regionB", 1);
+    locator.invoke(() -> {
+      InternalClusterConfigurationService configurationService =
+          ClusterStartupRule.getLocator().getSharedConfiguration();
+      assertThat(configurationService.getConfiguration("cluster").getCacheXmlContent())
+          .contains("<region name=\"regionB\">");
+    });
+
+    gfsh.executeAndAssertThat("create index --name=myIndex --expression=id --region=regionB")
+        .statusIsSuccess();
+
+    locator.invoke(() -> {
+      InternalClusterConfigurationService configurationService =
+          ClusterStartupRule.getLocator().getSharedConfiguration();
+      assertThat(configurationService.getConfiguration("cluster").getCacheXmlContent())
+          .contains("<region name=\"regionB\">").contains("<index").contains("expression=\"id\" ")
+          .contains("from-clause=\"/regionB\"").contains("name=\"myIndex\"")
+          .contains("type=\"range\"");
+    });
+  }
+}
diff --git a/geode-core/src/test/java/org/apache/geode/management/internal/cli/commands/CreateIndexCommandTest.java b/geode-core/src/test/java/org/apache/geode/management/internal/cli/commands/CreateIndexCommandTest.java
index b3645e9..5bd0be9 100644
--- a/geode-core/src/test/java/org/apache/geode/management/internal/cli/commands/CreateIndexCommandTest.java
+++ b/geode-core/src/test/java/org/apache/geode/management/internal/cli/commands/CreateIndexCommandTest.java
@@ -33,10 +33,10 @@ import org.junit.Test;
 import org.junit.experimental.categories.Category;
 import org.mockito.ArgumentCaptor;
 
+import org.apache.geode.cache.configuration.CacheConfig;
+import org.apache.geode.cache.configuration.RegionConfig;
 import org.apache.geode.cache.execute.ResultCollector;
-import org.apache.geode.cache.query.IndexType;
 import org.apache.geode.distributed.DistributedMember;
-import org.apache.geode.management.internal.cli.domain.IndexInfo;
 import org.apache.geode.management.internal.cli.result.CommandResult;
 import org.apache.geode.test.junit.categories.UnitTest;
 import org.apache.geode.test.junit.rules.GfshParserRule;
@@ -122,15 +122,31 @@ public class CreateIndexCommandTest {
     DistributedMember member = mock(DistributedMember.class);
     doReturn(Collections.singleton(member)).when(command).findMembers(any(), any());
 
-    ArgumentCaptor<IndexInfo> indexTypeCaptor = ArgumentCaptor.forClass(IndexInfo.class);
+    ArgumentCaptor<RegionConfig.Index> indexTypeCaptor =
+        ArgumentCaptor.forClass(RegionConfig.Index.class);
     gfshParser.executeAndAssertThat(command,
         "create index --name=abc --expression=abc --region=abc");
 
     verify(command).executeAndGetFunctionResult(any(), indexTypeCaptor.capture(),
         eq(Collections.singleton(member)));
 
-    assertThat(indexTypeCaptor.getValue().getIndexType()).isEqualTo(IndexType.FUNCTIONAL);
+    assertThat(indexTypeCaptor.getValue().getType()).isEqualTo("range");
   }
 
-
+  @Test
+  public void getValidRegionName() {
+    CacheConfig cacheConfig = mock(CacheConfig.class);
+    RegionConfig region = new RegionConfig("regionA.regionB", "REPLICATE");
+    when(cacheConfig.findRegionConfiguration("/regionA.regionB")).thenReturn(region);
+
+    assertThat(command.getValidRegionName("regionB", cacheConfig)).isEqualTo("regionB");
+    assertThat(command.getValidRegionName("/regionB", cacheConfig)).isEqualTo("/regionB");
+    assertThat(command.getValidRegionName("/regionB b", cacheConfig)).isEqualTo("/regionB");
+    assertThat(command.getValidRegionName("/regionB.entrySet()", cacheConfig))
+        .isEqualTo("/regionB");
+    assertThat(command.getValidRegionName("/regionA.regionB.entrySet() A", cacheConfig))
+        .isEqualTo("/regionA.regionB");
+    assertThat(command.getValidRegionName("/regionB.regionA.entrySet() B", cacheConfig))
+        .isEqualTo("/regionB");
+  }
 }
diff --git a/geode-core/src/test/java/org/apache/geode/management/internal/cli/commands/IndexCommandsShareConfigurationDUnitTest.java b/geode-core/src/test/java/org/apache/geode/management/internal/cli/commands/IndexCommandsShareConfigurationDUnitTest.java
index 2ddb9ff..9d89ae3 100644
--- a/geode-core/src/test/java/org/apache/geode/management/internal/cli/commands/IndexCommandsShareConfigurationDUnitTest.java
+++ b/geode-core/src/test/java/org/apache/geode/management/internal/cli/commands/IndexCommandsShareConfigurationDUnitTest.java
@@ -14,41 +14,26 @@
  */
 package org.apache.geode.management.internal.cli.commands;
 
-import static org.apache.geode.distributed.ConfigurationProperties.ENABLE_CLUSTER_CONFIGURATION;
 import static org.apache.geode.distributed.ConfigurationProperties.GROUPS;
-import static org.apache.geode.distributed.ConfigurationProperties.HTTP_SERVICE_PORT;
-import static org.apache.geode.distributed.ConfigurationProperties.JMX_MANAGER;
-import static org.apache.geode.distributed.ConfigurationProperties.JMX_MANAGER_PORT;
-import static org.apache.geode.distributed.ConfigurationProperties.JMX_MANAGER_START;
-import static org.apache.geode.distributed.ConfigurationProperties.LOG_LEVEL;
-import static org.apache.geode.distributed.ConfigurationProperties.NAME;
-import static org.junit.Assert.assertFalse;
+import static org.apache.geode.distributed.ConfigurationProperties.SERIALIZABLE_OBJECT_FILTER;
+import static org.assertj.core.api.Assertions.assertThat;
 import static org.junit.Assert.assertNotNull;
 import static org.junit.Assert.assertNull;
-import static org.junit.Assert.assertTrue;
-
-import java.util.Properties;
 
 import org.junit.Before;
 import org.junit.Rule;
 import org.junit.Test;
 import org.junit.experimental.categories.Category;
 
-import org.apache.geode.cache.Cache;
-import org.apache.geode.cache.DataPolicy;
 import org.apache.geode.cache.Region;
-import org.apache.geode.cache.RegionFactory;
 import org.apache.geode.cache.query.Index;
-import org.apache.geode.distributed.ConfigurationProperties;
 import org.apache.geode.distributed.Locator;
 import org.apache.geode.distributed.internal.InternalClusterConfigurationService;
 import org.apache.geode.distributed.internal.InternalLocator;
-import org.apache.geode.internal.AvailablePortHelper;
 import org.apache.geode.internal.cache.InternalCache;
 import org.apache.geode.management.internal.cli.domain.Stock;
 import org.apache.geode.management.internal.cli.i18n.CliStrings;
 import org.apache.geode.management.internal.cli.util.CommandStringBuilder;
-import org.apache.geode.test.dunit.Assert;
 import org.apache.geode.test.dunit.rules.ClusterStartupRule;
 import org.apache.geode.test.dunit.rules.MemberVM;
 import org.apache.geode.test.junit.categories.DistributedTest;
@@ -71,35 +56,21 @@ public class IndexCommandsShareConfigurationDUnitTest {
 
   @Before
   public void before() throws Exception {
-    int jmxPort, httpPort;
-
-    final int[] ports = AvailablePortHelper.getRandomAvailableTCPPorts(2);
-    jmxPort = ports[0];
-    httpPort = ports[1];
-
-    final Properties locatorProps = new Properties();
-    locatorProps.setProperty(NAME, "Locator");
-    locatorProps.setProperty(LOG_LEVEL, "fine");
-    locatorProps.setProperty(ENABLE_CLUSTER_CONFIGURATION, "true");
-    locatorProps.setProperty(JMX_MANAGER, "true");
-    locatorProps.setProperty(JMX_MANAGER_START, "true");
-    locatorProps.setProperty(JMX_MANAGER_PORT, String.valueOf(jmxPort));
-    locatorProps.setProperty(HTTP_SERVICE_PORT, String.valueOf(httpPort));
-
-    locator = startupRule.startLocatorVM(0, x -> x.withProperties(locatorProps));
-
-    gfsh.connectAndVerify(locator.getJmxPort(), GfshCommandRule.PortType.jmxManager);
-
-    Properties props = new Properties();
-    props.setProperty(GROUPS, groupName);
-    props.setProperty(ConfigurationProperties.SERIALIZABLE_OBJECT_FILTER,
-        "org.apache.geode.management.internal.cli.domain.Stock");
-    serverVM = startupRule.startServerVM(1, props, locator.getPort());
+    locator = startupRule.startLocatorVM(0);
+    int locatorPort = locator.getPort();
+    serverVM = startupRule.startServerVM(1,
+        s -> s.withConnectionToLocator(locatorPort).withProperty(GROUPS, groupName).withProperty(
+            SERIALIZABLE_OBJECT_FILTER, "org.apache.geode.management.internal.cli.domain.Stock"));
+
+    gfsh.connectAndVerify(locator);
+
+    gfsh.executeAndAssertThat(
+        "create region  --group=group1 --name=partitionedRegion --type=PARTITION "
+            + "--key-constraint=java.lang.String --value-constraint=org.apache.geode.management.internal.cli.domain.Stock");
+
     serverVM.invoke(() -> {
-      InternalCache cache = ClusterStartupRule.getCache();
-      Region parReg =
-          createPartitionedRegion(partitionedRegionName, cache, String.class, Stock.class);
-      parReg.put("VMW", new Stock("VMW", 98));
+      Region region = ClusterStartupRule.getCache().getRegion(partitionedRegionName);
+      region.put("VMW", new Stock("VMW", 98));
     });
   }
 
@@ -112,18 +83,13 @@ public class IndexCommandsShareConfigurationDUnitTest {
     createStringBuilder.addOption(CliStrings.CREATE_INDEX__REGION, "/" + partitionedRegionName);
     gfsh.executeAndAssertThat(createStringBuilder.toString()).statusIsSuccess();
 
-    assertTrue(indexIsListed());
+    gfsh.executeAndAssertThat(CliStrings.LIST_INDEX).statusIsSuccess().containsOutput(indexName);
 
     locator.invoke(() -> {
       InternalClusterConfigurationService sharedConfig =
           ((InternalLocator) Locator.getLocator()).getSharedConfiguration();
-      String xmlFromConfig;
-      try {
-        xmlFromConfig = sharedConfig.getConfiguration(groupName).getCacheXmlContent();
-        assertTrue(xmlFromConfig.contains(indexName));
-      } catch (Exception e) {
-        Assert.fail("Error occurred in cluster configuration service", e);
-      }
+      String xmlFromConfig = sharedConfig.getConfiguration(groupName).getCacheXmlContent();
+      assertThat(xmlFromConfig).contains(indexName);
     });
 
     createStringBuilder = new CommandStringBuilder(CliStrings.DESTROY_INDEX);
@@ -135,13 +101,8 @@ public class IndexCommandsShareConfigurationDUnitTest {
     locator.invoke(() -> {
       InternalClusterConfigurationService sharedConfig =
           ((InternalLocator) Locator.getLocator()).getSharedConfiguration();
-      String xmlFromConfig;
-      try {
-        xmlFromConfig = sharedConfig.getConfiguration(groupName).getCacheXmlContent();
-        assertFalse(xmlFromConfig.contains(indexName));
-      } catch (Exception e) {
-        Assert.fail("Error occurred in cluster configuration service", e);
-      }
+      String xmlFromConfig = sharedConfig.getConfiguration(groupName).getCacheXmlContent();
+      assertThat(xmlFromConfig).doesNotContain(indexName);
     });
 
     // Restart the data member cache to make sure that the index is destroyed.
@@ -158,17 +119,4 @@ public class IndexCommandsShareConfigurationDUnitTest {
     });
   }
 
-  private static Region<?, ?> createPartitionedRegion(String regionName, Cache cache,
-      Class keyConstraint, Class valueConstraint) {
-    RegionFactory regionFactory = cache.createRegionFactory();
-    regionFactory.setDataPolicy(DataPolicy.PARTITION);
-    regionFactory.setKeyConstraint(keyConstraint);
-    regionFactory.setValueConstraint(valueConstraint);
-    return regionFactory.create(regionName);
-  }
-
-  private boolean indexIsListed() throws Exception {
-    gfsh.executeAndAssertThat(CliStrings.LIST_INDEX).statusIsSuccess();
-    return gfsh.getGfshOutput().contains(indexName);
-  }
 }
diff --git a/geode-core/src/test/java/org/apache/geode/management/internal/cli/remote/CommandExecutorTest.java b/geode-core/src/test/java/org/apache/geode/management/internal/cli/remote/CommandExecutorTest.java
index 85001de..f6b846b 100644
--- a/geode-core/src/test/java/org/apache/geode/management/internal/cli/remote/CommandExecutorTest.java
+++ b/geode-core/src/test/java/org/apache/geode/management/internal/cli/remote/CommandExecutorTest.java
@@ -26,9 +26,9 @@ import static org.mockito.Mockito.spy;
 import org.junit.Before;
 import org.junit.Test;
 import org.junit.experimental.categories.Category;
-import org.springframework.shell.event.ParseResult;
 
 import org.apache.geode.management.cli.Result;
+import org.apache.geode.management.internal.cli.GfshParseResult;
 import org.apache.geode.management.internal.cli.exceptions.EntityNotFoundException;
 import org.apache.geode.management.internal.cli.exceptions.UserErrorException;
 import org.apache.geode.management.internal.cli.result.CommandResult;
@@ -37,13 +37,13 @@ import org.apache.geode.test.junit.categories.UnitTest;
 
 @Category(UnitTest.class)
 public class CommandExecutorTest {
-  ParseResult parseResult;
+  GfshParseResult parseResult;
   CommandExecutor executor;
   Result result;
 
   @Before
   public void before() {
-    parseResult = mock(ParseResult.class);
+    parseResult = mock(GfshParseResult.class);
     result = mock(Result.class);
     executor = spy(CommandExecutor.class);
   }
diff --git a/geode-lucene/src/test/java/org/apache/geode/cache/lucene/internal/configuration/LuceneClusterConfigurationDUnitTest.java b/geode-lucene/src/test/java/org/apache/geode/cache/lucene/internal/configuration/LuceneClusterConfigurationDUnitTest.java
index cea463d..b629eaa 100644
--- a/geode-lucene/src/test/java/org/apache/geode/cache/lucene/internal/configuration/LuceneClusterConfigurationDUnitTest.java
+++ b/geode-lucene/src/test/java/org/apache/geode/cache/lucene/internal/configuration/LuceneClusterConfigurationDUnitTest.java
@@ -40,6 +40,7 @@ import org.apache.geode.cache.lucene.LuceneServiceProvider;
 import org.apache.geode.cache.lucene.internal.cli.LuceneCliStrings;
 import org.apache.geode.cache.lucene.internal.repository.serializer.PrimitiveSerializer;
 import org.apache.geode.cache.lucene.internal.xml.LuceneXmlConstants;
+import org.apache.geode.distributed.ClusterConfigurationService;
 import org.apache.geode.distributed.internal.InternalClusterConfigurationService;
 import org.apache.geode.distributed.internal.InternalLocator;
 import org.apache.geode.management.internal.cli.i18n.CliStrings;
@@ -263,8 +264,7 @@ public class LuceneClusterConfigurationDUnitTest {
     return () -> {
       InternalLocator internalLocator = ClusterStartupRule.getLocator();
       InternalClusterConfigurationService sc = internalLocator.getSharedConfiguration();
-      Configuration config =
-          sc.getConfiguration(InternalClusterConfigurationService.CLUSTER_CONFIG);
+      Configuration config = sc.getConfiguration(ClusterConfigurationService.CLUSTER_CONFIG);
       String xmlContent = config.getCacheXmlContent();
       String luceneIndex0Config = "<" + LuceneXmlConstants.PREFIX + ":" + LuceneXmlConstants.INDEX
           + " xmlns:lucene=\"" + LuceneXmlConstants.NAMESPACE + "\" " + LuceneXmlConstants.NAME

-- 
To stop receiving notification emails like this one, please contact
jinmeiliao@apache.org.