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

lgallinat pushed a commit to branch feature/GEODE-3781
in repository https://gitbox.apache.org/repos/asf/geode.git


The following commit(s) were added to refs/heads/feature/GEODE-3781 by this 
push:
     new cffa2f4  Feature/geode 4020 (#1122)
cffa2f4 is described below

commit cffa2f4da02b7267b76f576ce7f6aa40a3298fcc
Author: lgallinat <[email protected]>
AuthorDate: Tue Dec 5 17:16:55 2017 -0800

    Feature/geode 4020 (#1122)
    
    GEODE-4020 Add list connection command
---
 .../internal/ConnectionConfigExistsException.java  |   2 +-
 .../internal/InternalJdbcConnectorService.java     |   8 +-
 .../jdbc/internal/JdbcConnectorService.java        |  32 +++--
 .../jdbc/internal/cli/CreateConnectionCommand.java |  78 ++++++++----
 .../internal/cli/CreateConnectionFunction.java     |  56 +++++----
 .../internal/cli/DestroyConnectionCommand.java     |  70 +++++++----
 .../internal/cli/DestroyConnectionFunction.java    |  88 +++++++------
 .../jdbc/internal/cli/ExceptionHandler.java        |  46 +++++--
 .../cli/FunctionContextArgumentProvider.java       |  73 +++++++++++
 .../jdbc/internal/cli/ListConnectionCommand.java   | 105 ++++++++++++++++
 .../jdbc/internal/cli/ListConnectionFunction.java  |  77 ++++++++++++
 .../internal/xml/JdbcServiceConfiguration.java     |  13 +-
 .../org.springframework.shell.core.CommandMarker   |   1 +
 .../jdbc/JdbcAsyncWriterIntegrationTest.java       |   6 +-
 .../connectors/jdbc/JdbcLoaderIntegrationTest.java |  12 +-
 .../connectors/jdbc/JdbcWriterIntegrationTest.java |   6 +-
 .../jdbc/internal/JdbcConnectorServiceTest.java    |  16 +--
 .../jdbc/internal/TestConfigService.java           |   2 +-
 .../cli/CreateConnectionCommandDUnitTest.java      |   2 +-
 .../internal/cli/CreateConnectionFunctionTest.java |  62 ++++++---
 .../cli/DestroyConnectionCommandDUnitTest.java     |   3 +-
 .../DestroyConnectionCommandIntegrationTest.java   |  24 ++--
 .../cli/DestroyConnectionFunctionTest.java         |  36 ++++--
 ...va => FunctionContextArgumentProviderTest.java} |  69 +++-------
 ...st.java => ListConnectionCommandDUnitTest.java} |  75 +++++++----
 .../cli/ListConnectionCommandIntegrationTest.java  | 108 ++++++++++++++++
 ...onTest.java => ListConnectionFunctionTest.java} | 106 ++++++++++++----
 .../JdbcConnectorServiceXmlIntegrationTest.java    |   3 +-
 .../internal/xml/JdbcServiceConfigurationTest.java |  18 +--
 .../internal/configuration/domain/XmlEntity.java   | 139 ++++++++++++---------
 .../cache/xmlcache/CacheXmlParserJUnitTest.java    |   7 +-
 ...serJUnitTest.testSimpleClientCacheXml.cache.xml |   2 +-
 32 files changed, 977 insertions(+), 368 deletions(-)

diff --git 
a/geode-connectors/src/main/java/org/apache/geode/connectors/jdbc/internal/ConnectionConfigExistsException.java
 
b/geode-connectors/src/main/java/org/apache/geode/connectors/jdbc/internal/ConnectionConfigExistsException.java
index d960505..9094b10 100644
--- 
a/geode-connectors/src/main/java/org/apache/geode/connectors/jdbc/internal/ConnectionConfigExistsException.java
+++ 
b/geode-connectors/src/main/java/org/apache/geode/connectors/jdbc/internal/ConnectionConfigExistsException.java
@@ -14,7 +14,7 @@
  */
 package org.apache.geode.connectors.jdbc.internal;
 
