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

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

commit 98d37be738002badceeda566392c3d892a0ce9e7
Author: zhouxh <[email protected]>
AuthorDate: Wed May 22 10:19:58 2019 -0700

    GEODE-6770: add optional deregister driver class when destroy data source.
    
        Co-authored-by: Benjamin Ross <[email protected]>
        Co-authored-by: Donal Evans <[email protected]>
        Co-authored-by: Xiaojian Zhou <[email protected]>
---
 .../internal/cli/DestroyDataSourceCommand.java     |  54 ++++++++-
 .../internal/cli/DestroyDataSourceCommandTest.java | 132 +++++++++++++++++++++
 .../geode/internal/util/DriverJarUtilTest.java     |   1 -
 3 files changed, 183 insertions(+), 4 deletions(-)

diff --git 
a/geode-connectors/src/main/java/org/apache/geode/connectors/jdbc/internal/cli/DestroyDataSourceCommand.java
 
b/geode-connectors/src/main/java/org/apache/geode/connectors/jdbc/internal/cli/DestroyDataSourceCommand.java
index 2b1be87..0188710 100644
--- 
a/geode-connectors/src/main/java/org/apache/geode/connectors/jdbc/internal/cli/DestroyDataSourceCommand.java
+++ 
b/geode-connectors/src/main/java/org/apache/geode/connectors/jdbc/internal/cli/DestroyDataSourceCommand.java
@@ -14,6 +14,7 @@
  */
 package org.apache.geode.connectors.jdbc.internal.cli;
 
+import java.sql.SQLException;
 import java.util.List;
 import java.util.Set;
 
@@ -28,12 +29,14 @@ import org.apache.geode.cache.configuration.RegionConfig;
 import org.apache.geode.connectors.jdbc.internal.configuration.RegionMapping;
 import org.apache.geode.distributed.DistributedMember;
 import 
org.apache.geode.distributed.internal.InternalConfigurationPersistenceService;
+import org.apache.geode.internal.util.DriverJarUtil;
 import org.apache.geode.management.cli.CliMetaData;
 import org.apache.geode.management.cli.SingleGfshCommand;
 import 
org.apache.geode.management.internal.cli.commands.CreateJndiBindingCommand;
 import org.apache.geode.management.internal.cli.functions.CliFunctionResult;
 import 
org.apache.geode.management.internal.cli.functions.DestroyJndiBindingFunction;
 import org.apache.geode.management.internal.cli.i18n.CliStrings;
+import org.apache.geode.management.internal.cli.result.model.InfoResultModel;
 import org.apache.geode.management.internal.cli.result.model.ResultModel;
 import org.apache.geode.management.internal.exceptions.EntityNotFoundException;
 import org.apache.geode.management.internal.security.ResourceOperation;
@@ -49,6 +52,10 @@ public class DestroyDataSourceCommand extends 
SingleGfshCommand {
       "Skip the destroy operation when the specified data source does "
           + "not exist. Without this option, an error results from the 
specification "
           + "of a data source that does not exist.";
+  static final String DEREGISTER_DRIVER = "deregister-driver";
+  static final String DEREGISTER_DRIVER_HELP =
+      "Indicates whether or not the driver class associated"
+          + "with the target data source should be deregistered during the 
destroy process.";
 
   @CliCommand(value = DESTROY_DATA_SOURCE, help = DESTROY_DATA_SOURCE_HELP)
   @CliMetaData(relatedTopic = CliStrings.TOPIC_GEODE_REGION)
@@ -57,11 +64,15 @@ public class DestroyDataSourceCommand extends 
SingleGfshCommand {
   public ResultModel destroyDataSource(
       @CliOption(key = DATA_SOURCE_NAME, mandatory = true,
           help = DATA_SOURCE_NAME_HELP) String dataSourceName,
+      @CliOption(key = DEREGISTER_DRIVER,
+          help = DEREGISTER_DRIVER_HELP, specifiedDefaultValue = "true",
+          unspecifiedDefaultValue = "false") boolean deregisterDriver,
       @CliOption(key = CliStrings.IFEXISTS, help = IFEXISTS_HELP, 
specifiedDefaultValue = "true",
           unspecifiedDefaultValue = "false") boolean ifExists) {
 
     InternalConfigurationPersistenceService service =
         (InternalConfigurationPersistenceService) 
getConfigurationPersistenceService();
+    String driverClassName = null;
     if (service != null) {
       List<JndiBindingsType.JndiBinding> bindings =
           service.getCacheConfig("cluster").getJndiBindings();
@@ -86,6 +97,9 @@ public class DestroyDataSourceCommand extends 
SingleGfshCommand {
             dataSourceName, ex.getMessage()));
 
       }
+      if (deregisterDriver) {
+        driverClassName = binding.getJdbcDriverClass();
+      }
     }
 
     Set<DistributedMember> targetMembers = findMembers(null, null);
@@ -109,14 +123,27 @@ public class DestroyDataSourceCommand extends 
SingleGfshCommand {
       }
 
       ResultModel result = 
ResultModel.createMemberStatusResult(dataSourceDestroyResult);
+      InfoResultModel infoModel = result.addInfo();
+      String deregisterResult = deregisterDriver(deregisterDriver, 
driverClassName, dataSourceName);
+      if (deregisterResult != null) {
+        infoModel.addLine(deregisterResult);
+      }
       result.setConfigObject(dataSourceName);
 
       return result;
     } else {
       if (service != null) {
-        ResultModel result =
-            ResultModel
-                .createInfo("No members found, data source removed from 
cluster configuration.");
+        // ResultModel result =
+        // ResultModel
+        // .createInfo("No members found, data source removed from cluster 
configuration.");
+        ResultModel result = new ResultModel();
+        InfoResultModel infoModel = result.addInfo();
+        infoModel.addLine("No members found, data source removed from cluster 
configuration.");
+        String deregisterResult =
+            deregisterDriver(deregisterDriver, driverClassName, 
dataSourceName);
+        if (deregisterResult != null) {
+          infoModel.addLine(deregisterResult);
+        }
         result.setConfigObject(dataSourceName);
         return result;
       } else {
@@ -149,6 +176,27 @@ public class DestroyDataSourceCommand extends 
SingleGfshCommand {
         || 
CreateJndiBindingCommand.DATASOURCE_TYPE.POOLED.getType().equals(binding.getType());
   }
 
+  private String deregisterDriver(boolean deregisterDriver, String 
driverClassName,
+      String dataSourceName) {
+    if (deregisterDriver && driverClassName != null) {
+      DriverJarUtil util = createDriverJarUtil();
+      try {
+        util.deregisterDriver(driverClassName);
+      } catch (SQLException ex) {
+        return "Warning: deregistering \"" + driverClassName + "\" while 
destroying data source \""
+            + dataSourceName + "\" failed with exception: " + ex.getMessage();
+      }
+    } else if (deregisterDriver && driverClassName == null) {
+      return "Warning: deregistering \"" + driverClassName + "\" while 
destroying data source \""
+          + dataSourceName + "\" failed: No driver class name found";
+    }
+    return null;
+  }
+
+  DriverJarUtil createDriverJarUtil() {
+    return new DriverJarUtil();
+  }
+
   @Override
   public boolean updateConfigForGroup(String group, CacheConfig config, Object 
element) {
     CacheElement.removeElement(config.getJndiBindings(), (String) element);
diff --git 
a/geode-connectors/src/test/java/org/apache/geode/connectors/jdbc/internal/cli/DestroyDataSourceCommandTest.java
 
b/geode-connectors/src/test/java/org/apache/geode/connectors/jdbc/internal/cli/DestroyDataSourceCommandTest.java
index 4388e91..823b946 100644
--- 
a/geode-connectors/src/test/java/org/apache/geode/connectors/jdbc/internal/cli/DestroyDataSourceCommandTest.java
+++ 
b/geode-connectors/src/test/java/org/apache/geode/connectors/jdbc/internal/cli/DestroyDataSourceCommandTest.java
@@ -20,12 +20,14 @@ import static org.mockito.ArgumentMatchers.eq;
 import static org.mockito.ArgumentMatchers.isNotNull;
 import static org.mockito.Mockito.doAnswer;
 import static org.mockito.Mockito.doReturn;
+import static org.mockito.Mockito.doThrow;
 import static org.mockito.Mockito.mock;
 import static org.mockito.Mockito.spy;
 import static org.mockito.Mockito.times;
 import static org.mockito.Mockito.verify;
 import static org.mockito.Mockito.when;
 
+import java.sql.SQLException;
 import java.util.ArrayList;
 import java.util.Collections;
 import java.util.HashSet;
@@ -47,6 +49,7 @@ import 
org.apache.geode.connectors.jdbc.internal.configuration.RegionMapping;
 import org.apache.geode.distributed.DistributedMember;
 import 
org.apache.geode.distributed.internal.InternalConfigurationPersistenceService;
 import org.apache.geode.internal.cache.InternalCache;
+import org.apache.geode.internal.util.DriverJarUtil;
 import 
org.apache.geode.management.internal.cli.commands.CreateJndiBindingCommand;
 import org.apache.geode.management.internal.cli.functions.CliFunctionResult;
 import 
org.apache.geode.management.internal.cli.functions.DestroyJndiBindingFunction;
@@ -364,4 +367,133 @@ public class DestroyDataSourceCommandTest {
     assertThat(destroyingDataSource).isEqualTo(true);
     assertThat(targetMembers.getValue()).isEqualTo(members);
   }
+
+  @Test
+  public void destroyDataSourceWithDeregisterDriverSucceedsWithWarning() {
+    List<JndiBindingsType.JndiBinding> bindings = new ArrayList<>();
+    JndiBindingsType.JndiBinding jndiBinding = new 
JndiBindingsType.JndiBinding();
+    jndiBinding.setJndiName("name");
+    
jndiBinding.setType(CreateJndiBindingCommand.DATASOURCE_TYPE.SIMPLE.getType());
+    bindings.add(jndiBinding);
+    doReturn(bindings).when(cacheConfig).getJndiBindings();
+
+    Set<DistributedMember> members = new HashSet<>();
+    members.add(mock(DistributedMember.class));
+
+    CliFunctionResult result =
+        new CliFunctionResult("server1", true, "Data source \"name\" destroyed 
on \"server1\"");
+    List<CliFunctionResult> results = new ArrayList<>();
+    results.add(result);
+
+    doReturn(members).when(command).findMembers(any(), any());
+    doReturn(results).when(command).executeAndGetFunctionResult(any(), any(), 
any());
+
+    gfsh.executeAndAssertThat(command, COMMAND + " --name=name 
--deregister-driver")
+        .statusIsSuccess()
+        .tableHasColumnOnlyWithValues("Member", "server1")
+        .tableHasColumnOnlyWithValues("Status", "OK")
+        .tableHasColumnOnlyWithValues("Message", "Data source \"name\" 
destroyed on \"server1\"");
+
+    assertThat(cacheConfig.getJndiBindings().isEmpty()).isTrue();
+    verify(command).updateConfigForGroup(eq("cluster"), eq(cacheConfig), 
any());
+
+    ArgumentCaptor<DestroyJndiBindingFunction> function =
+        ArgumentCaptor.forClass(DestroyJndiBindingFunction.class);
+    ArgumentCaptor<Object[]> arguments = 
ArgumentCaptor.forClass(Object[].class);
+
+    ArgumentCaptor<Set<DistributedMember>> targetMembers = 
ArgumentCaptor.forClass(Set.class);
+    verify(command, times(1)).executeAndGetFunctionResult(function.capture(), 
arguments.capture(),
+        targetMembers.capture());
+
+    String jndiName = (String) arguments.getValue()[0];
+    boolean destroyingDataSource = (boolean) arguments.getValue()[1];
+
+    
assertThat(function.getValue()).isInstanceOf(DestroyJndiBindingFunction.class);
+    assertThat(jndiName).isEqualTo("name");
+    assertThat(destroyingDataSource).isEqualTo(true);
+    assertThat(targetMembers.getValue()).isEqualTo(members);
+  }
+
+  @Test
+  public void 
destroyDataSourceThrowsSQLExceptpionWithRegisterDriverAndBadDriverClassName()
+      throws SQLException {
+    DriverJarUtil util = mock(DriverJarUtil.class);
+    doReturn(util).when(command).createDriverJarUtil();
+
+    String exceptionMessage = "Command failed as expected.";
+
+    doThrow(new 
SQLException(exceptionMessage)).when(util).deregisterDriver(any());
+
+    List<JndiBindingsType.JndiBinding> bindings = new ArrayList<>();
+    JndiBindingsType.JndiBinding jndiBinding = new 
JndiBindingsType.JndiBinding();
+    jndiBinding.setJndiName("name");
+    jndiBinding.setJdbcDriverClass("badDriverClassName");
+    
jndiBinding.setType(CreateJndiBindingCommand.DATASOURCE_TYPE.SIMPLE.getType());
+    bindings.add(jndiBinding);
+    doReturn(bindings).when(cacheConfig).getJndiBindings();
+
+    Set<DistributedMember> members = new HashSet<>();
+    members.add(mock(DistributedMember.class));
+
+    CliFunctionResult result =
+        new CliFunctionResult("server1", true, "Data source \"name\" destroyed 
on \"server1\"");
+    List<CliFunctionResult> results = new ArrayList<>();
+    results.add(result);
+
+    doReturn(members).when(command).findMembers(any(), any());
+    doReturn(results).when(command).executeAndGetFunctionResult(any(), any(), 
any());
+
+    gfsh.executeAndAssertThat(command, COMMAND + " --name=name 
--deregister-driver")
+        .containsOutput(exceptionMessage);
+  }
+
+  @Test
+  public void destroyDataSourceWithDeregisterDriverSucceedsWithoutWarnings() {
+    DriverJarUtil util = mock(DriverJarUtil.class);
+
+    List<JndiBindingsType.JndiBinding> bindings = new ArrayList<>();
+    JndiBindingsType.JndiBinding jndiBinding = new 
JndiBindingsType.JndiBinding();
+    jndiBinding.setJndiName("name");
+    jndiBinding.setJdbcDriverClass("driverClassName");
+    
jndiBinding.setType(CreateJndiBindingCommand.DATASOURCE_TYPE.SIMPLE.getType());
+    bindings.add(jndiBinding);
+    doReturn(bindings).when(cacheConfig).getJndiBindings();
+
+    Set<DistributedMember> members = new HashSet<>();
+    members.add(mock(DistributedMember.class));
+
+    CliFunctionResult result =
+        new CliFunctionResult("server1", true, "Data source \"name\" destroyed 
on \"server1\"");
+    List<CliFunctionResult> results = new ArrayList<>();
+    results.add(result);
+
+    doReturn(members).when(command).findMembers(any(), any());
+    doReturn(results).when(command).executeAndGetFunctionResult(any(), any(), 
any());
+
+    gfsh.executeAndAssertThat(command, COMMAND + " --name=name 
--deregister-driver")
+        .statusIsSuccess()
+        .tableHasColumnOnlyWithValues("Member", "server1")
+        .tableHasColumnOnlyWithValues("Status", "OK")
+        .tableHasColumnOnlyWithValues("Message", "Data source \"name\" 
destroyed on \"server1\"")
+        .doesNotContainOutput("Warning:");
+
+    assertThat(cacheConfig.getJndiBindings().isEmpty()).isTrue();
+    verify(command).updateConfigForGroup(eq("cluster"), eq(cacheConfig), 
any());
+
+    ArgumentCaptor<DestroyJndiBindingFunction> function =
+        ArgumentCaptor.forClass(DestroyJndiBindingFunction.class);
+    ArgumentCaptor<Object[]> arguments = 
ArgumentCaptor.forClass(Object[].class);
+
+    ArgumentCaptor<Set<DistributedMember>> targetMembers = 
ArgumentCaptor.forClass(Set.class);
+    verify(command, times(1)).executeAndGetFunctionResult(function.capture(), 
arguments.capture(),
+        targetMembers.capture());
+
+    String jndiName = (String) arguments.getValue()[0];
+    boolean destroyingDataSource = (boolean) arguments.getValue()[1];
+
+    
assertThat(function.getValue()).isInstanceOf(DestroyJndiBindingFunction.class);
+    assertThat(jndiName).isEqualTo("name");
+    assertThat(destroyingDataSource).isEqualTo(true);
+    assertThat(targetMembers.getValue()).isEqualTo(members);
+  }
 }
diff --git 
a/geode-core/src/test/java/org/apache/geode/internal/util/DriverJarUtilTest.java
 
b/geode-core/src/test/java/org/apache/geode/internal/util/DriverJarUtilTest.java
index 8a93b96..de8102a 100644
--- 
a/geode-core/src/test/java/org/apache/geode/internal/util/DriverJarUtilTest.java
+++ 
b/geode-core/src/test/java/org/apache/geode/internal/util/DriverJarUtilTest.java
@@ -63,5 +63,4 @@ public class DriverJarUtilTest {
     util.deregisterDriver(driverName);
     verify(util).deregisterDriverWithDriverManager(any());
   }
-
 }

Reply via email to