-public class ConnectionConfigExistsException extends RuntimeException {
+public class ConnectionConfigExistsException extends Exception {
 
   public ConnectionConfigExistsException() {
     super();
diff --git 
a/geode-connectors/src/main/java/org/apache/geode/connectors/jdbc/internal/InternalJdbcConnectorService.java
 
b/geode-connectors/src/main/java/org/apache/geode/connectors/jdbc/internal/InternalJdbcConnectorService.java
index c7bdc16..c242255 100644
--- 
a/geode-connectors/src/main/java/org/apache/geode/connectors/jdbc/internal/InternalJdbcConnectorService.java
+++ 
b/geode-connectors/src/main/java/org/apache/geode/connectors/jdbc/internal/InternalJdbcConnectorService.java
@@ -14,6 +14,8 @@
  */
 package org.apache.geode.connectors.jdbc.internal;
 
+import java.util.Set;
+
 import org.apache.geode.cache.Cache;
 import org.apache.geode.internal.cache.CacheService;
 import org.apache.geode.internal.cache.extension.Extension;
@@ -25,9 +27,11 @@ public interface InternalJdbcConnectorService extends 
Extension<Cache>, CacheSer
 
   void destroyConnectionConfig(String connectionName);
 
-  void addOrUpdateRegionMapping(RegionMapping mapping);
-
   ConnectionConfiguration getConnectionConfig(String connectionName);
 
+  Set<ConnectionConfiguration> getConnectionConfigs();
+
+  void addOrUpdateRegionMapping(RegionMapping mapping);
+
   RegionMapping getMappingForRegion(String regionName);
 }
diff --git 
a/geode-connectors/src/main/java/org/apache/geode/connectors/jdbc/internal/JdbcConnectorService.java
 
b/geode-connectors/src/main/java/org/apache/geode/connectors/jdbc/internal/JdbcConnectorService.java
index de4759b..8192c75 100644
--- 
a/geode-connectors/src/main/java/org/apache/geode/connectors/jdbc/internal/JdbcConnectorService.java
+++ 
b/geode-connectors/src/main/java/org/apache/geode/connectors/jdbc/internal/JdbcConnectorService.java
@@ -14,7 +14,9 @@
  */
 package org.apache.geode.connectors.jdbc.internal;
 
+import java.util.HashSet;
 import java.util.Map;
+import java.util.Set;
 import java.util.concurrent.ConcurrentHashMap;
 
 import org.apache.geode.cache.Cache;
@@ -33,17 +35,8 @@ public class JdbcConnectorService implements 
InternalJdbcConnectorService {
   private boolean registered;
 
   @Override
-  public ConnectionConfiguration getConnectionConfig(String connectionName) {
-    return connectionsByName.get(connectionName);
-  }
-
-  @Override
-  public RegionMapping getMappingForRegion(String regionName) {
-    return mappingsByRegion.get(regionName);
-  }
-
-  @Override
-  public void createConnectionConfig(ConnectionConfiguration config) {
+  public void createConnectionConfig(ConnectionConfiguration config)
+      throws ConnectionConfigExistsException {
     registerAsExtension();
     ConnectionConfiguration existing = 
connectionsByName.putIfAbsent(config.getName(), config);
     if (existing != null) {
@@ -59,12 +52,29 @@ public class JdbcConnectorService implements 
InternalJdbcConnectorService {
   }
 
   @Override
+  public ConnectionConfiguration getConnectionConfig(String connectionName) {
+    return connectionsByName.get(connectionName);
+  }
+
+  @Override
+  public Set<ConnectionConfiguration> getConnectionConfigs() {
+    Set<ConnectionConfiguration> connectionConfigs = new HashSet<>();
+    connectionConfigs.addAll(connectionsByName.values());
+    return connectionConfigs;
+  }
+
+  @Override
   public void addOrUpdateRegionMapping(RegionMapping mapping) {
     registerAsExtension();
     mappingsByRegion.put(mapping.getRegionName(), mapping);
   }
 
   @Override
+  public RegionMapping getMappingForRegion(String regionName) {
+    return mappingsByRegion.get(regionName);
+  }
+
+  @Override
   public void init(Cache cache) {
     this.cache = (InternalCache) cache;
   }
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 9bf9ba0..93664ff 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
@@ -16,7 +16,6 @@ package org.apache.geode.connectors.jdbc.internal.cli;
 
 import java.util.List;
 import java.util.Set;
-import java.util.concurrent.atomic.AtomicReference;
 
 import org.apache.logging.log4j.Logger;
 import org.springframework.shell.core.annotation.CliCommand;
@@ -61,7 +60,7 @@ public class CreateConnectionCommand implements GfshCommand {
   private static final String ERROR_PREFIX = "ERROR: ";
 
   @CliCommand(value = CREATE_CONNECTION, help = CREATE_CONNECTION__HELP)
-  @CliMetaData(relatedTopic = CliStrings.TOPIC_GEODE_REGION)
+  @CliMetaData(relatedTopic = CliStrings.DEFAULT_TOPIC_GEODE)
   @ResourceOperation(resource = ResourcePermission.Resource.CLUSTER,
       operation = ResourcePermission.Operation.MANAGE)
   public Result createConnection(
@@ -75,42 +74,69 @@ public class CreateConnectionCommand implements GfshCommand 
{
       @CliOption(key = CREATE_CONNECTION__PARAMS,
           help = CREATE_CONNECTION__PARAMS__HELP) String[] params) {
 
-    Set<DistributedMember> membersToCreateConnectionOn = getMembers(null, 
null);
+    // input
+    Set<DistributedMember> targetMembers = getMembers(null, null);
+    ConnectionConfiguration configuration = getArguments(name, url, user, 
password, params);
 
+    // action
+    ResultCollector<CliFunctionResult, List<CliFunctionResult>> 
resultCollector =
+        execute(new CreateConnectionFunction(), configuration, targetMembers);
+
+    // output
+    TabularResultData tabularResultData = 
ResultBuilder.createTabularResultData();
+    XmlEntity xmlEntity = fillTabularResultData(resultCollector, 
tabularResultData);
+    Result result = ResultBuilder.buildResult(tabularResultData);
+    updateClusterConfiguration(result, xmlEntity);
+    return result;
+  }
+
+  ConnectionConfiguration getArguments(String name, String url, String user, 
String password,
+      String[] params) {
     ConnectionConfigBuilder builder = new 
ConnectionConfigBuilder().withName(name).withUrl(url)
         .withUser(user).withPassword(password).withParameters(params);
-    ConnectionConfiguration configuration = builder.build();
-
-    ResultCollector<?, ?> resultCollector =
-        executeFunction(new CreateConnectionFunction(), configuration, 
membersToCreateConnectionOn);
+    return builder.build();
+  }
 
-    Object resultCollectorResult = resultCollector.getResult();
+  ResultCollector<CliFunctionResult, List<CliFunctionResult>> execute(
+      CreateConnectionFunction function, ConnectionConfiguration configuration,
+      Set<DistributedMember> targetMembers) {
+    return (ResultCollector<CliFunctionResult, List<CliFunctionResult>>) 
executeFunction(function,
+        configuration, targetMembers);
+  }
 
-    List<CliFunctionResult> connectionCreateResults =
-        (List<CliFunctionResult>) resultCollectorResult;
+  private XmlEntity fillTabularResultData(
+      ResultCollector<CliFunctionResult, List<CliFunctionResult>> 
resultCollector,
+      TabularResultData tabularResultData) {
+    XmlEntity xmlEntity = null;
 
-    AtomicReference<XmlEntity> xmlEntity = new AtomicReference<>();
-    TabularResultData tabularResultData = 
ResultBuilder.createTabularResultData();
-    for (CliFunctionResult regionCreateResult : connectionCreateResults) {
-      boolean success = regionCreateResult.isSuccessful();
-      tabularResultData.accumulate("Member", 
regionCreateResult.getMemberIdOrName());
-      tabularResultData.accumulate("Status",
-          (success ? "" : ERROR_PREFIX) + regionCreateResult.getMessage());
-
-      if (success) {
-        xmlEntity.set(regionCreateResult.getXmlEntity());
+    for (CliFunctionResult oneResult : resultCollector.getResult()) {
+      if (oneResult.isSuccessful()) {
+        xmlEntity = addSuccessToResults(tabularResultData, oneResult);
       } else {
-        tabularResultData.setStatus(Result.Status.ERROR);
+        addErrorToResults(tabularResultData, oneResult);
       }
     }
 
-    Result result = ResultBuilder.buildResult(tabularResultData);
+    return xmlEntity;
+  }
+
+  private XmlEntity addSuccessToResults(TabularResultData tabularResultData,
+      CliFunctionResult oneResult) {
+    tabularResultData.accumulate("Member", oneResult.getMemberIdOrName());
+    tabularResultData.accumulate("Status", oneResult.getMessage());
+    return oneResult.getXmlEntity();
+  }
 
-    if (xmlEntity.get() != null) {
+  private void addErrorToResults(TabularResultData tabularResultData, 
CliFunctionResult oneResult) {
+    tabularResultData.accumulate("Member", oneResult.getMemberIdOrName());
+    tabularResultData.accumulate("Status", ERROR_PREFIX + 
oneResult.getMessage());
+    tabularResultData.setStatus(Result.Status.ERROR);
+  }
+
+  private void updateClusterConfiguration(final Result result, final XmlEntity 
xmlEntity) {
+    if (xmlEntity != null) {
       persistClusterConfiguration(result,
-          () -> getSharedConfiguration().addXmlEntity(xmlEntity.get(), null));
+          () -> getSharedConfiguration().addXmlEntity(xmlEntity, null));
     }
-
-    return result;
   }
 }
diff --git 
a/geode-connectors/src/main/java/org/apache/geode/connectors/jdbc/internal/cli/CreateConnectionFunction.java
 
b/geode-connectors/src/main/java/org/apache/geode/connectors/jdbc/internal/cli/CreateConnectionFunction.java
index 72358b0..503c237 100644
--- 
a/geode-connectors/src/main/java/org/apache/geode/connectors/jdbc/internal/cli/CreateConnectionFunction.java
+++ 
b/geode-connectors/src/main/java/org/apache/geode/connectors/jdbc/internal/cli/CreateConnectionFunction.java
@@ -14,9 +14,12 @@
  */
 package org.apache.geode.connectors.jdbc.internal.cli;
 
+import static 
org.apache.geode.connectors.jdbc.internal.cli.FunctionContextArgumentProvider.getMemberFromContext;
+
 import org.apache.geode.cache.execute.Function;
 import org.apache.geode.cache.execute.FunctionContext;
 import org.apache.geode.cache.execute.ResultSender;
+import 
org.apache.geode.connectors.jdbc.internal.ConnectionConfigExistsException;
 import org.apache.geode.connectors.jdbc.internal.ConnectionConfiguration;
 import org.apache.geode.connectors.jdbc.internal.InternalJdbcConnectorService;
 import org.apache.geode.connectors.jdbc.internal.xml.ElementType;
@@ -33,13 +36,16 @@ public class CreateConnectionFunction implements 
Function<ConnectionConfiguratio
 
   private static final String ID = CreateConnectionFunction.class.getName();
 
-  private final transient ExceptionHandler exceptionHandler;
+  private final FunctionContextArgumentProvider argumentProvider;
+  private final ExceptionHandler exceptionHandler;
 
   public CreateConnectionFunction() {
-    this(new ExceptionHandler());
+    this(new FunctionContextArgumentProvider(), new ExceptionHandler());
   }
 
-  private CreateConnectionFunction(ExceptionHandler exceptionHandler) {
+  private CreateConnectionFunction(FunctionContextArgumentProvider 
argumentProvider,
+      ExceptionHandler exceptionHandler) {
+    this.argumentProvider = argumentProvider;
     this.exceptionHandler = exceptionHandler;
   }
 
@@ -55,30 +61,36 @@ public class CreateConnectionFunction implements 
Function<ConnectionConfiguratio
 
   @Override
   public void execute(FunctionContext<ConnectionConfiguration> context) {
-    ResultSender<Object> resultSender = context.getResultSender();
-
-    InternalCache cache = (InternalCache) context.getCache();
-    String memberNameOrId =
-        
CliUtil.getMemberNameOrId(cache.getDistributedSystem().getDistributedMember());
-
-    ConnectionConfiguration connectionConfig = context.getArguments();
-
     try {
-      InternalJdbcConnectorService service = 
cache.getService(InternalJdbcConnectorService.class);
-      service.createConnectionConfig(connectionConfig);
+      // input
+      ConnectionConfiguration connectionConfig = context.getArguments();
+      InternalJdbcConnectorService service = 
argumentProvider.getJdbcConnectorService(context);
 
-      XmlEntity xmlEntity = new XmlEntity(CacheXml.CACHE, 
JdbcConnectorServiceXmlGenerator.PREFIX,
-          JdbcConnectorServiceXmlParser.NAMESPACE, 
ElementType.CONNECTION_SERVICE.getTypeName());
+      // action
+      createConnectionConfig(service, connectionConfig);
 
-      resultSender.lastResult(new CliFunctionResult(memberNameOrId, xmlEntity,
-          "Created JDBC connection " + connectionConfig.getName() + " on " + 
memberNameOrId));
+      // output
+      String member = argumentProvider.getMember(context);
+      XmlEntity xmlEntity = argumentProvider.createXmlEntity(context);
+      CliFunctionResult result = 
createSuccessResult(connectionConfig.getName(), member, xmlEntity);
+      context.getResultSender().lastResult(result);
 
     } catch (Exception e) {
-      String exceptionMsg = e.getMessage();
-      if (exceptionMsg == null) {
-        exceptionMsg = CliUtil.stackTraceAsString(e);
-      }
-      resultSender.lastResult(exceptionHandler.handleException(memberNameOrId, 
exceptionMsg, e));
+      exceptionHandler.handleException(context, e);
     }
   }
+
+  /**
+   * Creates the named connection configuration
+   */
+  void createConnectionConfig(InternalJdbcConnectorService service,
+      ConnectionConfiguration connectionConfig) throws 
ConnectionConfigExistsException {
+    service.createConnectionConfig(connectionConfig);
+  }
+
+  private CliFunctionResult createSuccessResult(String connectionName, String 
member,
+      XmlEntity xmlEntity) {
+    String message = "Created JDBC connection " + connectionName + " on " + 
member;
+    return new CliFunctionResult(member, xmlEntity, message);
+  }
 }
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 04217f4..66ce393 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
@@ -22,6 +22,7 @@ import org.springframework.shell.core.annotation.CliCommand;
 import org.springframework.shell.core.annotation.CliOption;
 
 import org.apache.geode.cache.execute.ResultCollector;
+import org.apache.geode.connectors.jdbc.internal.ConnectionConfiguration;
 import org.apache.geode.distributed.DistributedMember;
 import org.apache.geode.management.cli.CliMetaData;
 import org.apache.geode.management.cli.Result;
@@ -45,44 +46,67 @@ public class DestroyConnectionCommand implements 
GfshCommand {
   private static final String ERROR_PREFIX = "ERROR: ";
 
   @CliCommand(value = DESTROY_CONNECTION, help = DESTROY_CONNECTION__HELP)
-  @CliMetaData(relatedTopic = CliStrings.TOPIC_GEODE_REGION)
+  @CliMetaData(relatedTopic = CliStrings.DEFAULT_TOPIC_GEODE)
   @ResourceOperation(resource = ResourcePermission.Resource.CLUSTER,
       operation = ResourcePermission.Operation.MANAGE)
   public Result destroyConnection(@CliOption(key = DESTROY_CONNECTION__NAME, 
mandatory = true,
       help = DESTROY_CONNECTION__NAME__HELP) String name) {
 
-    Set<DistributedMember> membersToDestroyConnectionOn = getMembers(null, 
null);
+    // input
+    Set<DistributedMember> targetMembers = getMembers(null, null);
 
-    ResultCollector<?, ?> resultCollector =
-        executeFunction(new DestroyConnectionFunction(), name, 
membersToDestroyConnectionOn);
+    // action
+    ResultCollector<CliFunctionResult, List<CliFunctionResult>> 
resultCollector =
+        execute(new DestroyConnectionFunction(), name, targetMembers);
 
-    Object resultCollectorResult = resultCollector.getResult();
+    // output
+    TabularResultData tabularResultData = 
ResultBuilder.createTabularResultData();
+    XmlEntity xmlEntity = fillTabularResultData(resultCollector, 
tabularResultData);
+    Result result = ResultBuilder.buildResult(tabularResultData);
+    updateClusterConfiguration(result, xmlEntity);
+    return result;
+  }
 
-    List<CliFunctionResult> connectionDestroyResults =
-        (List<CliFunctionResult>) resultCollectorResult;
+  ResultCollector<CliFunctionResult, List<CliFunctionResult>> execute(
+      DestroyConnectionFunction function, String connectionName,
+      Set<DistributedMember> targetMembers) {
+    return (ResultCollector<CliFunctionResult, List<CliFunctionResult>>) 
executeFunction(function,
+        connectionName, targetMembers);
+  }
 
-    AtomicReference<XmlEntity> xmlEntity = new AtomicReference<>();
-    TabularResultData tabularResultData = 
ResultBuilder.createTabularResultData();
-    for (CliFunctionResult connectionDestroyResult : connectionDestroyResults) 
{
-      boolean success = connectionDestroyResult.isSuccessful();
-      tabularResultData.accumulate("Member", 
connectionDestroyResult.getMemberIdOrName());
-      tabularResultData.accumulate("Status",
-          (success ? "" : ERROR_PREFIX) + 
connectionDestroyResult.getMessage());
-
-      if (success) {
-        xmlEntity.set(connectionDestroyResult.getXmlEntity());
+  private XmlEntity fillTabularResultData(
+      ResultCollector<CliFunctionResult, List<CliFunctionResult>> 
resultCollector,
+      TabularResultData tabularResultData) {
+    XmlEntity xmlEntity = null;
+
+    for (CliFunctionResult oneResult : resultCollector.getResult()) {
+      if (oneResult.isSuccessful()) {
+        xmlEntity = addSuccessToResults(tabularResultData, oneResult);
       } else {
-        tabularResultData.setStatus(Result.Status.ERROR);
+        addErrorToResults(tabularResultData, oneResult);
       }
     }
 
-    Result result = ResultBuilder.buildResult(tabularResultData);
+    return xmlEntity;
+  }
+
+  private XmlEntity addSuccessToResults(TabularResultData tabularResultData,
+      CliFunctionResult oneResult) {
+    tabularResultData.accumulate("Member", oneResult.getMemberIdOrName());
+    tabularResultData.accumulate("Status", oneResult.getMessage());
+    return oneResult.getXmlEntity();
+  }
 
-    if (xmlEntity.get() != null) {
+  private void addErrorToResults(TabularResultData tabularResultData, 
CliFunctionResult oneResult) {
+    tabularResultData.accumulate("Member", oneResult.getMemberIdOrName());
+    tabularResultData.accumulate("Status", ERROR_PREFIX + 
oneResult.getMessage());
+    tabularResultData.setStatus(Result.Status.ERROR);
+  }
+
+  private void updateClusterConfiguration(final Result result, final XmlEntity 
xmlEntity) {
+    if (xmlEntity != null) {
       persistClusterConfiguration(result,
-          () -> getSharedConfiguration().addXmlEntity(xmlEntity.get(), null));
+          () -> getSharedConfiguration().addXmlEntity(xmlEntity, null));
     }
-
-    return result;
   }
 }
diff --git 
a/geode-connectors/src/main/java/org/apache/geode/connectors/jdbc/internal/cli/DestroyConnectionFunction.java
 
b/geode-connectors/src/main/java/org/apache/geode/connectors/jdbc/internal/cli/DestroyConnectionFunction.java
index e0886cc..88b673a 100644
--- 
a/geode-connectors/src/main/java/org/apache/geode/connectors/jdbc/internal/cli/DestroyConnectionFunction.java
+++ 
b/geode-connectors/src/main/java/org/apache/geode/connectors/jdbc/internal/cli/DestroyConnectionFunction.java
@@ -16,30 +16,26 @@ package org.apache.geode.connectors.jdbc.internal.cli;
 
 import org.apache.geode.cache.execute.Function;
 import org.apache.geode.cache.execute.FunctionContext;
-import org.apache.geode.cache.execute.ResultSender;
+import org.apache.geode.connectors.jdbc.internal.ConnectionConfiguration;
 import org.apache.geode.connectors.jdbc.internal.InternalJdbcConnectorService;
-import org.apache.geode.connectors.jdbc.internal.xml.ElementType;
-import 
org.apache.geode.connectors.jdbc.internal.xml.JdbcConnectorServiceXmlGenerator;
-import 
org.apache.geode.connectors.jdbc.internal.xml.JdbcConnectorServiceXmlParser;
 import org.apache.geode.internal.InternalEntity;
-import org.apache.geode.internal.cache.InternalCache;
-import org.apache.geode.internal.cache.xmlcache.CacheXml;
-import org.apache.geode.management.internal.cli.CliUtil;
 import org.apache.geode.management.internal.cli.functions.CliFunctionResult;
-import org.apache.geode.management.internal.cli.i18n.CliStrings;
 import org.apache.geode.management.internal.configuration.domain.XmlEntity;
 
 public class DestroyConnectionFunction implements Function<String>, 
InternalEntity {
 
   private static final String ID = DestroyConnectionFunction.class.getName();
 
-  private final transient ExceptionHandler exceptionHandler;
+  private final FunctionContextArgumentProvider argumentProvider;
+  private final ExceptionHandler exceptionHandler;
 
   public DestroyConnectionFunction() {
-    this(new ExceptionHandler());
+    this(new FunctionContextArgumentProvider(), new ExceptionHandler());
   }
 
-  private DestroyConnectionFunction(ExceptionHandler exceptionHandler) {
+  private DestroyConnectionFunction(FunctionContextArgumentProvider 
jdbcCommandFunctionContext,
+      ExceptionHandler exceptionHandler) {
+    this.argumentProvider = jdbcCommandFunctionContext;
     this.exceptionHandler = exceptionHandler;
   }
 
@@ -55,37 +51,59 @@ public class DestroyConnectionFunction implements 
Function<String>, InternalEnti
 
   @Override
   public void execute(FunctionContext<String> context) {
-    ResultSender<Object> resultSender = context.getResultSender();
+    try {
+      // input
+      InternalJdbcConnectorService service = 
argumentProvider.getJdbcConnectorService(context);
+      String connectionName = context.getArguments();
 
-    InternalCache cache = (InternalCache) context.getCache();
-    String memberNameOrId =
-        
CliUtil.getMemberNameOrId(cache.getDistributedSystem().getDistributedMember());
+      // action
+      boolean success = destroyConnectionConfig(service, connectionName);
 
-    String connectionName = context.getArguments();
+      // output
+      String member = argumentProvider.getMember(context);
+      CliFunctionResult result = createResult(success, context, member, 
connectionName);
+      context.getResultSender().lastResult(result);
 
-    try {
-      InternalJdbcConnectorService service = 
cache.getService(InternalJdbcConnectorService.class);
+    } catch (Exception e) {
+      exceptionHandler.handleException(context, e);
+    }
+  }
 
-      if (service.getConnectionConfig(connectionName) == null) {
-        resultSender.lastResult(new CliFunctionResult(memberNameOrId, false,
-            CliStrings.format("Connection named \"{0}\" not found", 
connectionName)));
+  /**
+   * Destroys the named connection configuration
+   *
+   * @return true if the connection was found and destroyed
+   */
+  boolean destroyConnectionConfig(InternalJdbcConnectorService service, String 
connectionName) {
+    ConnectionConfiguration connectionConfig = 
service.getConnectionConfig(connectionName);
+    if (connectionConfig != null) {
+      service.destroyConnectionConfig(connectionName);
+      return true;
+    }
+    return false;
+  }
 
-      } else {
-        service.destroyConnectionConfig(connectionName);
+  private CliFunctionResult createResult(boolean success, FunctionContext<?> 
context, String member,
+      String connectionName) {
+    CliFunctionResult result;
+    if (success) {
+      XmlEntity xmlEntity = argumentProvider.createXmlEntity(context);
+      result = createSuccessResult(member, connectionName, xmlEntity);
 
-        XmlEntity xmlEntity = new XmlEntity(CacheXml.CACHE, 
JdbcConnectorServiceXmlGenerator.PREFIX,
-            JdbcConnectorServiceXmlParser.NAMESPACE, 
ElementType.CONNECTION_SERVICE.getTypeName());
+    } else {
+      result = createNotFoundResult(member, connectionName);
+    }
+    return result;
+  }
 
-        resultSender.lastResult(new CliFunctionResult(memberNameOrId, 
xmlEntity,
-            "Destroyed JDBC connection " + connectionName + " on " + 
memberNameOrId));
-      }
+  private CliFunctionResult createSuccessResult(String member, String 
connectionName,
+      XmlEntity xmlEntity) {
+    String message = "Destroyed JDBC connection \"" + connectionName + "\" on 
" + member;
+    return new CliFunctionResult(member, xmlEntity, message);
+  }
 
-    } catch (Exception e) {
-      String exceptionMsg = e.getMessage();
-      if (exceptionMsg == null) {
-        exceptionMsg = CliUtil.stackTraceAsString(e);
-      }
-      resultSender.lastResult(exceptionHandler.handleException(memberNameOrId, 
exceptionMsg, e));
-    }
+  private CliFunctionResult createNotFoundResult(String member, String 
connectionName) {
+    String message = "Connection named \"" + connectionName + "\" not found";
+    return new CliFunctionResult(member, false, message);
   }
 }
diff --git 
a/geode-connectors/src/main/java/org/apache/geode/connectors/jdbc/internal/cli/ExceptionHandler.java
 
b/geode-connectors/src/main/java/org/apache/geode/connectors/jdbc/internal/cli/ExceptionHandler.java
index 8e44ec7..3291fba 100644
--- 
a/geode-connectors/src/main/java/org/apache/geode/connectors/jdbc/internal/cli/ExceptionHandler.java
+++ 
b/geode-connectors/src/main/java/org/apache/geode/connectors/jdbc/internal/cli/ExceptionHandler.java
@@ -14,23 +14,51 @@
  */
 package org.apache.geode.connectors.jdbc.internal.cli;
 
+import java.io.Serializable;
+
 import org.apache.logging.log4j.Logger;
 
+import org.apache.geode.cache.Cache;
+import org.apache.geode.cache.execute.FunctionContext;
+import 
org.apache.geode.distributed.internal.membership.InternalDistributedMember;
+import org.apache.geode.internal.cache.InternalCache;
 import org.apache.geode.internal.logging.LogService;
+import org.apache.geode.management.internal.cli.CliUtil;
 import org.apache.geode.management.internal.cli.functions.CliFunctionResult;
 
-class ExceptionHandler {
+/**
+ * Handles exceptions by returning an error result to GFSH
+ */
+class ExceptionHandler implements Serializable {
   private static final Logger logger = LogService.getLogger();
 
-  CliFunctionResult handleException(final String memberNameOrId, final String 
exceptionMsg,
-      final Exception e) {
-    if (e != null && logger.isDebugEnabled()) {
-      logger.debug(e.getMessage(), e);
-    }
-    if (exceptionMsg != null) {
-      return new CliFunctionResult(memberNameOrId, false, exceptionMsg);
+  void handleException(final FunctionContext<?> context, final Exception 
exception) {
+    String message = getExceptionMessage(exception);
+    String member = getMember(context.getCache());
+    context.getResultSender().lastResult(handleException(member, message, 
exception));
+  }
+
+  private CliFunctionResult handleException(final String memberNameOrId, final 
String exceptionMsg,
+      final Exception exception) {
+    if (exception != null && logger.isDebugEnabled()) {
+      logger.debug(exception.getMessage(), exception);
     }
+    // if (exceptionMsg != null) {
+    return new CliFunctionResult(memberNameOrId, false, exceptionMsg);
+    // }
+    //
+    // return new CliFunctionResult(memberNameOrId);
+  }
+
+  private String getMember(final Cache cache) {
+    return 
CliUtil.getMemberNameOrId(cache.getDistributedSystem().getDistributedMember());
+  }
 
-    return new CliFunctionResult(memberNameOrId);
+  private String getExceptionMessage(final Exception exception) {
+    String message = exception.getMessage();
+    if (message == null) {
+      message = CliUtil.stackTraceAsString(exception);
+    }
+    return message;
   }
 }
diff --git 
a/geode-connectors/src/main/java/org/apache/geode/connectors/jdbc/internal/cli/FunctionContextArgumentProvider.java
 
b/geode-connectors/src/main/java/org/apache/geode/connectors/jdbc/internal/cli/FunctionContextArgumentProvider.java
new file mode 100644
index 0000000..92ed00f
--- /dev/null
+++ 
b/geode-connectors/src/main/java/org/apache/geode/connectors/jdbc/internal/cli/FunctionContextArgumentProvider.java
@@ -0,0 +1,73 @@
+/*
+ * 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.connectors.jdbc.internal.cli;
+
+import static 
org.apache.geode.connectors.jdbc.internal.xml.ElementType.CONNECTION_SERVICE;
+import static 
org.apache.geode.connectors.jdbc.internal.xml.JdbcConnectorServiceXmlGenerator.PREFIX;
+import static 
org.apache.geode.connectors.jdbc.internal.xml.JdbcConnectorServiceXmlParser.NAMESPACE;
+import static org.apache.geode.internal.cache.xmlcache.CacheXml.CACHE;
+
+import java.io.Serializable;
+
+import org.apache.geode.cache.execute.FunctionContext;
+import org.apache.geode.connectors.jdbc.internal.InternalJdbcConnectorService;
+import org.apache.geode.connectors.jdbc.internal.xml.ElementType;
+import 
org.apache.geode.connectors.jdbc.internal.xml.JdbcConnectorServiceXmlGenerator;
+import 
org.apache.geode.connectors.jdbc.internal.xml.JdbcConnectorServiceXmlParser;
+import org.apache.geode.internal.cache.InternalCache;
+import org.apache.geode.internal.cache.xmlcache.CacheXml;
+import org.apache.geode.management.internal.cli.CliUtil;
+import org.apache.geode.management.internal.configuration.domain.XmlEntity;
+
+/**
+ * Provides JDBC command dependencies provided in the FunctionContext
+ */
+class FunctionContextArgumentProvider implements Serializable {
+
+  static InternalCache getCacheFromContext(FunctionContext<?> context) {
+    return (InternalCache) context.getCache();
+  }
+
+  static String getMemberFromContext(FunctionContext<?> context) {
+    InternalCache cache = getCacheFromContext(context);
+    return 
CliUtil.getMemberNameOrId(cache.getDistributedSystem().getDistributedMember());
+  }
+
+  /**
+   * Returns the JdbcConnectorService
+   */
+  InternalJdbcConnectorService getJdbcConnectorService(FunctionContext<?> 
context) {
+    return 
getCacheFromContext(context).getService(InternalJdbcConnectorService.class);
+  }
+
+  /**
+   * Returns the name of the distributed member or its id if it has no name
+   */
+  String getMember(FunctionContext<?> context) {
+    return getMemberFromContext(context);
+  }
+
+  /**
+   * Returns XmlEntity for JdbcConnectorServiceXmlGenerator snippet of cache 
xml
+   */
+  XmlEntity createXmlEntity(FunctionContext<?> context) {
+    return new XmlEntity(createCacheProvider(context), CACHE, PREFIX, 
NAMESPACE,
+        CONNECTION_SERVICE.getTypeName());
+  }
+
+  private XmlEntity.CacheProvider createCacheProvider(FunctionContext<?> 
context) {
+    return () -> getCacheFromContext(context);
+  }
+}
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
new file mode 100644
index 0000000..f78191a
--- /dev/null
+++ 
b/geode-connectors/src/main/java/org/apache/geode/connectors/jdbc/internal/cli/ListConnectionCommand.java
@@ -0,0 +1,105 @@
+/*
+ * 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.connectors.jdbc.internal.cli;
+
+import java.util.Arrays;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Set;
+
+import org.springframework.shell.core.annotation.CliCommand;
+
+import org.apache.geode.cache.execute.ResultCollector;
+import org.apache.geode.connectors.jdbc.internal.ConnectionConfiguration;
+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.GfshCommand;
+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;
+import org.apache.geode.management.internal.security.ResourceOperation;
+import org.apache.geode.security.ResourcePermission;
+
+public class ListConnectionCommand implements GfshCommand {
+
+  static final String LIST_JDBC_CONNECTION = "list jdbc-connection";
+  static final String LIST_JDBC_CONNECTION__HELP = "Display jdbc connections 
for all members.";
+
+  static final String LIST_OF_CONNECTIONS = "List of connections";
+  static final String NO_CONNECTIONS_FOUND = "No connections found";
+
+  @CliCommand(value = LIST_JDBC_CONNECTION, help = LIST_JDBC_CONNECTION__HELP)
+  @CliMetaData(relatedTopic = CliStrings.DEFAULT_TOPIC_GEODE)
+  @ResourceOperation(resource = ResourcePermission.Resource.CLUSTER,
+      operation = ResourcePermission.Operation.MANAGE)
+  public Result listConnection() {
+
+    // input
+    Set<DistributedMember> targetMembers = getMembers(null, null);
+    if (targetMembers.isEmpty()) {
+      return 
ResultBuilder.createUserErrorResult(CliStrings.NO_MEMBERS_FOUND_MESSAGE);
+    }
+
+    // action
+    ResultCollector<ConnectionConfiguration, List<ConnectionConfiguration[]>> 
resultCollector =
+        execute(new ListConnectionFunction(), targetMembers.iterator().next());
+
+    // output
+    TabularResultData tabularResultData = 
ResultBuilder.createTabularResultData();
+    boolean connectionsExist = fillTabularResultData(resultCollector, 
tabularResultData);
+    return createResult(tabularResultData, connectionsExist);
+  }
+
+  ResultCollector<ConnectionConfiguration, List<ConnectionConfiguration[]>> 
execute(
+      ListConnectionFunction function, DistributedMember targetMember) {
+    return (ResultCollector<ConnectionConfiguration, 
List<ConnectionConfiguration[]>>) executeFunction(
+        function, null, targetMember);
+  }
+
+  private Result createResult(TabularResultData tabularResultData, boolean 
connectionsExist) {
+    if (connectionsExist) {
+      return ResultBuilder.buildResult(tabularResultData);
+
+    } else {
+      return ResultBuilder.createInfoResult(NO_CONNECTIONS_FOUND);
+    }
+  }
+
+  /**
+   * Returns true if any connections exist
+   */
+  private boolean fillTabularResultData(
+      ResultCollector<ConnectionConfiguration, 
List<ConnectionConfiguration[]>> resultCollector,
+      TabularResultData tabularResultData) {
+    Set<ConnectionConfiguration> connectionConfigs = new HashSet<>();
+
+    for (Object resultObject : resultCollector.getResult()) {
+      if (resultObject instanceof ConnectionConfiguration[]) {
+        connectionConfigs.addAll(Arrays.asList((ConnectionConfiguration[]) 
resultObject));
+      } else if (resultObject instanceof Throwable) {
+        throw new IllegalStateException((Throwable) resultObject);
+      } else {
+        throw new IllegalStateException(resultObject.getClass().getName());
+      }
+    }
+
+    for (ConnectionConfiguration connectionConfig : connectionConfigs) {
+      tabularResultData.accumulate(LIST_OF_CONNECTIONS, 
connectionConfig.getName());
+    }
+
+    return !connectionConfigs.isEmpty();
+  }
+}
diff --git 
a/geode-connectors/src/main/java/org/apache/geode/connectors/jdbc/internal/cli/ListConnectionFunction.java
 
b/geode-connectors/src/main/java/org/apache/geode/connectors/jdbc/internal/cli/ListConnectionFunction.java
new file mode 100644
index 0000000..cd14ab9
--- /dev/null
+++ 
b/geode-connectors/src/main/java/org/apache/geode/connectors/jdbc/internal/cli/ListConnectionFunction.java
@@ -0,0 +1,77 @@
+/*
+ * 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.connectors.jdbc.internal.cli;
+
+import java.util.Set;
+
+import org.apache.geode.cache.execute.Function;
+import org.apache.geode.cache.execute.FunctionContext;
+import org.apache.geode.connectors.jdbc.internal.ConnectionConfiguration;
+import org.apache.geode.connectors.jdbc.internal.InternalJdbcConnectorService;
+import org.apache.geode.internal.InternalEntity;
+
+public class ListConnectionFunction implements Function<Void>, InternalEntity {
+
+  private static final String ID = ListConnectionFunction.class.getName();
+
+  private final FunctionContextArgumentProvider argumentProvider;
+  private final ExceptionHandler exceptionHandler;
+
+  public ListConnectionFunction() {
+    this(new FunctionContextArgumentProvider(), new ExceptionHandler());
+  }
+
+  private ListConnectionFunction(FunctionContextArgumentProvider 
jdbcCommandFunctionContext,
+      ExceptionHandler exceptionHandler) {
+    this.argumentProvider = jdbcCommandFunctionContext;
+    this.exceptionHandler = exceptionHandler;
+  }
+
+  @Override
+  public boolean isHA() {
+    return false;
+  }
+
+  @Override
+  public String getId() {
+    return ID;
+  }
+
+  @Override
+  public void execute(FunctionContext<Void> context) {
+    try {
+      // input
+      InternalJdbcConnectorService service = 
argumentProvider.getJdbcConnectorService(context);
+
+      // action
+      ConnectionConfiguration[] connectionConfigs = 
getConnectionConfigAsArray(service);
+
+      // output
+      context.getResultSender().lastResult(connectionConfigs);
+
+    } catch (Exception e) {
+      exceptionHandler.handleException(context, e);
+    }
+  }
+
+  ConnectionConfiguration[] 
getConnectionConfigAsArray(InternalJdbcConnectorService service) {
+    Set<ConnectionConfiguration> connectionConfigs = 
getConnectionConfigs(service);
+    return connectionConfigs.toArray(new 
ConnectionConfiguration[connectionConfigs.size()]);
+  }
+
+  private Set<ConnectionConfiguration> 
getConnectionConfigs(InternalJdbcConnectorService service) {
+    return service.getConnectionConfigs();
+  }
+}
diff --git 
a/geode-connectors/src/main/java/org/apache/geode/connectors/jdbc/internal/xml/JdbcServiceConfiguration.java
 
b/geode-connectors/src/main/java/org/apache/geode/connectors/jdbc/internal/xml/JdbcServiceConfiguration.java
index 4c19b2b..6de0734 100644
--- 
a/geode-connectors/src/main/java/org/apache/geode/connectors/jdbc/internal/xml/JdbcServiceConfiguration.java
+++ 
b/geode-connectors/src/main/java/org/apache/geode/connectors/jdbc/internal/xml/JdbcServiceConfiguration.java
@@ -17,7 +17,9 @@ package org.apache.geode.connectors.jdbc.internal.xml;
 import java.util.ArrayList;
 import java.util.List;
 
+import org.apache.geode.InternalGemFireException;
 import org.apache.geode.cache.Cache;
+import 
org.apache.geode.connectors.jdbc.internal.ConnectionConfigExistsException;
 import org.apache.geode.connectors.jdbc.internal.ConnectionConfiguration;
 import org.apache.geode.connectors.jdbc.internal.InternalJdbcConnectorService;
 import org.apache.geode.connectors.jdbc.internal.RegionMapping;
@@ -54,7 +56,16 @@ public class JdbcServiceConfiguration implements 
Extension<Cache> {
     InternalCache internalCache = (InternalCache) target;
     InternalJdbcConnectorService service =
         internalCache.getService(InternalJdbcConnectorService.class);
-    connections.forEach(connection -> 
service.createConnectionConfig(connection));
+    connections.forEach(connection -> createConnectionConfig(service, 
connection));
     mappings.forEach(mapping -> service.addOrUpdateRegionMapping(mapping));
   }
+
+  private void createConnectionConfig(InternalJdbcConnectorService service,
+      ConnectionConfiguration connectionConfig) {
+    try {
+      service.createConnectionConfig(connectionConfig);
+    } catch (ConnectionConfigExistsException e) {
+      throw new InternalGemFireException(e);
+    }
+  }
 }
diff --git 
a/geode-connectors/src/main/resources/META-INF/services/org.springframework.shell.core.CommandMarker
 
b/geode-connectors/src/main/resources/META-INF/services/org.springframework.shell.core.CommandMarker
index 5ec0430..60e3207 100644
--- 
a/geode-connectors/src/main/resources/META-INF/services/org.springframework.shell.core.CommandMarker
+++ 
b/geode-connectors/src/main/resources/META-INF/services/org.springframework.shell.core.CommandMarker
@@ -17,3 +17,4 @@
 # Lucene Extensions command
 org.apache.geode.connectors.jdbc.internal.cli.CreateConnectionCommand
 org.apache.geode.connectors.jdbc.internal.cli.DestroyConnectionCommand
+org.apache.geode.connectors.jdbc.internal.cli.ListConnectionCommand
diff --git 
a/geode-connectors/src/test/java/org/apache/geode/connectors/jdbc/JdbcAsyncWriterIntegrationTest.java
 
b/geode-connectors/src/test/java/org/apache/geode/connectors/jdbc/JdbcAsyncWriterIntegrationTest.java
index 1655bd9..e7e9819 100644
--- 
a/geode-connectors/src/test/java/org/apache/geode/connectors/jdbc/JdbcAsyncWriterIntegrationTest.java
+++ 
b/geode-connectors/src/test/java/org/apache/geode/connectors/jdbc/JdbcAsyncWriterIntegrationTest.java
@@ -34,6 +34,7 @@ import org.apache.geode.cache.Cache;
 import org.apache.geode.cache.CacheFactory;
 import org.apache.geode.cache.Region;
 import org.apache.geode.cache.RegionFactory;
+import 
org.apache.geode.connectors.jdbc.internal.ConnectionConfigExistsException;
 import org.apache.geode.connectors.jdbc.internal.SqlHandler;
 import org.apache.geode.connectors.jdbc.internal.TestConfigService;
 import org.apache.geode.connectors.jdbc.internal.TestableConnectionManager;
@@ -230,7 +231,8 @@ public class JdbcAsyncWriterIntegrationTest {
     assertThat(resultSet.getObject("age")).isEqualTo(employee.getAge());
   }
 
-  private Region<String, PdxInstance> createRegionWithJDBCAsyncWriter(String 
regionName) {
+  private Region<String, PdxInstance> createRegionWithJDBCAsyncWriter(String 
regionName)
+      throws ConnectionConfigExistsException {
     jdbcWriter = new JdbcAsyncWriter(createSqlHandler());
     
cache.createAsyncEventQueueFactory().setBatchSize(1).setBatchTimeInterval(1)
         .create("jdbcAsyncQueue", jdbcWriter);
@@ -247,7 +249,7 @@ public class JdbcAsyncWriterIntegrationTest {
     assertThat(size).isEqualTo(expected);
   }
 
-  private SqlHandler createSqlHandler() {
+  private SqlHandler createSqlHandler() throws ConnectionConfigExistsException 
{
     return new SqlHandler(new 
TestableConnectionManager(TestConfigService.getTestConfigService()));
   }
 
diff --git 
a/geode-connectors/src/test/java/org/apache/geode/connectors/jdbc/JdbcLoaderIntegrationTest.java
 
b/geode-connectors/src/test/java/org/apache/geode/connectors/jdbc/JdbcLoaderIntegrationTest.java
index 1dbd693..44777bb 100644
--- 
a/geode-connectors/src/test/java/org/apache/geode/connectors/jdbc/JdbcLoaderIntegrationTest.java
+++ 
b/geode-connectors/src/test/java/org/apache/geode/connectors/jdbc/JdbcLoaderIntegrationTest.java
@@ -31,6 +31,7 @@ import org.apache.geode.cache.Cache;
 import org.apache.geode.cache.CacheFactory;
 import org.apache.geode.cache.Region;
 import org.apache.geode.cache.RegionFactory;
+import 
org.apache.geode.connectors.jdbc.internal.ConnectionConfigExistsException;
 import org.apache.geode.connectors.jdbc.internal.SqlHandler;
 import org.apache.geode.connectors.jdbc.internal.TestConfigService;
 import org.apache.geode.connectors.jdbc.internal.TestableConnectionManager;
@@ -49,7 +50,7 @@ public class JdbcLoaderIntegrationTest {
   private Statement statement;
 
   @Before
-  public void setup() throws Exception {
+  public void setUp() throws Exception {
     cache = new CacheFactory().setPdxReadSerialized(false).create();
     connection = DriverManager.getConnection(CONNECTION_URL);
     statement = connection.createStatement();
@@ -76,7 +77,7 @@ public class JdbcLoaderIntegrationTest {
   }
 
   @Test
-  public void verifySimpleGet() throws SQLException {
+  public void verifySimpleGet() throws Exception {
     statement.execute("Insert into " + REGION_TABLE_NAME + " values('1', 
'Emp1', 21)");
     Region<String, PdxInstance> region = 
createRegionWithJDBCLoader(REGION_TABLE_NAME);
     PdxInstance pdx = region.get("1");
@@ -86,17 +87,18 @@ public class JdbcLoaderIntegrationTest {
   }
 
   @Test
-  public void verifySimpleMiss() throws SQLException {
+  public void verifySimpleMiss() throws Exception {
     Region<String, PdxInstance> region = 
createRegionWithJDBCLoader(REGION_TABLE_NAME);
     PdxInstance pdx = region.get("1");
     assertThat(pdx).isNull();
   }
 
-  private SqlHandler createSqlHandler() {
+  private SqlHandler createSqlHandler() throws ConnectionConfigExistsException 
{
     return new SqlHandler(new 
TestableConnectionManager(TestConfigService.getTestConfigService()));
   }
 
-  private Region<String, PdxInstance> createRegionWithJDBCLoader(String 
regionName) {
+  private Region<String, PdxInstance> createRegionWithJDBCLoader(String 
regionName)
+      throws ConnectionConfigExistsException {
     JdbcLoader<String, PdxInstance> jdbcLoader = new 
JdbcLoader<>(createSqlHandler());
     RegionFactory<String, PdxInstance> regionFactory = 
cache.createRegionFactory(REPLICATE);
     regionFactory.setCacheLoader(jdbcLoader);
diff --git 
a/geode-connectors/src/test/java/org/apache/geode/connectors/jdbc/JdbcWriterIntegrationTest.java
 
b/geode-connectors/src/test/java/org/apache/geode/connectors/jdbc/JdbcWriterIntegrationTest.java
index e26b3ee..8d76f07 100644
--- 
a/geode-connectors/src/test/java/org/apache/geode/connectors/jdbc/JdbcWriterIntegrationTest.java
+++ 
b/geode-connectors/src/test/java/org/apache/geode/connectors/jdbc/JdbcWriterIntegrationTest.java
@@ -37,6 +37,7 @@ import org.apache.geode.cache.CacheFactory;
 import org.apache.geode.cache.Region;
 import org.apache.geode.cache.RegionFactory;
 import org.apache.geode.cache.RegionShortcut;
+import 
org.apache.geode.connectors.jdbc.internal.ConnectionConfigExistsException;
 import org.apache.geode.connectors.jdbc.internal.SqlHandler;
 import org.apache.geode.connectors.jdbc.internal.TestConfigService;
 import org.apache.geode.connectors.jdbc.internal.TestableConnectionManager;
@@ -203,7 +204,8 @@ public class JdbcWriterIntegrationTest {
     assertThat(resultSet.next()).isFalse();
   }
 
-  private Region<String, PdxInstance> 
createRegionWithJDBCSynchronousWriter(String regionName) {
+  private Region<String, PdxInstance> 
createRegionWithJDBCSynchronousWriter(String regionName)
+      throws ConnectionConfigExistsException {
     jdbcWriter = new JdbcWriter(createSqlHandler());
     jdbcWriter.init(new Properties());
 
@@ -220,7 +222,7 @@ public class JdbcWriterIntegrationTest {
     assertThat(size).isEqualTo(expected);
   }
 
-  private SqlHandler createSqlHandler() {
+  private SqlHandler createSqlHandler() throws ConnectionConfigExistsException 
{
     return new SqlHandler(new 
TestableConnectionManager(TestConfigService.getTestConfigService()));
   }
 
diff --git 
a/geode-connectors/src/test/java/org/apache/geode/connectors/jdbc/internal/JdbcConnectorServiceTest.java
 
b/geode-connectors/src/test/java/org/apache/geode/connectors/jdbc/internal/JdbcConnectorServiceTest.java
index da5f923..0a85da9 100644
--- 
a/geode-connectors/src/test/java/org/apache/geode/connectors/jdbc/internal/JdbcConnectorServiceTest.java
+++ 
b/geode-connectors/src/test/java/org/apache/geode/connectors/jdbc/internal/JdbcConnectorServiceTest.java
@@ -40,7 +40,7 @@ public class JdbcConnectorServiceTest {
   private JdbcConnectorService service;
 
   @Before
-  public void setup() {
+  public void setUp() throws Exception {
     InternalCache cache = mock(InternalCache.class);
     config = mock(ConnectionConfiguration.class);
     mapping = mock(RegionMapping.class);
@@ -56,24 +56,24 @@ public class JdbcConnectorServiceTest {
   }
 
   @Test
-  public void returnsNoConfigIfEmpty() {
+  public void returnsNoConfigIfEmpty() throws Exception {
     assertThat(service.getConnectionConfig("foo")).isNull();
   }
 
   @Test
-  public void returnsNoMappingIfEmpty() {
+  public void returnsNoMappingIfEmpty() throws Exception {
     assertThat(service.getMappingForRegion("foo")).isNull();
   }
 
   @Test
-  public void returnsCorrectConfig() {
+  public void returnsCorrectConfig() throws Exception {
     service.createConnectionConfig(config);
 
     assertThat(service.getConnectionConfig(TEST_CONFIG_NAME)).isSameAs(config);
   }
 
   @Test
-  public void doesNotReturnConfigWithDifferentName() {
+  public void doesNotReturnConfigWithDifferentName() throws Exception {
     when(config.getName()).thenReturn("theOtherConfig");
     service.createConnectionConfig(config);
 
@@ -81,14 +81,14 @@ public class JdbcConnectorServiceTest {
   }
 
   @Test
-  public void returnsCorrectMapping() {
+  public void returnsCorrectMapping() throws Exception {
     service.addOrUpdateRegionMapping(mapping);
 
     
assertThat(service.getMappingForRegion(TEST_REGION_NAME)).isSameAs(mapping);
   }
 
   @Test
-  public void doesNotReturnMappingForDifferentRegion() {
+  public void doesNotReturnMappingForDifferentRegion() throws Exception {
     when(mapping.getRegionName()).thenReturn("theOtherMapping");
     service.addOrUpdateRegionMapping(mapping);
 
@@ -96,7 +96,7 @@ public class JdbcConnectorServiceTest {
   }
 
   @Test
-  public void createConnectionConfig_throwsIfConnectionExists() {
+  public void createConnectionConfig_throwsIfConnectionExists() throws 
Exception {
     service.createConnectionConfig(config);
 
     assertThatThrownBy(() -> service.createConnectionConfig(config2))
diff --git 
a/geode-connectors/src/test/java/org/apache/geode/connectors/jdbc/internal/TestConfigService.java
 
b/geode-connectors/src/test/java/org/apache/geode/connectors/jdbc/internal/TestConfigService.java
index ec5c668..4b3235c 100644
--- 
a/geode-connectors/src/test/java/org/apache/geode/connectors/jdbc/internal/TestConfigService.java
+++ 
b/geode-connectors/src/test/java/org/apache/geode/connectors/jdbc/internal/TestConfigService.java
@@ -32,7 +32,7 @@ public class TestConfigService {
   private static final String CONNECTION_URL = "jdbc:derby:memory:" + DB_NAME 
+ ";create=true";
   private static final String CONNECTION_CONFIG_NAME = "testConnectionConfig";
 
-  public static JdbcConnectorService getTestConfigService() {
+  public static JdbcConnectorService getTestConfigService() throws 
ConnectionConfigExistsException {
     InternalCache cache = mock(InternalCache.class);
     when(cache.getExtensionPoint()).thenReturn(mock(ExtensionPoint.class));
 
diff --git 
a/geode-connectors/src/test/java/org/apache/geode/connectors/jdbc/internal/cli/CreateConnectionCommandDUnitTest.java
 
b/geode-connectors/src/test/java/org/apache/geode/connectors/jdbc/internal/cli/CreateConnectionCommandDUnitTest.java
index e1a97fd..7f61b37 100644
--- 
a/geode-connectors/src/test/java/org/apache/geode/connectors/jdbc/internal/cli/CreateConnectionCommandDUnitTest.java
+++ 
b/geode-connectors/src/test/java/org/apache/geode/connectors/jdbc/internal/cli/CreateConnectionCommandDUnitTest.java
@@ -75,7 +75,7 @@ public class CreateConnectionCommandDUnitTest {
     locator.invoke(() -> {
       String xml = 
InternalLocator.getLocator().getSharedConfiguration().getConfiguration("cluster")
           .getCacheXmlContent();
-      assertThat(xml).contains("jdbc:connector-service");
+      assertThat(xml).isNotNull().contains("jdbc:connector-service");
     });
 
     server.invoke(() -> {
diff --git 
a/geode-connectors/src/test/java/org/apache/geode/connectors/jdbc/internal/cli/CreateConnectionFunctionTest.java
 
b/geode-connectors/src/test/java/org/apache/geode/connectors/jdbc/internal/cli/CreateConnectionFunctionTest.java
index 5ab909d..882a8d0 100644
--- 
a/geode-connectors/src/test/java/org/apache/geode/connectors/jdbc/internal/cli/CreateConnectionFunctionTest.java
+++ 
b/geode-connectors/src/test/java/org/apache/geode/connectors/jdbc/internal/cli/CreateConnectionFunctionTest.java
@@ -15,6 +15,7 @@
 package org.apache.geode.connectors.jdbc.internal.cli;
 
 import static org.assertj.core.api.Assertions.assertThat;
+import static org.assertj.core.api.Assertions.assertThatThrownBy;
 import static org.mockito.ArgumentMatchers.eq;
 import static org.mockito.Mockito.doThrow;
 import static org.mockito.Mockito.mock;
@@ -45,29 +46,32 @@ import org.apache.geode.test.junit.categories.UnitTest;
 @Category(UnitTest.class)
 public class CreateConnectionFunctionTest {
 
-  private ConnectionConfiguration configuration;
+  private static final String CONNECTION_NAME = "theConnection";
+
+  private ConnectionConfiguration connectionConfig;
   private FunctionContext<ConnectionConfiguration> context;
-  private InternalJdbcConnectorService service;
+  private DistributedMember distributedMember;
   private ResultSender<Object> resultSender;
+  private InternalJdbcConnectorService service;
 
   private CreateConnectionFunction function;
 
   @Before
-  public void setUp() {
+  public void setUp() throws Exception {
     context = mock(FunctionContext.class);
     resultSender = mock(ResultSender.class);
     InternalCache cache = mock(InternalCache.class);
     DistributedSystem system = mock(DistributedSystem.class);
-    DistributedMember member = mock(DistributedMember.class);
+    distributedMember = mock(DistributedMember.class);
     service = mock(InternalJdbcConnectorService.class);
 
-    configuration = new ConnectionConfigBuilder().build();
+    connectionConfig = new 
ConnectionConfigBuilder().withName(CONNECTION_NAME).build();
 
     when(context.getResultSender()).thenReturn(resultSender);
     when(context.getCache()).thenReturn(cache);
     when(cache.getDistributedSystem()).thenReturn(system);
-    when(system.getDistributedMember()).thenReturn(member);
-    when(context.getArguments()).thenReturn(configuration);
+    when(system.getDistributedMember()).thenReturn(distributedMember);
+    when(context.getArguments()).thenReturn(connectionConfig);
     
when(cache.getService(eq(InternalJdbcConnectorService.class))).thenReturn(service);
 
     function = new CreateConnectionFunction();
@@ -84,31 +88,49 @@ public class CreateConnectionFunctionTest {
   }
 
   @Test
-  public void executeCreatesConnectionIfConfigNotFound() throws Exception {
-    function.execute(context);
+  public void serializes() throws Exception {
+    Serializable original = function;
+
+    Object copy = SerializationUtils.clone(original);
 
-    verify(service, times(1)).createConnectionConfig(configuration);
+    
assertThat(copy).isNotSameAs(original).isInstanceOf(CreateConnectionFunction.class);
+  }
+
+  @Test
+  public void createConnectionConfigReturnsConnectionName() throws Exception {
+    function.createConnectionConfig(service, connectionConfig);
+
+    verify(service, times(1)).createConnectionConfig(connectionConfig);
   }
 
   @Test
-  public void executeReportsErrorIfConnectionConfigFound() throws Exception {
+  public void createConnectionConfigThrowsIfConnectionExists() throws 
Exception {
     doThrow(ConnectionConfigExistsException.class).when(service)
-        .createConnectionConfig(eq(configuration));
+        .createConnectionConfig(eq(connectionConfig));
+
+    assertThatThrownBy(() -> function.createConnectionConfig(service, 
connectionConfig))
+        .isInstanceOf(ConnectionConfigExistsException.class);
+
+    verify(service, times(1)).createConnectionConfig(connectionConfig);
+  }
 
+  @Test
+  public void executeCreatesConnection() throws Exception {
     function.execute(context);
 
-    ArgumentCaptor<CliFunctionResult> argument = 
ArgumentCaptor.forClass(CliFunctionResult.class);
-    verify(resultSender, times(1)).lastResult(argument.capture());
-    assertThat(argument.getValue().getErrorMessage())
-        .contains(ConnectionConfigExistsException.class.getName());
+    verify(service, times(1)).createConnectionConfig(connectionConfig);
   }
 
   @Test
-  public void serializes() throws Exception {
-    Serializable original = function;
+  public void executeReportsErrorIfConnectionConfigExists() throws Exception {
+    doThrow(ConnectionConfigExistsException.class).when(service)
+        .createConnectionConfig(eq(connectionConfig));
 
-    Object copy = SerializationUtils.clone(original);
+    function.execute(context);
 
-    
assertThat(copy).isNotSameAs(original).isInstanceOf(CreateConnectionFunction.class);
+    ArgumentCaptor<CliFunctionResult> argument = 
ArgumentCaptor.forClass(CliFunctionResult.class);
+    verify(resultSender, times(1)).lastResult(argument.capture());
+    assertThat(argument.getValue().getErrorMessage())
+        .contains(ConnectionConfigExistsException.class.getName());
   }
 }
diff --git 
a/geode-connectors/src/test/java/org/apache/geode/connectors/jdbc/internal/cli/DestroyConnectionCommandDUnitTest.java
 
b/geode-connectors/src/test/java/org/apache/geode/connectors/jdbc/internal/cli/DestroyConnectionCommandDUnitTest.java
index 380c6ed..3cb095f 100644
--- 
a/geode-connectors/src/test/java/org/apache/geode/connectors/jdbc/internal/cli/DestroyConnectionCommandDUnitTest.java
+++ 
b/geode-connectors/src/test/java/org/apache/geode/connectors/jdbc/internal/cli/DestroyConnectionCommandDUnitTest.java
@@ -26,6 +26,7 @@ import org.junit.Test;
 import org.junit.experimental.categories.Category;
 
 import org.apache.geode.connectors.jdbc.internal.ConnectionConfigBuilder;
+import 
org.apache.geode.connectors.jdbc.internal.ConnectionConfigExistsException;
 import org.apache.geode.connectors.jdbc.internal.ConnectionConfiguration;
 import org.apache.geode.connectors.jdbc.internal.InternalJdbcConnectorService;
 import org.apache.geode.distributed.internal.InternalLocator;
@@ -87,7 +88,7 @@ public class DestroyConnectionCommandDUnitTest implements 
Serializable {
     });
   }
 
-  private void createConnection() {
+  private void createConnection() throws ConnectionConfigExistsException {
     InternalCache cache = LocatorServerStartupRule.getCache();
     InternalJdbcConnectorService service = 
cache.getService(InternalJdbcConnectorService.class);
 
diff --git 
a/geode-connectors/src/test/java/org/apache/geode/connectors/jdbc/internal/cli/DestroyConnectionCommandIntegrationTest.java
 
b/geode-connectors/src/test/java/org/apache/geode/connectors/jdbc/internal/cli/DestroyConnectionCommandIntegrationTest.java
index d6a8125..eecf9c7 100644
--- 
a/geode-connectors/src/test/java/org/apache/geode/connectors/jdbc/internal/cli/DestroyConnectionCommandIntegrationTest.java
+++ 
b/geode-connectors/src/test/java/org/apache/geode/connectors/jdbc/internal/cli/DestroyConnectionCommandIntegrationTest.java
@@ -33,23 +33,23 @@ import 
org.apache.geode.test.junit.categories.IntegrationTest;
 @Category(IntegrationTest.class)
 public class DestroyConnectionCommandIntegrationTest {
 
-  private String name;
+  private String connectionName;
   private InternalCache cache;
   private ConnectionConfiguration connectionConfig;
 
-  private DestroyConnectionCommand destroyConnectionCommand;
+  private DestroyConnectionCommand command;
 
   @Before
   public void setup() throws Exception {
-    name = "name";
+    connectionName = "connectionName";
 
     String[] params = new String[] {"param1:value1", "param2:value2"};
-    connectionConfig = new 
ConnectionConfigBuilder().withName(name).withUrl("url").withUser("user")
-        .withPassword("password").withParameters(params).build();
+    connectionConfig = new 
ConnectionConfigBuilder().withName(connectionName).withUrl("url")
+        
.withUser("user").withPassword("password").withParameters(params).build();
 
     cache = (InternalCache) new 
CacheFactory().set(ENABLE_CLUSTER_CONFIGURATION, "true").create();
 
-    destroyConnectionCommand = new DestroyConnectionCommand();
+    command = new DestroyConnectionCommand();
   }
 
   @After
@@ -61,22 +61,22 @@ public class DestroyConnectionCommandIntegrationTest {
   public void destroysNamedConnection() throws Exception {
     InternalJdbcConnectorService service = 
cache.getService(InternalJdbcConnectorService.class);
     service.createConnectionConfig(connectionConfig);
-    assertThat(service.getConnectionConfig(name)).isSameAs(connectionConfig);
+    
assertThat(service.getConnectionConfig(connectionName)).isSameAs(connectionConfig);
 
-    Result result = destroyConnectionCommand.destroyConnection(name);
+    Result result = command.destroyConnection(connectionName);
     assertThat(result.getStatus()).isSameAs(Result.Status.OK);
 
-    assertThat(service.getConnectionConfig(name)).isNull();
+    assertThat(service.getConnectionConfig(connectionName)).isNull();
   }
 
   @Test
   public void returnsErrorIfNamedConnectionNotFound() throws Exception {
     InternalJdbcConnectorService service = 
cache.getService(InternalJdbcConnectorService.class);
-    assertThat(service.getConnectionConfig(name)).isNull();
+    assertThat(service.getConnectionConfig(connectionName)).isNull();
 
-    Result result = destroyConnectionCommand.destroyConnection(name);
+    Result result = command.destroyConnection(connectionName);
     assertThat(result.getStatus()).isSameAs(Result.Status.ERROR);
 
-    assertThat(service.getConnectionConfig(name)).isNull();
+    assertThat(service.getConnectionConfig(connectionName)).isNull();
   }
 }
diff --git 
a/geode-connectors/src/test/java/org/apache/geode/connectors/jdbc/internal/cli/DestroyConnectionFunctionTest.java
 
b/geode-connectors/src/test/java/org/apache/geode/connectors/jdbc/internal/cli/DestroyConnectionFunctionTest.java
index b28f499..86b8212 100644
--- 
a/geode-connectors/src/test/java/org/apache/geode/connectors/jdbc/internal/cli/DestroyConnectionFunctionTest.java
+++ 
b/geode-connectors/src/test/java/org/apache/geode/connectors/jdbc/internal/cli/DestroyConnectionFunctionTest.java
@@ -52,7 +52,7 @@ public class DestroyConnectionFunctionTest {
   private InternalJdbcConnectorService service;
 
   @Before
-  public void setUp() {
+  public void setUp() throws Exception {
     InternalCache cache = mock(InternalCache.class);
     context = mock(FunctionContext.class);
     DistributedMember member = mock(DistributedMember.class);
@@ -83,13 +83,24 @@ public class DestroyConnectionFunctionTest {
   }
 
   @Test
-  public void executeReportsErrorIfConnectionConfigNotFound() throws Exception 
{
-    function.execute(context);
+  public void serializes() throws Exception {
+    Serializable original = function;
 
-    ArgumentCaptor<CliFunctionResult> argument = 
ArgumentCaptor.forClass(CliFunctionResult.class);
-    verify(resultSender, times(1)).lastResult(argument.capture());
-    assertThat(argument.getValue().getErrorMessage())
-        .contains("Connection named \"" + connectionName + "\" not found");
+    Object copy = SerializationUtils.clone(original);
+
+    
assertThat(copy).isNotSameAs(original).isInstanceOf(DestroyConnectionFunction.class);
+  }
+
+  @Test
+  public void destroyConnectionConfigReturnsTrueIfConnectionDestroyed() throws 
Exception {
+    
when(service.getConnectionConfig(eq(connectionName))).thenReturn(configuration);
+
+    assertThat(function.destroyConnectionConfig(service, 
connectionName)).isTrue();
+  }
+
+  @Test
+  public void destroyConnectionConfigReturnsFalseIfConnectionDoesNotExist() 
throws Exception {
+    assertThat(function.destroyConnectionConfig(service, 
connectionName)).isFalse();
   }
 
   @Test
@@ -102,11 +113,12 @@ public class DestroyConnectionFunctionTest {
   }
 
   @Test
-  public void serializes() throws Exception {
-    Serializable original = function;
-
-    Object copy = SerializationUtils.clone(original);
+  public void executeReportsErrorIfConnectionConfigNotFound() throws Exception 
{
+    function.execute(context);
 
-    
assertThat(copy).isNotSameAs(original).isInstanceOf(DestroyConnectionFunction.class);
+    ArgumentCaptor<CliFunctionResult> argument = 
ArgumentCaptor.forClass(CliFunctionResult.class);
+    verify(resultSender, times(1)).lastResult(argument.capture());
+    assertThat(argument.getValue().getErrorMessage())
+        .contains("Connection named \"" + connectionName + "\" not found");
   }
 }
diff --git 
a/geode-connectors/src/test/java/org/apache/geode/connectors/jdbc/internal/cli/DestroyConnectionFunctionTest.java
 
b/geode-connectors/src/test/java/org/apache/geode/connectors/jdbc/internal/cli/FunctionContextArgumentProviderTest.java
similarity index 51%
copy from 
geode-connectors/src/test/java/org/apache/geode/connectors/jdbc/internal/cli/DestroyConnectionFunctionTest.java
copy to 
geode-connectors/src/test/java/org/apache/geode/connectors/jdbc/internal/cli/FunctionContextArgumentProviderTest.java
index b28f499..6e86cdf 100644
--- 
a/geode-connectors/src/test/java/org/apache/geode/connectors/jdbc/internal/cli/DestroyConnectionFunctionTest.java
+++ 
b/geode-connectors/src/test/java/org/apache/geode/connectors/jdbc/internal/cli/FunctionContextArgumentProviderTest.java
@@ -17,96 +17,65 @@ package org.apache.geode.connectors.jdbc.internal.cli;
 import static org.assertj.core.api.Assertions.assertThat;
 import static org.mockito.ArgumentMatchers.eq;
 import static org.mockito.Mockito.mock;
-import static org.mockito.Mockito.times;
-import static org.mockito.Mockito.verify;
 import static org.mockito.Mockito.when;
 
-import java.io.Serializable;
-
-import org.apache.commons.lang.SerializationUtils;
 import org.junit.Before;
 import org.junit.Test;
 import org.junit.experimental.categories.Category;
-import org.mockito.ArgumentCaptor;
 
 import org.apache.geode.cache.execute.FunctionContext;
 import org.apache.geode.cache.execute.ResultSender;
-import org.apache.geode.connectors.jdbc.internal.ConnectionConfigBuilder;
-import org.apache.geode.connectors.jdbc.internal.ConnectionConfiguration;
 import org.apache.geode.connectors.jdbc.internal.InternalJdbcConnectorService;
 import org.apache.geode.distributed.DistributedMember;
 import org.apache.geode.distributed.DistributedSystem;
 import org.apache.geode.internal.cache.InternalCache;
-import org.apache.geode.management.internal.cli.functions.CliFunctionResult;
 import org.apache.geode.test.junit.categories.UnitTest;
 
 @Category(UnitTest.class)
-public class DestroyConnectionFunctionTest {
-
-  private static final String connectionName = "connectionName";
+public class FunctionContextArgumentProviderTest {
 
-  private DestroyConnectionFunction function;
-  private FunctionContext<String> context;
+  private FunctionContext<?> context;
+  private DistributedMember distributedMember;
   private ResultSender<Object> resultSender;
-  private ConnectionConfiguration configuration;
   private InternalJdbcConnectorService service;
 
+  private FunctionContextArgumentProvider jdbcCommandFunctionContext;
+
   @Before
   public void setUp() {
-    InternalCache cache = mock(InternalCache.class);
     context = mock(FunctionContext.class);
-    DistributedMember member = mock(DistributedMember.class);
     resultSender = mock(ResultSender.class);
-    service = mock(InternalJdbcConnectorService.class);
+    InternalCache cache = mock(InternalCache.class);
     DistributedSystem system = mock(DistributedSystem.class);
+    distributedMember = mock(DistributedMember.class);
+    service = mock(InternalJdbcConnectorService.class);
 
     when(context.getResultSender()).thenReturn(resultSender);
     when(context.getCache()).thenReturn(cache);
     when(cache.getDistributedSystem()).thenReturn(system);
-    when(system.getDistributedMember()).thenReturn(member);
-    when(context.getArguments()).thenReturn(connectionName);
+    when(system.getDistributedMember()).thenReturn(distributedMember);
     
when(cache.getService(eq(InternalJdbcConnectorService.class))).thenReturn(service);
 
-    configuration = new ConnectionConfigBuilder().build();
-
-    function = new DestroyConnectionFunction();
+    jdbcCommandFunctionContext = new FunctionContextArgumentProvider();
   }
 
   @Test
-  public void isHAReturnsFalse() throws Exception {
-    assertThat(function.isHA()).isFalse();
-  }
+  public void getMemberReturnsMemberNameInsteadOfId() throws Exception {
+    when(distributedMember.getId()).thenReturn("myId");
+    when(distributedMember.getName()).thenReturn("myName");
 
-  @Test
-  public void getIdReturnsNameOfClass() throws Exception {
-    assertThat(function.getId()).isEqualTo(function.getClass().getName());
-  }
-
-  @Test
-  public void executeReportsErrorIfConnectionConfigNotFound() throws Exception 
{
-    function.execute(context);
+    String member = jdbcCommandFunctionContext.getMember(context);
 
-    ArgumentCaptor<CliFunctionResult> argument = 
ArgumentCaptor.forClass(CliFunctionResult.class);
-    verify(resultSender, times(1)).lastResult(argument.capture());
-    assertThat(argument.getValue().getErrorMessage())
-        .contains("Connection named \"" + connectionName + "\" not found");
+    assertThat(member).isEqualTo("myName");
   }
 
   @Test
-  public void executeDestroysIfConnectionConfigFound() throws Exception {
-    
when(service.getConnectionConfig(eq(connectionName))).thenReturn(configuration);
+  public void getMemberReturnsMemberIdIfNameIsMissing() throws Exception {
+    when(distributedMember.getId()).thenReturn("myId");
 
-    function.execute(context);
+    String member = jdbcCommandFunctionContext.getMember(context);
 
-    verify(service, times(1)).destroyConnectionConfig(eq(connectionName));
+    assertThat(member).isEqualTo("myId");
   }
 
-  @Test
-  public void serializes() throws Exception {
-    Serializable original = function;
-
-    Object copy = SerializationUtils.clone(original);
-
-    
assertThat(copy).isNotSameAs(original).isInstanceOf(DestroyConnectionFunction.class);
-  }
 }
diff --git 
a/geode-connectors/src/test/java/org/apache/geode/connectors/jdbc/internal/cli/DestroyConnectionCommandDUnitTest.java
 
b/geode-connectors/src/test/java/org/apache/geode/connectors/jdbc/internal/cli/ListConnectionCommandDUnitTest.java
similarity index 53%
copy from 
geode-connectors/src/test/java/org/apache/geode/connectors/jdbc/internal/cli/DestroyConnectionCommandDUnitTest.java
copy to 
geode-connectors/src/test/java/org/apache/geode/connectors/jdbc/internal/cli/ListConnectionCommandDUnitTest.java
index 380c6ed..12387de 100644
--- 
a/geode-connectors/src/test/java/org/apache/geode/connectors/jdbc/internal/cli/DestroyConnectionCommandDUnitTest.java
+++ 
b/geode-connectors/src/test/java/org/apache/geode/connectors/jdbc/internal/cli/ListConnectionCommandDUnitTest.java
@@ -14,8 +14,8 @@
  */
 package org.apache.geode.connectors.jdbc.internal.cli;
 
-import static 
org.apache.geode.connectors.jdbc.internal.cli.DestroyConnectionCommand.DESTROY_CONNECTION;
-import static 
org.apache.geode.connectors.jdbc.internal.cli.DestroyConnectionCommand.DESTROY_CONNECTION__NAME;
+import static 
org.apache.geode.connectors.jdbc.internal.cli.ListConnectionCommand.LIST_JDBC_CONNECTION;
+import static 
org.apache.geode.connectors.jdbc.internal.cli.ListConnectionCommand.LIST_OF_CONNECTIONS;
 import static org.assertj.core.api.Assertions.assertThat;
 
 import java.io.Serializable;
@@ -26,19 +26,19 @@ import org.junit.Test;
 import org.junit.experimental.categories.Category;
 
 import org.apache.geode.connectors.jdbc.internal.ConnectionConfigBuilder;
-import org.apache.geode.connectors.jdbc.internal.ConnectionConfiguration;
+import 
org.apache.geode.connectors.jdbc.internal.ConnectionConfigExistsException;
 import org.apache.geode.connectors.jdbc.internal.InternalJdbcConnectorService;
-import org.apache.geode.distributed.internal.InternalLocator;
 import org.apache.geode.internal.cache.InternalCache;
 import org.apache.geode.management.internal.cli.util.CommandStringBuilder;
 import org.apache.geode.test.dunit.rules.LocatorServerStartupRule;
 import org.apache.geode.test.dunit.rules.MemberVM;
+import org.apache.geode.test.junit.assertions.CommandResultAssert;
 import org.apache.geode.test.junit.categories.DistributedTest;
 import org.apache.geode.test.junit.rules.GfshCommandRule;
 import org.apache.geode.test.junit.rules.serializable.SerializableTestName;
 
 @Category(DistributedTest.class)
-public class DestroyConnectionCommandDUnitTest implements Serializable {
+public class ListConnectionCommandDUnitTest implements Serializable {
 
   @Rule
   public transient GfshCommandRule gfsh = new GfshCommandRule();
@@ -61,33 +61,45 @@ public class DestroyConnectionCommandDUnitTest implements 
Serializable {
     locator = startupRule.startLocatorVM(0);
     server = startupRule.startServerVM(1, locator.getPort());
 
-    server.invoke(() -> createConnection());
-
     gfsh.connectAndVerify(locator);
   }
 
   @Test
-  public void destroysConnection() throws Exception {
-    CommandStringBuilder csb = new CommandStringBuilder(DESTROY_CONNECTION);
-    csb.addOption(DESTROY_CONNECTION__NAME, "name");
-
-    gfsh.executeAndAssertThat(csb.toString()).statusIsSuccess();
-
-    locator.invoke(() -> {
-      String xml = 
InternalLocator.getLocator().getSharedConfiguration().getConfiguration("cluster")
-          .getCacheXmlContent();
-      assertThat(xml).contains("jdbc:connector-service");
-    });
-
-    server.invoke(() -> {
-      InternalCache cache = LocatorServerStartupRule.getCache();
-      ConnectionConfiguration config =
-          
cache.getService(InternalJdbcConnectorService.class).getConnectionConfig("name");
-      assertThat(config).isNull();
-    });
+  public void listsOneConnection() throws Exception {
+    server.invoke(() -> createOneConnection());
+    CommandStringBuilder csb = new CommandStringBuilder(LIST_JDBC_CONNECTION);
+
+    CommandResultAssert commandResultAssert = 
gfsh.executeAndAssertThat(csb.toString());
+
+    commandResultAssert.statusIsSuccess();
+    commandResultAssert.tableHasRowCount(LIST_OF_CONNECTIONS, 1);
+    commandResultAssert.tableHasColumnOnlyWithValues(LIST_OF_CONNECTIONS, 
connectionName);
+  }
+
+  @Test
+  public void listsMultipleConnections() throws Exception {
+    server.invoke(() -> createNConnections(3));
+    CommandStringBuilder csb = new CommandStringBuilder(LIST_JDBC_CONNECTION);
+
+    CommandResultAssert commandResultAssert = 
gfsh.executeAndAssertThat(csb.toString());
+
+    commandResultAssert.statusIsSuccess();
+    commandResultAssert.tableHasRowCount(LIST_OF_CONNECTIONS, 3);
+    commandResultAssert.tableHasColumnOnlyWithValues(LIST_OF_CONNECTIONS, 
connectionName + "-1",
+        connectionName + "-2", connectionName + "-3");
+  }
+
+  @Test
+  public void reportsNoConnectionsFound() throws Exception {
+    CommandStringBuilder csb = new CommandStringBuilder(LIST_JDBC_CONNECTION);
+
+    CommandResultAssert commandResultAssert = 
gfsh.executeAndAssertThat(csb.toString());
+
+    commandResultAssert.statusIsSuccess();
+    commandResultAssert.containsOutput("No connections found");
   }
 
-  private void createConnection() {
+  private void createOneConnection() throws ConnectionConfigExistsException {
     InternalCache cache = LocatorServerStartupRule.getCache();
     InternalJdbcConnectorService service = 
cache.getService(InternalJdbcConnectorService.class);
 
@@ -95,4 +107,15 @@ public class DestroyConnectionCommandDUnitTest implements 
Serializable {
 
     assertThat(service.getConnectionConfig(connectionName)).isNotNull();
   }
+
+  private void createNConnections(int N) throws 
ConnectionConfigExistsException {
+    InternalCache cache = LocatorServerStartupRule.getCache();
+    InternalJdbcConnectorService service = 
cache.getService(InternalJdbcConnectorService.class);
+    for (int i = 1; i <= N; i++) {
+      String name = connectionName + "-" + i;
+      service.createConnectionConfig(new 
ConnectionConfigBuilder().withName(name).build());
+      assertThat(service.getConnectionConfig(name)).isNotNull();
+    }
+  }
+
 }
diff --git 
a/geode-connectors/src/test/java/org/apache/geode/connectors/jdbc/internal/cli/ListConnectionCommandIntegrationTest.java
 
b/geode-connectors/src/test/java/org/apache/geode/connectors/jdbc/internal/cli/ListConnectionCommandIntegrationTest.java
new file mode 100644
index 0000000..d835509
--- /dev/null
+++ 
b/geode-connectors/src/test/java/org/apache/geode/connectors/jdbc/internal/cli/ListConnectionCommandIntegrationTest.java
@@ -0,0 +1,108 @@
+/*
+ * 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.connectors.jdbc.internal.cli;
+
+import static 
org.apache.geode.connectors.jdbc.internal.cli.ListConnectionCommand.LIST_OF_CONNECTIONS;
+import static 
org.apache.geode.connectors.jdbc.internal.cli.ListConnectionCommand.NO_CONNECTIONS_FOUND;
+import static 
org.apache.geode.distributed.ConfigurationProperties.ENABLE_CLUSTER_CONFIGURATION;
+import static org.assertj.core.api.Assertions.assertThat;
+
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.experimental.categories.Category;
+
+import org.apache.geode.cache.CacheFactory;
+import org.apache.geode.connectors.jdbc.internal.ConnectionConfigBuilder;
+import org.apache.geode.connectors.jdbc.internal.ConnectionConfiguration;
+import org.apache.geode.connectors.jdbc.internal.InternalJdbcConnectorService;
+import org.apache.geode.internal.cache.InternalCache;
+import org.apache.geode.management.cli.Result;
+import org.apache.geode.management.internal.cli.result.CommandResult;
+import org.apache.geode.test.junit.categories.IntegrationTest;
+
+@Category(IntegrationTest.class)
+public class ListConnectionCommandIntegrationTest {
+
+  private InternalCache cache;
+  private InternalJdbcConnectorService service;
+
+  private ConnectionConfiguration connectionConfig1;
+  private ConnectionConfiguration connectionConfig2;
+  private ConnectionConfiguration connectionConfig3;
+
+  private ListConnectionCommand command;
+
+  @Before
+  public void setup() throws Exception {
+    String[] params = new String[] {"param1:value1", "param2:value2"};
+
+    connectionConfig1 = new 
ConnectionConfigBuilder().withName("connection1").withUrl("url1")
+        
.withUser("user1").withPassword("password1").withParameters(params).build();
+    connectionConfig2 = new 
ConnectionConfigBuilder().withName("connection2").withUrl("url2")
+        
.withUser("user2").withPassword("password2").withParameters(params).build();
+    connectionConfig3 = new 
ConnectionConfigBuilder().withName("connection3").withUrl("url3")
+        
.withUser("user3").withPassword("password3").withParameters(params).build();
+
+    cache = (InternalCache) new 
CacheFactory().set(ENABLE_CLUSTER_CONFIGURATION, "true").create();
+    service = cache.getService(InternalJdbcConnectorService.class);
+
+    command = new ListConnectionCommand();
+  }
+
+  @After
+  public void tearDown() {
+    cache.close();
+  }
+
+  @Test
+  public void displaysNoConnectionsFoundWhenZeroConnectionsExist() throws 
Exception {
+    Result result = command.listConnection();
+
+    assertThat(result.getStatus()).isSameAs(Result.Status.OK);
+    CommandResult commandResult = (CommandResult) result;
+    String tableContent = commandResult.getTableContent().toString();
+    assertThat(tableContent).contains(NO_CONNECTIONS_FOUND);
+    assertThat(tableContent).doesNotContain(connectionConfig1.getName())
+        
.doesNotContain(connectionConfig2.getName()).doesNotContain(connectionConfig3.getName());
+  }
+
+  @Test
+  public void displaysListOfConnectionsHeaderWhenOneConnectionExists() throws 
Exception {
+    service.createConnectionConfig(connectionConfig1);
+
+    Result result = command.listConnection();
+
+    assertThat(result.getStatus()).isSameAs(Result.Status.OK);
+    CommandResult commandResult = (CommandResult) result;
+    String tableContent = commandResult.getTableContent().toString();
+    assertThat(tableContent).contains(LIST_OF_CONNECTIONS);
+    assertThat(tableContent).contains(connectionConfig1.getName());
+  }
+
+  @Test
+  public void displaysMultipleConnectionsByName() throws Exception {
+    service.createConnectionConfig(connectionConfig1);
+    service.createConnectionConfig(connectionConfig2);
+    service.createConnectionConfig(connectionConfig3);
+
+    Result result = command.listConnection();
+
+    assertThat(result.getStatus()).isSameAs(Result.Status.OK);
+    CommandResult commandResult = (CommandResult) result;
+    
assertThat(commandResult.getTableContent().toString()).contains(connectionConfig1.getName())
+        
.contains(connectionConfig2.getName()).contains(connectionConfig3.getName());
+  }
+}
diff --git 
a/geode-connectors/src/test/java/org/apache/geode/connectors/jdbc/internal/cli/DestroyConnectionFunctionTest.java
 
b/geode-connectors/src/test/java/org/apache/geode/connectors/jdbc/internal/cli/ListConnectionFunctionTest.java
similarity index 51%
copy from 
geode-connectors/src/test/java/org/apache/geode/connectors/jdbc/internal/cli/DestroyConnectionFunctionTest.java
copy to 
geode-connectors/src/test/java/org/apache/geode/connectors/jdbc/internal/cli/ListConnectionFunctionTest.java
index b28f499..5ced44f 100644
--- 
a/geode-connectors/src/test/java/org/apache/geode/connectors/jdbc/internal/cli/DestroyConnectionFunctionTest.java
+++ 
b/geode-connectors/src/test/java/org/apache/geode/connectors/jdbc/internal/cli/ListConnectionFunctionTest.java
@@ -22,11 +22,12 @@ import static org.mockito.Mockito.verify;
 import static org.mockito.Mockito.when;
 
 import java.io.Serializable;
+import java.util.HashSet;
+import java.util.Set;
 
 import org.apache.commons.lang.SerializationUtils;
 import org.junit.Before;
 import org.junit.Test;
-import org.junit.experimental.categories.Category;
 import org.mockito.ArgumentCaptor;
 
 import org.apache.geode.cache.execute.FunctionContext;
@@ -38,38 +39,45 @@ import org.apache.geode.distributed.DistributedMember;
 import org.apache.geode.distributed.DistributedSystem;
 import org.apache.geode.internal.cache.InternalCache;
 import org.apache.geode.management.internal.cli.functions.CliFunctionResult;
-import org.apache.geode.test.junit.categories.UnitTest;
 
-@Category(UnitTest.class)
-public class DestroyConnectionFunctionTest {
+public class ListConnectionFunctionTest {
 
-  private static final String connectionName = "connectionName";
-
-  private DestroyConnectionFunction function;
-  private FunctionContext<String> context;
+  private InternalCache cache;
+  private FunctionContext<Void> context;
   private ResultSender<Object> resultSender;
-  private ConnectionConfiguration configuration;
   private InternalJdbcConnectorService service;
 
+  private ConnectionConfiguration connectionConfig1;
+  private ConnectionConfiguration connectionConfig2;
+  private ConnectionConfiguration connectionConfig3;
+
+  private Set<ConnectionConfiguration> expected;
+
+  private ListConnectionFunction function;
+
   @Before
-  public void setUp() {
-    InternalCache cache = mock(InternalCache.class);
+  public void setUp() throws Exception {
+    cache = mock(InternalCache.class);
     context = mock(FunctionContext.class);
     DistributedMember member = mock(DistributedMember.class);
     resultSender = mock(ResultSender.class);
     service = mock(InternalJdbcConnectorService.class);
     DistributedSystem system = mock(DistributedSystem.class);
 
+    connectionConfig1 = mock(ConnectionConfiguration.class);
+    connectionConfig2 = mock(ConnectionConfiguration.class);
+    connectionConfig3 = mock(ConnectionConfiguration.class);
+
+    expected = new HashSet<>();
+
     when(context.getResultSender()).thenReturn(resultSender);
     when(context.getCache()).thenReturn(cache);
     when(cache.getDistributedSystem()).thenReturn(system);
     when(system.getDistributedMember()).thenReturn(member);
-    when(context.getArguments()).thenReturn(connectionName);
     
when(cache.getService(eq(InternalJdbcConnectorService.class))).thenReturn(service);
+    when(service.getConnectionConfigs()).thenReturn(expected);
 
-    configuration = new ConnectionConfigBuilder().build();
-
-    function = new DestroyConnectionFunction();
+    function = new ListConnectionFunction();
   }
 
   @Test
@@ -83,30 +91,76 @@ public class DestroyConnectionFunctionTest {
   }
 
   @Test
-  public void executeReportsErrorIfConnectionConfigNotFound() throws Exception 
{
+  public void serializes() throws Exception {
+    Serializable original = function;
+
+    Object copy = SerializationUtils.clone(original);
+
+    
assertThat(copy).isNotSameAs(original).isInstanceOf(ListConnectionFunction.class);
+  }
+
+  @Test
+  public void getConnectionConfigsReturnsMultiple() throws Exception {
+    expected.add(connectionConfig1);
+    expected.add(connectionConfig2);
+    expected.add(connectionConfig3);
+
+    ConnectionConfiguration[] actual = 
function.getConnectionConfigAsArray(service);
+
+    assertThat(actual).containsExactlyInAnyOrder(connectionConfig1, 
connectionConfig2,
+        connectionConfig3);
+  }
+
+  @Test
+  public void getConnectionConfigsReturnsEmpty() throws Exception {
+    ConnectionConfiguration[] actual = 
function.getConnectionConfigAsArray(service);
+
+    assertThat(actual).isEmpty();
+  }
+
+  @Test
+  public void executeReturnsResultWithAllConfigs() throws Exception {
+    expected.add(connectionConfig1);
+    expected.add(connectionConfig2);
+    expected.add(connectionConfig3);
+
     function.execute(context);
 
-    ArgumentCaptor<CliFunctionResult> argument = 
ArgumentCaptor.forClass(CliFunctionResult.class);
+    ArgumentCaptor<Object[]> argument = 
ArgumentCaptor.forClass(Object[].class);
+    verify(resultSender, times(1)).lastResult(argument.capture());
+    
assertThat(argument.getValue()).containsExactlyInAnyOrder(connectionConfig1, 
connectionConfig2,
+        connectionConfig3);
+  }
+
+  @Test
+  public void executeReturnsEmptyResultForNoConfigs() throws Exception {
+    function.execute(context);
+
+    ArgumentCaptor<Object[]> argument = 
ArgumentCaptor.forClass(Object[].class);
     verify(resultSender, times(1)).lastResult(argument.capture());
-    assertThat(argument.getValue().getErrorMessage())
-        .contains("Connection named \"" + connectionName + "\" not found");
+    assertThat(argument.getValue()).isEmpty();
   }
 
   @Test
-  public void executeDestroysIfConnectionConfigFound() throws Exception {
-    
when(service.getConnectionConfig(eq(connectionName))).thenReturn(configuration);
+  public void executeReturnsResultForExceptionWithoutMessage() throws 
Exception {
+    when(service.getConnectionConfigs()).thenThrow(new NullPointerException());
 
     function.execute(context);
 
-    verify(service, times(1)).destroyConnectionConfig(eq(connectionName));
+    ArgumentCaptor<CliFunctionResult> argument = 
ArgumentCaptor.forClass(CliFunctionResult.class);
+    verify(resultSender, times(1)).lastResult(argument.capture());
+    
assertThat(argument.getValue().getMessage()).contains(NullPointerException.class.getName());
   }
 
   @Test
-  public void serializes() throws Exception {
-    Serializable original = function;
+  public void executeReturnsResultForExceptionWithMessage() throws Exception {
+    when(service.getConnectionConfigs()).thenThrow(new 
IllegalArgumentException("some message"));
 
-    Object copy = SerializationUtils.clone(original);
+    function.execute(context);
 
-    
assertThat(copy).isNotSameAs(original).isInstanceOf(DestroyConnectionFunction.class);
+    ArgumentCaptor<CliFunctionResult> argument = 
ArgumentCaptor.forClass(CliFunctionResult.class);
+    verify(resultSender, times(1)).lastResult(argument.capture());
+    assertThat(argument.getValue().getMessage()).contains("some message")
+        .doesNotContain(IllegalArgumentException.class.getName());
   }
 }
diff --git 
a/geode-connectors/src/test/java/org/apache/geode/connectors/jdbc/internal/xml/JdbcConnectorServiceXmlIntegrationTest.java
 
b/geode-connectors/src/test/java/org/apache/geode/connectors/jdbc/internal/xml/JdbcConnectorServiceXmlIntegrationTest.java
index 48fd9a8..0d478f4 100644
--- 
a/geode-connectors/src/test/java/org/apache/geode/connectors/jdbc/internal/xml/JdbcConnectorServiceXmlIntegrationTest.java
+++ 
b/geode-connectors/src/test/java/org/apache/geode/connectors/jdbc/internal/xml/JdbcConnectorServiceXmlIntegrationTest.java
@@ -31,6 +31,7 @@ import org.junit.rules.TemporaryFolder;
 
 import org.apache.geode.cache.CacheFactory;
 import org.apache.geode.connectors.jdbc.internal.ConnectionConfigBuilder;
+import 
org.apache.geode.connectors.jdbc.internal.ConnectionConfigExistsException;
 import org.apache.geode.connectors.jdbc.internal.ConnectionConfiguration;
 import org.apache.geode.connectors.jdbc.internal.InternalJdbcConnectorService;
 import org.apache.geode.connectors.jdbc.internal.JdbcConnectorService;
@@ -80,7 +81,7 @@ public class JdbcConnectorServiceXmlIntegrationTest {
         .isEqualTo(regionMapping2);
   }
 
-  private void configureService() {
+  private void configureService() throws ConnectionConfigExistsException {
     InternalJdbcConnectorService service = 
cache.getService(InternalJdbcConnectorService.class);
     config1 = new 
ConnectionConfigBuilder().withName("connection1").withUrl("url1")
         .withUser("username1").withPassword("secret1")
diff --git 
a/geode-connectors/src/test/java/org/apache/geode/connectors/jdbc/internal/xml/JdbcServiceConfigurationTest.java
 
b/geode-connectors/src/test/java/org/apache/geode/connectors/jdbc/internal/xml/JdbcServiceConfigurationTest.java
index a268e69..497a0f7 100644
--- 
a/geode-connectors/src/test/java/org/apache/geode/connectors/jdbc/internal/xml/JdbcServiceConfigurationTest.java
+++ 
b/geode-connectors/src/test/java/org/apache/geode/connectors/jdbc/internal/xml/JdbcServiceConfigurationTest.java
@@ -47,7 +47,7 @@ public class JdbcServiceConfigurationTest {
   private JdbcServiceConfiguration configuration;
 
   @Before
-  public void setUp() {
+  public void setUp() throws Exception {
     connection1 = mock(ConnectionConfiguration.class);
     connection2 = mock(ConnectionConfiguration.class);
     mapping1 = mock(RegionMapping.class);
@@ -61,21 +61,21 @@ public class JdbcServiceConfigurationTest {
   }
 
   @Test
-  public void getXmlGeneratorReturnsJdbcConnectorServiceXmlGenerator() {
+  public void getXmlGeneratorReturnsJdbcConnectorServiceXmlGenerator() throws 
Exception {
     XmlGenerator<Cache> generator = configuration.getXmlGenerator();
 
     assertThat(generator).isInstanceOf(JdbcConnectorServiceXmlGenerator.class);
   }
 
   @Test
-  public void getXmlGeneratorReturnsGeneratorWithJdbcConnectorNamespace() {
+  public void getXmlGeneratorReturnsGeneratorWithJdbcConnectorNamespace() 
throws Exception {
     XmlGenerator<Cache> generator = configuration.getXmlGenerator();
 
     assertThat(generator.getNamespaceUri()).isEqualTo(NAMESPACE);
   }
 
   @Test
-  public void getXmlGeneratorReturnsEmptyGeneratorByDefault() {
+  public void getXmlGeneratorReturnsEmptyGeneratorByDefault() throws Exception 
{
     JdbcConnectorServiceXmlGenerator generator =
         (JdbcConnectorServiceXmlGenerator) configuration.getXmlGenerator();
 
@@ -84,7 +84,7 @@ public class JdbcServiceConfigurationTest {
   }
 
   @Test
-  public void getXmlGeneratorWithConnections() {
+  public void getXmlGeneratorWithConnections() throws Exception {
     configuration.addConnectionConfig(connection1);
     configuration.addConnectionConfig(connection2);
 
@@ -95,7 +95,7 @@ public class JdbcServiceConfigurationTest {
   }
 
   @Test
-  public void getXmlGeneratorWithRegionMappings() {
+  public void getXmlGeneratorWithRegionMappings() throws Exception {
     configuration.addRegionMapping(mapping1);
     configuration.addRegionMapping(mapping2);
 
@@ -106,14 +106,14 @@ public class JdbcServiceConfigurationTest {
   }
 
   @Test
-  public void onCreateWithNoConnectionsOrMappings() {
+  public void onCreateWithNoConnectionsOrMappings() throws Exception {
     configuration.onCreate(cache, cache);
 
     verifyZeroInteractions(service);
   }
 
   @Test
-  public void onCreateWithConnections() {
+  public void onCreateWithConnections() throws Exception {
     configuration.addConnectionConfig(connection1);
     configuration.addConnectionConfig(connection2);
 
@@ -124,7 +124,7 @@ public class JdbcServiceConfigurationTest {
   }
 
   @Test
-  public void onCreateWithRegionMappings() {
+  public void onCreateWithRegionMappings() throws Exception {
     configuration.addRegionMapping(mapping1);
     configuration.addRegionMapping(mapping2);
 
diff --git 
a/geode-core/src/main/java/org/apache/geode/management/internal/configuration/domain/XmlEntity.java
 
b/geode-core/src/main/java/org/apache/geode/management/internal/configuration/domain/XmlEntity.java
index 0476072..88801a0 100644
--- 
a/geode-core/src/main/java/org/apache/geode/management/internal/configuration/domain/XmlEntity.java
+++ 
b/geode-core/src/main/java/org/apache/geode/management/internal/configuration/domain/XmlEntity.java
@@ -18,6 +18,7 @@ import java.io.DataInput;
 import java.io.DataOutput;
 import java.io.IOException;
 import java.io.PrintWriter;
+import java.io.Serializable;
 import java.io.StringReader;
 import java.io.StringWriter;
 import java.util.HashMap;
@@ -44,26 +45,31 @@ import org.apache.geode.cache.CacheFactory;
 import org.apache.geode.internal.Assert;
 import org.apache.geode.internal.Version;
 import org.apache.geode.internal.VersionedDataSerializable;
+import org.apache.geode.internal.cache.InternalCache;
 import org.apache.geode.internal.cache.xmlcache.CacheXml;
 import org.apache.geode.internal.cache.xmlcache.CacheXmlGenerator;
 import org.apache.geode.internal.logging.LogService;
 import org.apache.geode.management.internal.configuration.utils.XmlUtils;
 import 
org.apache.geode.management.internal.configuration.utils.XmlUtils.XPathContext;
 
-/****
+/**
  * Domain class for defining a GemFire entity in XML.
- *
- *
  */
 public class XmlEntity implements VersionedDataSerializable {
   private static final long serialVersionUID = 1L;
   private static final Logger logger = LogService.getLogger();
 
+  private transient volatile CacheProvider cacheProvider;
+
   private String type;
+
   @SuppressWarnings("unused")
   private String parentType;
+
   private Map<String, String> attributes = new HashMap<>();
+
   private String xmlDefinition;
+
   private String searchString;
 
   private String prefix = CacheXml.PREFIX;
@@ -75,12 +81,28 @@ public class XmlEntity implements VersionedDataSerializable 
{
   private String childNamespace;
 
   /**
+   * Produce a new XmlEntityBuilder.
+   *
+   * @return new XmlEntityBuilder.
+   * @since GemFire 8.1
+   */
+  public static XmlEntityBuilder builder() {
+    return new XmlEntityBuilder();
+  }
+
+  private static CacheProvider createDefaultCacheProvider() {
+    return () -> (InternalCache) CacheFactory.getAnyInstance();
+  }
+
+  /**
    * Default constructor for serialization only.
    *
    * @deprecated Use {@link XmlEntity#builder()}.
    */
   @Deprecated
-  public XmlEntity() {}
+  public XmlEntity() {
+    this.cacheProvider = createDefaultCacheProvider();
+  }
 
   /**
    * Construct a new XmlEntity while creating XML from the cache using the 
element which has a type
@@ -92,13 +114,14 @@ public class XmlEntity implements 
VersionedDataSerializable {
    * @param value Value of the attribute to match.
    */
   public XmlEntity(final String type, final String key, final String value) {
+    this.cacheProvider = createDefaultCacheProvider();
     this.type = type;
     this.attributes.put(key, value);
 
     init();
   }
 
-  /****
+  /**
    * Construct a new XmlEntity while creating Xml from the cache using the 
element which has
    * attributes matching those given
    *
@@ -114,13 +137,13 @@ public class XmlEntity implements 
VersionedDataSerializable {
    */
   public XmlEntity(final String parentType, final String parentKey, final 
String parentValue,
       final String childType, final String childKey, final String childValue) {
+    this.cacheProvider = createDefaultCacheProvider();
     this.parentType = parentType;
     this.type = childType;
     initializeSearchString(parentKey, parentValue, this.prefix, childKey, 
childValue);
-
   }
 
-  /****
+  /**
    * Construct a new XmlEntity while creating Xml from the cache using the 
element which has
    * attributes matching those given
    *
@@ -141,6 +164,7 @@ public class XmlEntity implements VersionedDataSerializable 
{
       final String childPrefix, final String childNamespace, final String 
childType,
       final String childKey, final String childValue) {
     // Note: Do not invoke init
+    this.cacheProvider = createDefaultCacheProvider();
     this.parentType = parentType;
     this.type = childType;
     this.childPrefix = childPrefix;
@@ -150,6 +174,12 @@ public class XmlEntity implements 
VersionedDataSerializable {
 
   public XmlEntity(final String parentType, final String childPrefix, final 
String childNamespace,
       final String childType) {
+    this(createDefaultCacheProvider(), parentType, childPrefix, 
childNamespace, childType);
+  }
+
+  public XmlEntity(final CacheProvider cacheProvider, final String parentType,
+      final String childPrefix, final String childNamespace, final String 
childType) {
+    this.cacheProvider = cacheProvider;
     this.parentType = parentType;
     this.type = childType;
     this.childPrefix = childPrefix;
@@ -157,28 +187,31 @@ public class XmlEntity implements 
VersionedDataSerializable {
 
     StringBuilder sb = new StringBuilder();
     sb.append("//").append(this.parentType);
-    sb.append("/").append(childPrefix).append(':').append(this.type);
+    sb.append('/').append(childPrefix).append(':').append(this.type);
     this.searchString = sb.toString();
     this.xmlDefinition = parseXmlForDefinition();
   }
 
   private String parseXmlForDefinition() {
-    final Cache cache = CacheFactory.getAnyInstance();
+    final Cache cache = cacheProvider.getCache();
 
     final StringWriter stringWriter = new StringWriter();
     final PrintWriter printWriter = new PrintWriter(stringWriter);
     CacheXmlGenerator.generate(cache, printWriter, true, false, false);
     printWriter.close();
     InputSource inputSource = new InputSource(new 
StringReader(stringWriter.toString()));
+
     try {
       Document document = XmlUtils.getDocumentBuilder().parse(inputSource);
       Node element = document.getElementsByTagNameNS(childNamespace, 
type).item(0);
       if (null != element) {
         return XmlUtils.elementToString(element);
       }
-    } catch (Exception e) {
+    } catch (IOException | ParserConfigurationException | RuntimeException | 
SAXException
+        | TransformerException e) {
       throw new InternalGemFireError("Could not parse XML when creating 
XMLEntity", e);
     }
+
     logger.warn("No XML definition could be found with name={} and 
attributes={}", type,
         attributes);
     return null;
@@ -186,14 +219,14 @@ public class XmlEntity implements 
VersionedDataSerializable {
 
   private void initializeSearchString(final String parentKey, final String 
parentValue,
       final String childPrefix, final String childKey, final String 
childValue) {
-    StringBuffer sb = new StringBuffer();
+    StringBuilder sb = new StringBuilder();
     sb.append("//").append(this.prefix).append(':').append(this.parentType);
 
     if (StringUtils.isNotBlank(parentKey) && 
StringUtils.isNotBlank(parentValue)) {
       
sb.append("[@").append(parentKey).append("='").append(parentValue).append("']");
     }
 
-    sb.append("/").append(childPrefix).append(':').append(this.type);
+    sb.append('/').append(childPrefix).append(':').append(this.type);
 
     if (StringUtils.isNotBlank(childKey) && 
StringUtils.isNotBlank(childValue)) {
       
sb.append("[@").append(childKey).append("='").append(childValue).append("']");
@@ -224,7 +257,7 @@ public class XmlEntity implements VersionedDataSerializable 
{
    * @return XML string representation of the entity.
    */
   private String loadXmlDefinition() {
-    final Cache cache = CacheFactory.getAnyInstance();
+    final Cache cache = cacheProvider.getCache();
 
     final StringWriter stringWriter = new StringWriter();
     final PrintWriter printWriter = new PrintWriter(stringWriter);
@@ -235,10 +268,10 @@ public class XmlEntity implements 
VersionedDataSerializable {
   }
 
   /**
-   * Used supplied xmlDocument to extract the XML for the defined {@link 
XmlEntity}.
+   * Used supplied xmlDocument to extract the XML for the defined XmlEntity.
    *
    * @param xmlDocument to extract XML from.
-   * @return XML for {@link XmlEntity} if found, otherwise <code>null</code>.
+   * @return XML for XmlEntity if found, otherwise {@code null}.
    * @since GemFire 8.1
    */
   private String loadXmlDefinition(final String xmlDocument) {
@@ -252,13 +285,10 @@ public class XmlEntity implements 
VersionedDataSerializable {
   }
 
   /**
-   * Used supplied XML {@link Document} to extract the XML for the defined 
{@link XmlEntity}.
+   * Used supplied XML {@link Document} to extract the XML for the defined 
XmlEntity.
    *
    * @param document to extract XML from.
-   * @return XML for {@link XmlEntity} if found, otherwise <code>null</code>.
-   * @throws XPathExpressionException
-   * @throws TransformerException
-   * @throws TransformerFactoryConfigurationError
+   * @return XML for XmlEntity if found, otherwise {@code null}.
    * @since GemFire 8.1
    */
   public String loadXmlDefinition(final Document document)
@@ -269,10 +299,13 @@ public class XmlEntity implements 
VersionedDataSerializable {
     if (document != null) {
       XPathContext xpathContext = new XPathContext();
       xpathContext.addNamespace(prefix, namespace);
-      xpathContext.addNamespace(childPrefix, childNamespace); // TODO: wrap 
this line with
-                                                              // conditional
+
+      // TODO: wrap this line with conditional
+      xpathContext.addNamespace(childPrefix, childNamespace);
+
       // Create an XPathContext here
       Node element = XmlUtils.querySingleElement(document, this.searchString, 
xpathContext);
+
       // Must copy to preserve namespaces.
       if (null != element) {
         return XmlUtils.elementToString(element);
@@ -299,18 +332,18 @@ public class XmlEntity implements 
VersionedDataSerializable {
     Iterator<Entry<String, String>> attributeIter = 
attributes.entrySet().iterator();
     queryStringBuilder.append("//").append(prefix).append(':').append(element);
 
-    if (attributes.size() > 0) {
-      queryStringBuilder.append("[");
+    if (!attributes.isEmpty()) {
+      queryStringBuilder.append('[');
       Entry<String, String> attrEntry = attributeIter.next();
-      queryStringBuilder.append("@").append(attrEntry.getKey()).append("='")
-          .append(attrEntry.getValue()).append("'");
+      queryStringBuilder.append('@').append(attrEntry.getKey()).append("='")
+          .append(attrEntry.getValue()).append('\'');
       while (attributeIter.hasNext()) {
         attrEntry = attributeIter.next();
         queryStringBuilder.append(" and 
@").append(attrEntry.getKey()).append("='")
-            .append(attrEntry.getValue()).append("'");
+            .append(attrEntry.getValue()).append('\'');
       }
 
-      queryStringBuilder.append("]");
+      queryStringBuilder.append(']');
     }
 
     return queryStringBuilder.toString();
@@ -396,9 +429,14 @@ public class XmlEntity implements 
VersionedDataSerializable {
   }
 
   @Override
+  public Version[] getSerializationVersions() {
+    return new Version[] {Version.GEODE_111};
+  }
+
+  @Override
   public String toString() {
     return "XmlEntity [namespace=" + namespace + ", type=" + this.type + ", 
attributes="
-        + this.attributes + ", xmlDefinition=" + this.xmlDefinition + "]";
+        + this.attributes + ", xmlDefinition=" + this.xmlDefinition + ']';
   }
 
   @Override
@@ -467,30 +505,23 @@ public class XmlEntity implements 
VersionedDataSerializable {
     this.searchString = DataSerializer.readString(in);
     this.prefix = DataSerializer.readString(in);
     this.namespace = DataSerializer.readString(in);
+    this.cacheProvider = createDefaultCacheProvider();
   }
 
   /**
-   * Produce a new {@link XmlEntityBuilder}.
-   *
-   * @return new {@link XmlEntityBuilder}.
-   * @since GemFire 8.1
+   * Defines how XmlEntity gets a reference to the Cache.
    */
-  public static XmlEntityBuilder builder() {
-    return new XmlEntityBuilder();
-  }
-
-  @Override
-  public Version[] getSerializationVersions() {
-    return new Version[] {Version.GEODE_111};
+  public interface CacheProvider {
+    InternalCache getCache();
   }
 
   /**
-   * Builder for {@link XmlEntity}. Default values are as described in {@link 
XmlEntity}.
-   *
+   * Builder for XmlEntity. Default values are as described in XmlEntity.
    *
    * @since GemFire 8.1
    */
   public static class XmlEntityBuilder {
+
     private XmlEntity xmlEntity;
 
     /**
@@ -498,17 +529,17 @@ public class XmlEntity implements 
VersionedDataSerializable {
      *
      * @since GemFire 8.1
      */
-    private XmlEntityBuilder() {
+    XmlEntityBuilder() {
       xmlEntity = new XmlEntity();
     }
 
     /**
-     * Produce an {@link XmlEntity} with the supplied values. Builder is reset 
after
-     * {@link #build()} is called. Subsequent calls will produce a new {@link 
XmlEntity}.
+     * Produce an XmlEntity with the supplied values. Builder is reset after 
#build() is called.
+     * Subsequent calls will produce a new XmlEntity.
      *
      * You are required to at least call {@link #withType(String)}.
      *
-     * @return {@link XmlEntity}
+     * @return XmlEntity
      * @since GemFire 8.1
      */
     public XmlEntity build() {
@@ -524,7 +555,7 @@ public class XmlEntity implements VersionedDataSerializable 
{
      * Sets the type or element name value as returned by {@link 
XmlEntity#getType()}
      *
      * @param type Name of element type.
-     * @return this {@link XmlEntityBuilder}
+     * @return this XmlEntityBuilder
      * @since GemFire 8.1
      */
     public XmlEntityBuilder withType(final String type) {
@@ -540,7 +571,7 @@ public class XmlEntity implements VersionedDataSerializable 
{
      *
      * @param prefix Prefix of element
      * @param namespace Namespace of element
-     * @return this {@link XmlEntityBuilder}
+     * @return this XmlEntityBuilder
      * @since GemFire 8.1
      */
     public XmlEntityBuilder withNamespace(final String prefix, final String 
namespace) {
@@ -556,7 +587,7 @@ public class XmlEntity implements VersionedDataSerializable 
{
      *
      * @param name Name of attribute to set.
      * @param value Value of attribute to set.
-     * @return this {@link XmlEntityBuilder}
+     * @return this XmlEntityBuilder
      * @since GemFire 8.1
      */
     public XmlEntityBuilder withAttribute(final String name, final String 
value) {
@@ -569,7 +600,7 @@ public class XmlEntity implements VersionedDataSerializable 
{
      * Replaces all attributes with the supplied attributes {@link Map}.
      *
      * @param attributes {@link Map} to use.
-     * @return this {@link XmlEntityBuilder}
+     * @return this XmlEntityBuilder
      * @since GemFire 8.1
      */
     public XmlEntityBuilder withAttributes(final Map<String, String> 
attributes) {
@@ -586,7 +617,7 @@ public class XmlEntity implements VersionedDataSerializable 
{
      * <b>Should only be used for testing.</b>
      *
      * @param xmlDocument Config XML document.
-     * @return this {@link XmlEntityBuilder}
+     * @return this XmlEntityBuilder
      * @since GemFire 8.1
      */
     public XmlEntityBuilder withConfig(final String xmlDocument) {
@@ -603,10 +634,7 @@ public class XmlEntity implements 
VersionedDataSerializable {
      * <b>Should only be used for testing.</b>
      *
      * @param document Config XML {@link Document}.
-     * @return this {@link XmlEntityBuilder}
-     * @throws TransformerException
-     * @throws TransformerFactoryConfigurationError
-     * @throws XPathExpressionException
+     * @return this XmlEntityBuilder
      * @since GemFire 8.1
      */
     public XmlEntityBuilder withConfig(final Document document) throws 
XPathExpressionException,
@@ -615,6 +643,5 @@ public class XmlEntity implements VersionedDataSerializable 
{
 
       return this;
     }
-
   }
 }
diff --git 
a/geode-core/src/test/java/org/apache/geode/internal/cache/xmlcache/CacheXmlParserJUnitTest.java
 
b/geode-core/src/test/java/org/apache/geode/internal/cache/xmlcache/CacheXmlParserJUnitTest.java
index afcc207..6e82ec1 100644
--- 
a/geode-core/src/test/java/org/apache/geode/internal/cache/xmlcache/CacheXmlParserJUnitTest.java
+++ 
b/geode-core/src/test/java/org/apache/geode/internal/cache/xmlcache/CacheXmlParserJUnitTest.java
@@ -20,8 +20,6 @@ import static org.junit.Assert.assertNotNull;
 import static org.junit.Assert.assertNull;
 import static org.junit.Assert.assertSame;
 import static org.junit.Assert.assertTrue;
-import static org.mockito.Mockito.mock;
-import static org.mockito.Mockito.when;
 
 import java.lang.reflect.Field;
 import java.lang.reflect.InvocationTargetException;
@@ -40,16 +38,15 @@ import org.xml.sax.SAXException;
 
 import org.apache.geode.cache.client.ClientCache;
 import org.apache.geode.cache.client.ClientCacheFactory;
-import org.apache.geode.distributed.internal.DM;
 import org.apache.geode.distributed.internal.InternalDistributedSystem;
-import org.apache.geode.test.junit.categories.UnitTest;
+import org.apache.geode.test.junit.categories.IntegrationTest;
 
 /**
  * Test cases for {@link CacheXmlParser}.
  *
  * @since GemFire 8.1
  */
-@Category(UnitTest.class)
+@Category(IntegrationTest.class)
 public class CacheXmlParserJUnitTest {
 
   @Rule
diff --git 
a/geode-core/src/test/resources/org/apache/geode/internal/cache/xmlcache/CacheXmlParserJUnitTest.testSimpleClientCacheXml.cache.xml
 
b/geode-core/src/test/resources/org/apache/geode/internal/cache/xmlcache/CacheXmlParserJUnitTest.testSimpleClientCacheXml.cache.xml
index 0a76a77..8c648c3 100644
--- 
a/geode-core/src/test/resources/org/apache/geode/internal/cache/xmlcache/CacheXmlParserJUnitTest.testSimpleClientCacheXml.cache.xml
+++ 
b/geode-core/src/test/resources/org/apache/geode/internal/cache/xmlcache/CacheXmlParserJUnitTest.testSimpleClientCacheXml.cache.xml
@@ -22,7 +22,7 @@
     version="1.0">
      
        <pool name="sessions" subscription-enabled="true">   
-               <server host="1.2.3.4" port="11211" /> 
+               <server host="127.0.0.1" port="11211" />
        </pool>
 </client-cache>
 

-- 
To stop receiving notification emails like this one, please contact
['"[email protected]" <[email protected]>'].

Reply via email to